How to Use iPhone 3.0 Features and Still Run on 2.2

iPhone SDK 3.0 has a lot of nifty new features.  One feature I want to use is to send email without exiting my application.  In the past, I have to use UIApplication openURL: to launch the Mail application.  But once I do that, the user is gone, gone, gone.

In SDK 3.0, there is a MFMailComposeViewController class that allows me to bring up a Mail Composer view.  When the user is done with the email and tap Send, user is back in my application.  Can it be cooler than that?

Yes, of course.  Using the MFMailComposeViewController class, I can also preload the body with an attachment.  So, if my application generates a graphical chart, a CSV file, a sound file, etc., I can attach it to the email that is being sent.

The MailComposer sample application (you may need to be logged into Apple’s Developer Connection to access this link) goes into the nitty gritty details on how to use this new class.  Definitely dig into the sample code.

My first question was does that mean that my application is now limited to iPhone OS 3.0 users?  I don’t want to do that as it excludes a large segment of the population who did not bother to upgrade (even though the upgrade is free on the iPhone).  Here’s the cool part.  You don’t have to exclude the pre-3.0 users.  The MailComposer sample application goes into the details of how to do that.

  1. You build the application with SDK 3.0.
  2. You target to iPhone OS 2.2.1 (or whatever version you want).
  3. You write your code to check for existence of certain 3.0 framework before using them, and provide a graceful degradation path for pre-3.0 users.
  4. In setting up the Frameworks for your build target, you set the role of the 3.0 framework used in your application to weak such that application will launch even if some of the frameworks are missing.

Step 4 above is the important part.  If you don’t do that, your application will fail to launch on pre-3.0 devices.  The following is the screen capture for where to set a framework’s role to weak.

Xcode example of where to set a Framework to Weak

Xcode example of where to set a Framework to Weak

As for testing, if you have the luxury of a rackful of devices running different OSes, by all means test on all of them.  The other option is to test on pre-3.0 OSes using the iPhone Simulator.  The way to do that is first build and test by setting Xcode to Simulator 3.0 setting.  This leaves a 3.0 version on your iPhone Simulator. Then from the iPhone Simulator men, choose Hardware > Version and select 2.2.1.  Then launch your 3.0 application in a 2.2.1 environment and test away.

Advertisements

