2012-09-27 111 views
31

我在iOS6中使用新的UIActivityViewController類來爲用戶提供各種共享選項。你可以傳遞一些參數給它,比如文本,鏈接和圖像,剩下的就完成了。如何在iOS 6中設置UIActivityViewController的收件人?

如何定義收件人?例如通過郵件或短信共享應該能夠接受收件人,但我無法弄清楚如何調用這種行爲。

我不希望必須分別使用MFMessageComposeViewControllerUIActivityViewController,因爲這只是失敗了股東控制器的目的。

有什麼建議嗎?

UIActivityViewController Class Reference

編輯:這現在已經提交蘋果公司,隨後與重複的bug報告合併。

Bug report on OpenRadar

回答

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

非常恐怖的解決方法 – Andy

+0

你能分享完整的例子嗎? – Rajeev

+0

這對任何人都有效嗎?如果是的話,你可以分享完整的代碼嗎? – mKane

1

你應該能夠包括使用NSURL對象和郵寄地址收件人:方案(或短信:文本消息)。

從UIActivity類參考:

UIActivityTypeMail 目的帖所提供的內容到一個新的 電子郵件消息。使用此服務時,您可以提供NSString和指向本地文件的UIImage對象和NSURL對象作爲 活動項目的數據。您也可以指定其內容爲 使用mailto方案的NSURL對象。

因此,這樣的事情應該工作:

NSString *text = @"My mail text"; 
NSURL *recipients = [NSURL URLWithString:@"mailto:[email protected]"]; 

NSArray *activityItems = @[text, recipients]; 

UIActivityViewController *activityController = 
        [[UIActivityViewController alloc] 
        initWithActivityItems:activityItems 
        applicationActivities:nil]; 

[self presentViewController:activityController 
        animated:YES completion:nil]; 
+5

感謝您的建議。我試了一下,mailto網址的內容只是被添加到電子郵件的正文中。所以看起來這不是解決方案,儘管文檔。 – MattCheetham

+0

嗯,這很奇怪。你可以嘗試從activityItems數組中刪除文本,並只傳遞NSURL與mailto? – henning77

+0

您可以擴展mailto以包含身體,例如用mailto:[email protected]?cc = [email protected]&subject=This%20is%20the%20subject&body=This%20is%20the%20body – henning77

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您正在包裝您將在您的自定義活動項目中分享的對象活動項目

第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設置爲撰寫視圖的委託。

這樣做的原因是,當顯示撰寫模式時,它會阻止顯示其他模式,即顯示自己的撰寫視圖會阻止顯示系統撰寫視圖。絕對是黑客,但它完成了工作。

希望這會有所幫助。

+1

您能否告訴我「 MFMailComposeViewController * mailController = [ShareViewController mailComposeControllerWithObject:self.object withDelegate:activityViewController];'工程?當我嘗試'MFMailComposeViewController * mailController = [[MFMailComposeViewController alloc] init]; mailController.delegate = activityViewController;'我得到了'試圖在上顯示,它正在等待完成錯誤 – zeroos

+0

嗨zeroos,我們放棄了這種方法前一陣子,所以蘋果在此期間可能已經關閉了這個漏洞。您要構建的是哪個iOS版本?您可以嘗試使用較早的操作系統構建模擬器,例如5.1,看看它是否與操作系統相關。 – ilyashev

+0

如果必須,您還可以嘗試從不同的視圖控制器顯示mailComposeView。據推測,這應該仍然會阻止標準的mailComposeView出現。 – ilyashev

10

我只是想出了一個解決這個問題(在我的情況設置電子郵件的主題): 作爲內部的UIActivityViewController將調用在某些時候setMessageBody:isHTML:方法MFMailComposeViewController類的,只是截距調用和內部調用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實體或標籤)。

使用該方法,我讓你詳細說明一種優雅的方式來設置郵件的收件人。

24

對於加入受到到iOS6的使用UIActivityViewController的電子郵件,這是任何人都可以使用的最佳解決方案。所有你需要做的就是調用下面在初始化UIActivityViewController。

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

而你的UIActivityViewController被填充主題。

+0

工作就像一個魅力,非常簡單。謝謝! – Jon

+1

這似乎工作,但它記錄? –

+1

使用KVO的絕佳解決方案! – manderson

1

我不確定收件人,但好像在iOS 7和更高版本中,您可以通過符合UIActivityItemSource協議並實施方法activityViewController:subjectForActivityType:來設置電子郵件的主題。

+3

是的,這確實爲主題工作,沒有汗水。但是,仍然沒有非常好的方式來設置收件人。 – matt

相關問題