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.
- You build the application with SDK 3.0.
- You target to iPhone OS 2.2.1 (or whatever version you want).
- 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.
- 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.
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.
August 12, 2009 at 10:57 pm |
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
August 12, 2009 at 11:24 pm |
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
}
August 13, 2009 at 12:54 am |
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)
August 13, 2009 at 5:51 am |
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.
August 13, 2009 at 8:41 pm |
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
August 14, 2009 at 1:44 am |
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???
August 14, 2009 at 6:47 am |
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.
August 14, 2009 at 11:50 pm |
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
August 21, 2009 at 11:41 pm |
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
September 21, 2009 at 12:02 pm |
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.
January 5, 2010 at 8:31 am |
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
January 5, 2010 at 9:22 am |
What are the compilation error and warning messages?
January 5, 2010 at 9:33 am |
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)
January 5, 2010 at 12:09 pm |
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