Wednesday, October 6, 2010

Taking Advantage of the RootViewController

that is now available in cocos2d 0.99.5

I mentioned in a forum post about how cool it is not that we have an actual view controller available to us to hang stuff off of. A few people have asked about what I was referring to, so here's a sample project.

This is just the cocos2d base template with the MessageUI framework added (required for in-app email) and a few bits of code.

First we'll add a menu to "Hello World", add this in the layer init;

CCMenuItem *emailItem = [CCMenuItemFont itemFromString: @"Email" target:self selector:@selector(emailCallback)];
CCMenu *menu = [CCMenu menuWithItems: emailItem, nil];
menu.position = ccp(50,50);
[self addChild:menu];


Now add the emailCallback method;

-(void) emailCallback
{
    [(BaseEmailAppDelegate*)[[UIApplication sharedApplication] delegate] sendEmail];
}

In our app delegate we need to create our sendEmail method;
In the .h file

-(void)sendEmail;

In the .m file

-(void)sendEmail
{
    [viewController displayComposer];  
}

In our RootViewController we need to create our displayComposer method;
In the .h file
Import the MessageUI header

#import <MessageUI/MessageUI.h>
and add MFMailComposeViewControllerDelegate
@interface RootViewController : UIViewController <MFMailComposeViewControllerDelegate> 
{
}

-(void)displayComposer;
@end

In the .m file

@implementation RootViewController


#pragma mark -
#pragma mark Setup Mail Alert
- (void)setUpMailAccount {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"System Error"
message:@"Please setup a mail account first."
delegate:self 
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil];
[alert show];
[alert release];
}

#pragma mark -
#pragma mark Compose Mail
// Displays an email composition interface inside the application. Populates all the Mail fields. 
-(void)displayComposerSheet {
if(![MFMailComposeViewController canSendMail]) {
[self setUpMailAccount];
return;
}
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;

[self presentModalViewController:picker animated:YES];
    [picker release];
}

-(void)displayComposer {
NSLog(@"pop-up email here");
[self displayComposerSheet];
}

// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the message field with the result of the operation.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
break;
case MFMailComposeResultSaved:
break;
case MFMailComposeResultSent:
break;
case MFMailComposeResultFailed:
break;
default:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Email" message:@"Sending Failed - Unknown Error :-("
delegate:self cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
break;
}
[self dismissModalViewControllerAnimated:YES];
}

Here is the LINK to the sample project.

12 comments:

  1. Thanks Greg, this is very helpful. I've been wanting to add email capabilities to my Cocos2d App, and this makes it easy

    ReplyDelete
  2. Thanks for sharing. I tried the sample project. Everything works perfect. But in my case, when I rotate the device when writing a message and returning to my scene, the screen is black. The gdb telling:
    Failed to make complete framebuffer object 8cdd
    OpenGL error 0x0506 in -[EAGLView swapBuffers]...

    I am currently using 0.99.5 rc0. I just changed to rc1. But still not working. Would be great if you could give me a hit.

    Regards,
    Marc

    ReplyDelete
  3. sry hint :), don't start hitting me :)

    ReplyDelete
  4. @Marc - sorry, I completely missed your comment. Hopefully you have resolved your problem by now, if not then head over to the cocos2d forums as I have seen a few similar threads.

    ReplyDelete
  5. Greg, thank you for this page!

    I have been trying to use this feature in my cocos2d project. However, I get the following link error:

    Undefined symbols:
    "_OBJC_CLASS_$_MFMailComposeViewController", referenced from:
    objc-class-ref-to-MFMailComposeViewController in RootViewController.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status

    Is there any (basic I am sure) manipulation I need to do so that the linker finds the missing reference?

    Thanks
    Max

    ReplyDelete
  6. Hi Max - sounds like you are missing the MessageUI framework, if you are still using Xcode 3, double click your Target and select the first tab and then click the "+" to add a framework.

    ReplyDelete
  7. thanks Gregory it works fine now. I read somewhere that we should check if the email functionality is available in the device (maybe it is an ipod or it is in the airplane mode?). How can I do that? is there a emailCapability flag somewhere in ios?
    max

    ReplyDelete
  8. Hi Max - Yes, thanks... I just updated the project / zip file and added the check (sorry left it out). Here's the important check line:

    if(![MFMailComposeViewController canSendMail]) {
    [self setUpMailAccount];
    return;
    }

    "canSendMail" will return FALSE when the device has no email accounts setup. If you have a test device, remove all email accounts and run the test app. It will popup an alert telling you to setup an email account first.

    Greg

    ReplyDelete
  9. Greg my (first) app now has a "send feedback" button, thanks to you!
    max

    ReplyDelete