14 Responses to “How to Use iPhone 3.0 Features and Still Run on 2.2”

  1. Edgard Rodriguez Says:

    When you said:
    3- You write your code to check for existence of certain 3.0 framework before using them, and provide a graceful degradation path for pre-3.0 users.
    what do you mean? add the MessageUI framework to the folder for older versions, like 2.2.1 ? can you explain this one for me

    thanks

  2. peter_k_lee Says:

    The code in MailComposer sample app from Apple illustrates that. The call NSClassFromString() returns the “class object” for the class MFMailComposeViewController (a 3.0 feature) given the string name *if* the runtime environment supports that. Otherwise, it returns nil.

    Class mailClass = (NSClassFromString(@”MFMailComposeViewController”));
    if (mailClass != nil)
    {
    // you have the MFMailComposeViewController class
    }
    else
    {
    // you do not have the MFMailComposeViewController class
    }

  3. Edgard Rodriguez Says:

    not quite yet.

    this is my code for MailComposer

    // the custom icon button was clicked, handle it here
    MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
    controller.mailComposeDelegate = self;
    [controller setSubject:@”In app email…”];
    [controller setMessageBody:@”…a tutorial from mobileorchard.com” isHTML:NO];
    [self presentModalViewController:controller animated:YES];

    /*
    // Attach an image to the email
    NSString *path = [[NSBundle mainBundle] pathForResource:@”Images” ofType:@”plist”];
    NSData *myData = [NSData dataWithContentsOfFile:path];
    [controller addAttachmentData:myData mimeType:@”image/png” fileName:@”rainy”];
    */
    [controller release];
    }

    – (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
    [self becomeFirstResponder];
    [self dismissModalViewControllerAnimated:YES];
    }

    error said.

    MailComposer undeclared.(3.0 works, not in 2.2.1)

    MessageUI no such file or path.( but in 3.0 work great but 2.2.1)

  4. peter_k_lee Says:

    I assume that you have used the code sample to check for the existence of the MFMailComposeViewController using NSClassFromString before you execute the above piece of code. If not, you should. This is because NSClassFromString will work on both 2.2.1 and 3.0. On 2.2.1, it returns nil and you should not call [MFMailComposeViewController alloc] init]. On 3.0, it returns the class object, then you are free to call the alloc-init pattern.

    The other thing you should check for is whether you have set MessageUI.framework to “weak” linking.

  5. Edgard Rodriguez Says:

    Yes I did setup to weak, I need to check where to use the NSClassFromString and that could be the problem.

    let me check and let you know

    thanks very much

  6. Edgard Rodriguez Says:

    OK this is what I got. the following code give works great in 3.0, click send button and open the Composer, now when I run in the 2.2.1 simulator the app run but clicking the send button don’t do anything but no crash or errors. seen like the button don’t have the action.

    – (void)email
    {

    //Can send email
    //if ([MFMailComposeViewController canSendMail])
    Class mailClass = (NSClassFromString(@”MFMailComposeViewController”));
    if (mailClass != nil && [mailClass canSendMail])

    {

    // the custom icon button was clicked, handle it here
    MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
    controller.mailComposeDelegate = self;
    [controller setSubject:@”In app email…”];
    [controller setMessageBody:@”…a tutorial from mobileorchard.com” isHTML:NO];
    [self presentModalViewController:controller animated:YES];
    [controller release];

    }

    }

    – (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
    [self becomeFirstResponder];
    [self dismissModalViewControllerAnimated:YES];
    }

    any idea???

  7. peter_k_lee Says:

    Refer back to the MailComposer sample app from Apple. See link in my original post. You need to have a else-clause for your if (mailClass != nil) test. The else-clause should use [[UIApplication sharedApplication] openURL: …] to launch the Mail application with a specific mailto: URL.

  8. Edgard Rodriguez Says:

    ok I did and I think I stock, the button doesn’t work.works fine in 3.0 but 2.2.1

    – (void)email
    {
    //Can send email
    //if ([MFMailComposeViewController canSendMail])
    Class mailClass = (NSClassFromString(@”MFMailComposeViewController”));
    if (mailClass != nil && [mailClass canSendMail])

    {
    // the custom icon button was clicked, handle it here
    MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
    controller.mailComposeDelegate = self;
    [controller setSubject:@”In app email…”];
    [controller setMessageBody:@”…a tutorial from mobileorchard.com” isHTML:NO];
    [self presentModalViewController:controller animated:YES];
    [controller release];
    }

    else
    {
    [self displayComposerSheet];

    }

    }

    // Launches the Mail application on the device.
    -(void)launchMailAppOnDevice
    {
    NSString *recipients = @”mailto:first@example.com?cc=second@example.com,third@example.com&subject=Hello from California!”;
    NSString *body = @”&body=It is raining in sunny California!”;

    NSString *email = [NSString stringWithFormat:@”%@%@”, recipients, body];
    email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
    }

    what I’m missing.???

    thanks

  9. Edgard Rodriguez Says:

    Peter, do you have any idea on this one?/ by now mailcomposer works great in 3.0 and 2.2.1 dont show the composer but the app run without crash

    thanks for any updates

  10. My Name Says:

    The problem is the simulator. The openURL action doesn’t work at all int he simulator. You have to test that on an actual phone.

  11. Omer Says:

    Hi Peter,

    I am trying to implement a mail feedback button in my game, and I can’t seem to get Apple’s example.
    I’m trying to get it to compile for iPhone OS2.0 (the actual code I downloaded from Apple). I didn’t change any of the settings, and when I looked at what Apple did, it looks fine:
    – The iPhone Base SDK is set for Device 3.0
    – thee Project’s Info under Build->Deployment->iPhone OS Deployment Target is set to iPhone OS 2.0,
    – The link binary with the 3.0 library is set to weak
    Everything looks like it should work.
    When I change the active SDK for the build to iPhone Device 2.0, like I’m successfully compiling my game all the time so far, I get 9 compile errors and 1 warning.
    Does this mean that if I want to add this code to my game I will have to change the its setting like Apple did, compile it using 3.0 for active SDK, but it will still work on devices with OS2.0?

    Thank you for your help,

    Omer

  12. Omer Says:

    Thank you for your help.

    The error list is long and ugly:

    Building target “MailComposer” of project “MailComposer” with configuration “Debug” — (9 errors, 1 warning)
    cd /Users/omerv/Desktop/MailComposer
    setenv PATH “/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin”
    /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 -x objective-c -arch armv6 -fmessage-length=0 -pipe -std=c99 -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Wreturn-type -Wunused-variable -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk -fvisibility=hidden -gdwarf-2 -mthumb -miphoneos-version-min=2.0 -iquote /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-generated-files.hmap -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-own-target-headers.hmap -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-all-target-headers.hmap -iquote /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-project-headers.hmap -F/Users/omerv/Desktop/MailComposer/build/Debug-iphoneos -I/Users/omerv/Desktop/MailComposer/build/Debug-iphoneos/include -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/DerivedSources/armv6 -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/DerivedSources -include /var/folders/D0/D0jkPH-XFj8CQ5nP2JrnzE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/MailComposer_Prefix-bnkdpsapkmvjmrayvegqwcdoejyq/MailComposer_Prefix.pch -c /Users/omerv/Desktop/MailComposer/Classes/MailComposerAppDelegate.m -o /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/Objects-normal/armv6/MailComposerAppDelegate.o
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerAppDelegate.m:52:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:52:32: error: MessageUI/MessageUI.h: No such file or directory
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:53:50: error: MessageUI/MFMailComposeViewController.h: No such file or directory
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerAppDelegate.m:52:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:55: error: cannot find protocol declaration for ‘MFMailComposeViewControllerDelegate’
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerAppDelegate.m:52:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:52:32: error: MessageUI/MessageUI.h: No such file or directory
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:53:50: error: MessageUI/MFMailComposeViewController.h: No such file or directory
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerAppDelegate.m:52:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:55: error: cannot find protocol declaration for ‘MFMailComposeViewControllerDelegate’
    cd /Users/omerv/Desktop/MailComposer
    setenv PATH “/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin”
    /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 -x objective-c -arch armv6 -fmessage-length=0 -pipe -std=c99 -Wno-trigraphs -fpascal-strings -fasm-blocks -O0 -Wreturn-type -Wunused-variable -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk -fvisibility=hidden -gdwarf-2 -mthumb -miphoneos-version-min=2.0 -iquote /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-generated-files.hmap -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-own-target-headers.hmap -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-all-target-headers.hmap -iquote /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/MailComposer-project-headers.hmap -F/Users/omerv/Desktop/MailComposer/build/Debug-iphoneos -I/Users/omerv/Desktop/MailComposer/build/Debug-iphoneos/include -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/DerivedSources/armv6 -I/Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/DerivedSources -include /var/folders/D0/D0jkPH-XFj8CQ5nP2JrnzE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/MailComposer_Prefix-bnkdpsapkmvjmrayvegqwcdoejyq/MailComposer_Prefix.pch -c /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m -o /Users/omerv/Desktop/MailComposer/build/MailComposer.build/Debug-iphoneos/MailComposer.build/Objects-normal/armv6/MailComposerViewController.o
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:53:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:52:32: error: MessageUI/MessageUI.h: No such file or directory
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:53:50: error: MessageUI/MFMailComposeViewController.h: No such file or directory
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:53:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:55: error: cannot find protocol declaration for ‘MFMailComposeViewControllerDelegate’
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m: In function ‘-[MailComposerViewController showPicker:]’:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: no ‘+canSendMail’ method found
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: (Messages without a matching method signature
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: will be assumed to return ‘id’ and accept
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: ‘…’ as arguments.)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m: In function ‘-[MailComposerViewController displayComposerSheet]’:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: ‘MFMailComposeViewController’ undeclared (first use in this function)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: (Each undeclared identifier is reported only once
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: for each function it appears in.)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: ‘picker’ undeclared (first use in this function)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m: At top level:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:123: error: syntax error before ‘MFMailComposeViewController’
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:53:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:52:32: error: MessageUI/MessageUI.h: No such file or directory
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:53:50: error: MessageUI/MFMailComposeViewController.h: No such file or directory
    In file included from /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:53:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.h:55: error: cannot find protocol declaration for ‘MFMailComposeViewControllerDelegate’
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: no ‘+canSendMail’ method found
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:71: warning: (Messages without a matching method signature
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: ‘MFMailComposeViewController’ undeclared (first use in this function)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:93: error: ‘picker’ undeclared (first use in this function)
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m: At top level:
    /Users/omerv/Desktop/MailComposer/Classes/MailComposerViewController.m:123: error: syntax error before ‘MFMailComposeViewController’
    Build failed (9 errors, 1 warning)

  13. Omer Says:

    I believe you can get the errors if you download the code from Apple and compile it after changing the Active SDK of the build to something lower than 3.0

    Although I’m almost sure this is the case, I still want to make sure:
    Does this all mean that if I want to add this kind of code to my game I will have to change the my project’s setting just like Apple did, compile it using 3.0 for active SDK, but it will still work on devices with OS2.0?

    Again – thank you for your help,

    Omer

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: