While it does appear that at present the mailto: solution for setting email subject and body isn't working, this would in any case not be adequate if you wanted to set the email body to contain HTML and still make use of Apple's system email icon via UIActivityViewController.
That was exactly what we wanted to do: use the system icon, but have the email contain an HTML body and a custom subject.
Our solution was something of a hack, but it works well, at least for the moment. It does involve using MFMailComposeViewController, but it still lets you use the system mail icon with UIActivityViewController.
Step 1: Create a wrapper class conforming to the UIActivityItemSource like so:
@interface ActivityItemSource : NSObject <UIActivityItemSource>
@property (nonatomic, strong) id object;
- (id) initWithObject:(id) objectToUse;
@end
@implementation ActivityItemSource
- (id) initWithObject:(id) objectToUse
{
self = [super init];
if (self) {
self.object = objectToUse;
}
return self;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
return self.object;
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
return self.object;
}
Step 2: Subclass UIActivityViewController and make it into a MFMailComposeViewControllerDelegate like so:
@interface ActivityViewController : UIActivityViewController <MFMailComposeViewControllerDelegate>
@property (nonatomic, strong) id object;
- (id) initWithObject:(id) objectToUse;
@end
@implementation ActivityViewController
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultSent:
case MFMailComposeResultSaved:
//successfully composed an email
break;
case MFMailComposeResultCancelled:
break;
case MFMailComposeResultFailed:
break;
}
//dismiss the compose view and then the action view
[self dismissViewControllerAnimated:YES completion:^() {
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}];
}
- (id) initWithObject:(id) objectToUse
{
self = [super initWithActivityItems:[NSArray arrayWithObjects:[[ActivityItemSource alloc] initWithObject:objectToUse], nil] applicationActivities:nil];
if (self) {
self.excludedActivityTypes = [NSArray arrayWithObjects: UIActivityTypePostToWeibo, UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll, nil];
self.object = objectToUse;
}
return self;
}
NOTE: when you are calling super initWithActivityItems
you are wrapping the object you will be sharing in your custom ActivityItemSource
Step 3: Launch your own MFMailComposeViewController instead of the system one when a user taps on the Mail icon.
You would do this in the activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
method in the ActivityItemSource class:
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
if([activityType isEqualToString:UIActivityTypeMail]) {
//TODO: fix; this is a hack; but we have to wait till apple fixes the inability to set subject and html body of email when using UIActivityViewController
[self setEmailContent:activityViewController];
return nil;
}
return self.object;
}
- (void) setEmailContent:(UIActivityViewController *)activityViewController
{
MFMailComposeViewController *mailController = [ShareViewController mailComposeControllerWithObject: self.object withDelegate: activityViewController];
[activityViewController presentViewController:mailController animated:YES completion:nil];
}
In the mailComposeControllerWithObject
method you instantiate an instance of the MFMailComposeViewController class and set it up to contain whatever data you want. Note also that you would set the activityViewController
as the compose view's delegate.
The reason this works is that when a compose modal is displayed, it prevents other modals from being displayed, i.e. you displaying your own compose view blocks the system compose view from being shown. Definitely a hack, but it gets the job done.
Hope this helps.