如何在iOS 6中设置UIActivityViewController的收件人?

我在iOS6中使用新的UIActivityViewController类来为用户提供各种共享选项。 你可以传递一些参数给它,比如文本,链接和图像,剩下的就完成了。

我如何定义收件人? 例如通过邮件或短信共享应该能够接受收件人,但我不知道如何调用此行为。

我不希望必须分别使用MFMessageComposeViewControllerUIActivityViewController因为这只是破坏了共享控制器的目的。

有什么build议么?

UIActivityViewController类参考

编辑:这已经提交了苹果,随后与重复的错误报告合并。

Bug报告在OpenRadar

所有功劳都归功于Emanuelle,因为他提出了大部分的代码。

虽然我以为我会张贴他的代码的修改版本,帮助设置收件人。

我在MFMailComposeViewController上使用了一个类别

 #import "MFMailComposeViewController+Recipient.h" #import <objc/message.h> @implementation MFMailComposeViewController (Recipient) + (void)load { MethodSwizzle(self, @selector(setMessageBody:isHTML:), @selector(setMessageBodySwizzled:isHTML:)); } static void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) { Method origMethod = class_getInstanceMethod(c, origSEL); Method overrideMethod = class_getInstanceMethod(c, overrideSEL); if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); } else { method_exchangeImplementations(origMethod, overrideMethod); } } - (void)setMessageBodySwizzled:(NSString*)body isHTML:(BOOL)isHTML { if (isHTML == YES) { NSRange range = [body rangeOfString:@"<torecipients>.*</torecipients>" options:NSRegularExpressionSearch|NSCaseInsensitiveSearch]; if (range.location != NSNotFound) { NSScanner *scanner = [NSScanner scannerWithString:body]; [scanner setScanLocation:range.location+14]; NSString *recipientsString = [NSString string]; if ([scanner scanUpToString:@"</torecipients>" intoString:&recipientsString] == YES) { NSArray * recipients = [recipientsString componentsSeparatedByString:@";"]; [self setToRecipients:recipients]; } body = [body stringByReplacingCharactersInRange:range withString:@""]; } } [self setMessageBodySwizzled:body isHTML:isHTML]; } @end 

要在iOS6上使用UIActivityViewController将邮件添加到电子邮件中,这是任何人都可以使用的最佳解决scheme。您只需在初始化UIActivityViewController时调用以下内容。

 UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities]; [activityViewController setValue:@"My Subject Text" forKey:@"subject"]; 

而你的UIActivityViewController是填充一个主题。

我只是想出了一个解决这个问题的方法(在我的情况下设置电子邮件的主题):作为内部的UIActivityViewController将在某些时候调用MFMailComposeViewController类的setMessageBody:isHTML:方法,只是拦截该调用,并在里面做一个调用setSubject:方法。 感谢“方法调配”技术,它看起来像:

 #import <objc/message.h> static void MethodSwizzle(Class c, SEL origSEL, SEL overrideSEL) { Method origMethod = class_getInstanceMethod(c, origSEL); Method overrideMethod = class_getInstanceMethod(c, overrideSEL); if (class_addMethod(c, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { class_replaceMethod(c, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); } else { method_exchangeImplementations(origMethod, overrideMethod); } } @implementation MFMailComposeViewController (force_subject) - (void)setMessageBodySwizzled:(NSString*)body isHTML:(BOOL)isHTML { if (isHTML == YES) { NSRange range = [body rangeOfString:@"<title>.*</title>" options:NSRegularExpressionSearch|NSCaseInsensitiveSearch]; if (range.location != NSNotFound) { NSScanner *scanner = [NSScanner scannerWithString:body]; [scanner setScanLocation:range.location+7]; NSString *subject = [NSString string]; if ([scanner scanUpToString:@"</title>" intoString:&subject] == YES) { [self setSubject:subject]; } } } [self setMessageBodySwizzled:body isHTML:isHTML]; } @end 

在使用UIActivityViewController之前调用以下代码行:

 MethodSwizzle([MFMailComposeViewController class], @selector(setMessageBody:isHTML:), @selector(setMessageBodySwizzled:isHTML:)); 

然后传递给UIActivityViewController一个自定义UIActivityItemProvider,为UIActivityTypeMail返回一个HTML NSString,如:

 <html><head> <title>Subject of the mail</title> </head><body> Body of the <b>mail</b> </body></html> 

电子邮件的主题是从HTML标题中提取的(使用该部分的纯文本,没有html实体或标签)。

使用这种方法,我让你详细说明一个优雅的方式来设置邮件的收件人。

虽然目前看来,设置电子邮件主题和正文的mailto:解决scheme不起作用,但如果您要将电子邮件正文设置为包含HTML并仍然使用Apple的系统电子邮件图标通过UIActivityViewController。

这正是我们想要做的:使用系统图标,但让电子邮件包含HTML正文和自定义主题。

我们的解决scheme是一种黑客行为,但至less目前来说,它运行良好。 它涉及到使用MFMailComposeViewController,但它仍然可以让你使用UIActivityViewController的系统邮件图标。

第1步:创build一个符合UIActivityItemSource的包装类,如下所示:

  @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; } 

第2步:子类UIActivityViewController,并把它变成一个像这样的MFMailComposeViewControllerDelegate:

  @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; } 

注意:当您调用super initWithActivityItems您正在包装将在您的自定义ActivityItemSource中共享的对象

第3步:当用户点击邮件图标时,启动您自己的MFMailComposeViewController而不是系统。

您可以在activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType执行以下操作activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType ActivityItemSource类中的activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType方法:

  - (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]; } 

mailComposeControllerWithObject方法中,您实例化了MFMailComposeViewController类的一个实例,并将其设置为包含所需的任何数据。 还要注意,你可以将activityViewController设置为组合视图的委托。

这样做的原因是,当一个组合模式显示时,它会阻止显示其他模式,即显示自己的组合视图会阻止显示系统组合视图。 绝对是一个黑客,但它完成了工作。

希望这可以帮助。

您应该能够使用mailto:scheme(或SMS:for text messages)使用NSUrl对象包含收件人。

从UIActivity类参考:

UIActivityTypeMail对象将提供的内容发布到新的电子邮件。 使用此服务时,可以提供指向本地文件的NSString和UIImage对象和NSURL对象作为活动项目的数据。 你也可以指定其内容使用mailtoscheme的NSURL对象。

因此,这样的事情应该工作:

 NSString *text = @"My mail text"; NSURL *recipients = [NSURL URLWithString:@"mailto:foo@bar.com"]; NSArray *activityItems = @[text, recipients]; UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil]; [self presentViewController:activityController animated:YES completion:nil]; 

我不确定收件人,但似乎在iOS 7和更高版本中,您可以通过符合UIActivityItemSource协议并实现方法activityViewController:subjectForActivityType:来设置电子邮件的主题。