我正在使用iOS6中的新UIActivityViewController
类为用户提供各种共享选项。您可以将一系列参数传递给它,例如文本,链接和图像,剩下的就完成了。
如何定义收件人?例如,通过邮件或短信共享应该能够接受收件人,但我无法弄清楚如何调用此行为。
我不希望必须单独使用MFMessageComposeViewController
和UIActivityViewController
,因为这会破坏共享控制器的目的。
有什么建议吗?
UIActivityViewController Class Reference
编辑:现在已经提交了Apple,并随后与重复的错误报告合并。
答案 0 :(得分:24)
要在iOS6上使用UIActivityViewController将主题添加到电子邮件中,这是任何人都可以使用的最佳解决方案。您所要做的就是在初始化UIActivityViewController时调用以下内容。
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities];
[activityViewController setValue:@"My Subject Text" forKey:@"subject"];
您的UIActivityViewController上填充了主题。
答案 1 :(得分:10)
我只想出一个解决这个问题的方法(在我的例子中设置了电子邮件的主题): 在内部,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实体或标签)。
使用该方法,我让您详细说明设置邮件收件人的优雅方法。
答案 2 :(得分:8)
虽然目前看来mailto:设置电子邮件主题和正文的解决方案似乎不起作用,但如果您想将电子邮件正文设置为包含HTML并仍然可以使用,那么这在任何情况下都是不够的通过UIActivityViewController获取Apple的系统电子邮件图标。
这正是我们想要做的:使用系统图标,但电子邮件包含HTML正文和自定义主题。
我们的解决方案是一种破解,但它运作良好,至少在目前。它确实涉及使用MFMailComposeViewController,但它仍然允许您使用带有UIActivityViewController的系统邮件图标。
步骤1:创建一个符合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而不是系统。
您可以在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
设置为撰写视图的委托。
这样做的原因是当显示合成模式时,它会阻止显示其他模态,即您显示自己的合成视图会阻止系统合成视图显示。绝对是一个黑客,但它完成了工作。
希望这有帮助。
答案 3 :(得分:3)
所有这些都归功于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
答案 4 :(得分:1)
您应该能够使用带有mailto:scheme的NSUrl对象(或短信:用于短信)包含收件人。
来自UIActivity类引用:
<强> UIActivityTypeMail 强> 该对象将提供的内容发布到新内容 电子邮件。使用此服务时,您可以提供NSString和 UIImage对象和NSURL对象指向本地文件作为数据 活动项目。您还可以指定其内容的NSURL对象 使用mailto方案。
因此,这样的事情应该有效:
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];
答案 5 :(得分:1)
我不确定收件人,但似乎在iOS 7及更高版本中,您可以通过符合UIActivityItemSource
协议并实施方法activityViewController:subjectForActivityType:
来设置电子邮件的主题。< / p>