Monday, October 11, 2010

Thoughts on Older Devices

So, lets put some "truthiness" (full credit to Stephen Colbert) down on paper about decisions, or better yet a "strategy" an indie developer has to make. The strategy I'm referring to is of course around supporting older devices. Well what does that mean? Thanks for asking Virginia, let me share my (recent) thoughts.

Most if not all indie developers need to make money. If you are an indie and this does not apply to you then stop reading now. Okay we got that out of the way, so we can openly admit to any and all that:
  1. We need to make money
Now we need to find out, given our target audience, how much users with a 2 or 3 year old iPod Touch or iPhone actually spend on apps in the App Store. Because that's how much the impact will be if we choose to NOT support older devices. But hang-on, if we can admit all this and move forward, guess what... we can actually develop BETTER apps! Yup, there you go, more "truthiness" for you! :-]

Yes, if we don't have to worry about how our app runs on a 2nd Generation iPod Touch running iOS 4.x or even iOS 3.x then our development environment just got a whole lot smaller and more defined. If we draw the line at multitasking devices only then we double the amount of memory (and openGL texture size) for our apps. This is huge. In addition we can also target openGL ES2 instead of 1.1 and we can streamline our code (e.g. just use blocks instead to having to runtime check for support). Yeah, I see your eyes widening... its okay. You should at least consider it and NOT once you're half-way into your project, I mean right from the start.

So this is what my new strategy might look like:
We will fully support iOS 4.x users with devices that support multitasking, including 3rd generation iPod Touch and newer along with iPhone 3GS and newer devices.
Wow, that felt great... now the decent thing to do is to post this new strategy on your web site.

Thursday, October 7, 2010

Game Center Design

I've read numerous forum and blog posts recently and initial reactions to Game Center from Users is:
The login (UIAlertView) sucks and looks like the app is trying to steal my iTunes Account.
This is a good place for a pre-sign-on modal view or alert, asking if they want to use Game Center and explaining that the next dialog box is required to log into / authenticate with Game Center and is provided by Apple. If the user doesn't want Game Center then disable it and prompt them no more. Also let them know where to turn it (Game Center) back on should they want to use it in the future.

Just my $0.02 :-]

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


In the .m file

    [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> 


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."
[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];
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:
case MFMailComposeResultSaved:
case MFMailComposeResultSent:
case MFMailComposeResultFailed:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Email" message:@"Sending Failed - Unknown Error :-("
delegate:self cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
[self dismissModalViewControllerAnimated:YES];

Here is the LINK to the sample project.

Tuesday, October 5, 2010

iAd's in Universal App

In iOS 4.2, there is a change in the references to the ADBannerView size. We used to use:

But now we need to use:

This allows iOS 4.2 to resize the iAd based on the device / window size.

So how do you create a universal app that uses iAd's AND will run on iOS 4.0? Here's what I did (based on some help from Rincewind on the Dev forums; I didn't know how to check for an NSString. Now I do! You use &<string> and if that doesn't equal nil, you are good to go).

Overview: I chose to create two new string values and then based on whether or not the app was running on iOS 4.2, set them to the appropriate identifier.

In .h file (view controller)
     NSString *PortraitBanner;
     NSString *LandscapeBanner;
@property(nonatomic, retain) NSString *PortraitBanner;
@property(nonatomic, retain) NSString *LandscapeBanner;

In .m file
@synthesize PortraitBanner;
@synthesize LandscapeBanner;

in my createBannerView method:
//If true then we're on iOS 4.2 (or newer) and we can use the identifiers
//If not true then we use the old identifiers
if (&ADBannerContentSizeIdentifierPortrait != nil) {
     PortraitBanner = ADBannerContentSizeIdentifierPortrait;
     LandscapeBanner = ADBannerContentSizeIdentifierLandscape;
     NSLog(@"Running on iOS 4.2 or newer.");
} else {
     PortraitBanner = ADBannerContentSizeIdentifier320x50;
     LandscapeBanner = ADBannerContentSizeIdentifier480x32;
     NSLog(@"Running on Pre-iOS 4.2.");

//Don't forget to release
in dealloc:
[PortraitBanner release];
[LandscapeBanner release];

Note: If you haven't checked out the Apple sample code iAd Suite, that's where my createBannerView method came from.

Then pretty much wherever you'd use one of the "ADBannerContentSizeIdentifier*" strings, use either PortraitBanner or LandscapeBanner. I've tested my app on iOS 4.1 and iOS 4.2 on several devices and my iPad and it is working fine.

Friday, October 1, 2010

It's Official!

Supporting multiple iOS versions is a real pain!

The last update for Hyper WARP (iPhone v2.7) has a problem only on iOS 3.x - ARG!! I tested the update several times but failed to test the final build (<- yup I know, what a dummy!). Even after I posted THIS PAGE on our site... double ARG!

Makes me reconsider supporting pre-iOS 4 at all... When we started both iOS 2.x and iOS 3.x were available but almost all of our apps only supported iOS 3.x. Man that kept things very nice for testing, no need for a 2.x test device. Now with a bunch of devices still running iOS 3.x, I've really got to give this some thought.