33

我正在使用UIActivityViewControlleriOS6 中的新类为用户提供各种共享选项。您可以将一组参数传递给它,例如文本、链接和图像,其余的由它完成。

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

我不想必须单独使用MFMessageComposeViewControllerUIActivityViewController,因为这违背了共享控制器的目的。

有什么建议么?

UIActivityViewController 类参考

编辑:这现已提交给 Apple,随后与重复的错误报告合并。

关于 OpenRadar 的错误报告

4

6 回答 6

24

要在 iOS6 上使用 UIActivityViewController 为电子邮件添加主题,这是任何人都可以使用的最佳解决方案。您所要做的就是在初始化 UIActivityViewController 时调用以下命令。

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

你的 UIActivityViewController 填充了一个主题。

于 2013-06-28T16:02:33.547 回答
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 实体或标签)。

使用该方法,我让您详细说明设置邮件收件人的优雅方法。

于 2013-01-29T18:50:46.907 回答
8

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

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

我们的解决方案有点像 hack,但它运行良好,至少目前是这样。它确实涉及使用 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 而不是系统控制器。

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

    - (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为撰写视图的委托。

这样做的原因是,当显示一个撰写模式时,它会阻止显示其他模式,即您显示自己的撰写视图会阻止显示系统撰写视图。绝对是一个 hack,但它可以完成工作。

希望这可以帮助。

于 2013-01-17T16:41:56.673 回答
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
于 2014-03-21T11:11:02.990 回答
1

您应该能够使用带有 mailto: 方案(或 sms: 用于文本消息)的 NSUrl 对象包括收件人。

从 UIActivity 类参考:

UIActivityTypeMail 该对象将提供的内容发布到新的电子邮件中。使用此服务时,您可以提供 NSString 和 UIImage 对象以及指向本地文件的 NSURL 对象作为活动项的数据。您还可以指定其内容使用 mailto 方案的 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];
于 2012-09-27T15:48:01.097 回答
1

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

于 2013-10-09T18:34:23.930 回答