web-dev-qa-db-fra.com

Comment définir des destinataires pour UIActivityViewController dans iOS 6?

J'utilise la nouvelle classe UIActivityViewController dans iOS6 pour fournir à l'utilisateur diverses options de partage. Vous pouvez lui passer un tableau de paramètres tels que du texte, des liens et des images et il fait le reste.

Comment définir les destinataires? Par exemple, le partage par courrier électronique ou SMS devrait pouvoir accepter les destinataires, mais je ne sais pas comment invoquer ce comportement.

Je ne veux pas avoir à utiliser MFMessageComposeViewController et UIActivityViewController séparément car cela va juste à l'encontre de l'objectif du contrôleur de partage.

Aucune suggestion?

Référence de classe UIActivityViewController

Modifier: cela a maintenant été soumis Apple et ensuite fusionné avec un rapport de bogue en double.

Rapport de bogue sur OpenRadar

32
MattCheetham

Tout le mérite revient à Emanuelle, car il a trouvé la plupart du code.

Bien que je pensais que je publierais une version modifiée de son code qui aide à définir le destinataire.

J'ai utilisé une catégorie sur 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
3
thewormsterror

Pour ajouter sujet à l'e-mail à l'aide de UIActivityViewController sur iOS6, c'est la meilleure solution que tout le monde peut utiliser. Tout ce que vous avez à faire est d'appeler ce qui suit lors de l'initialisation de UIActivityViewController.

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

Et votre UIActivityViewController est rempli avec un sujet.

24
Ajay

Je viens de trouver une solution à ce problème (dans mon cas, définissez le sujet de l'e-mail): comme en interne, UIActivityViewController appellera à un moment donné la méthode setMessageBody: isHTML: de la classe MFMailComposeViewController, interceptez simplement cet appel et faites à l'intérieur un appel à la méthode setSubject :. Grâce à la technique de "méthode swizzling", on dirait:

#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

Appelez la ligne de code suivante avant d'utiliser UIActivityViewController:

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

Passez ensuite à UIActivityViewController un UIActivityItemProvider personnalisé qui pour UIActivityTypeMail renvoie une chaîne NSString HTML comme:

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

Le sujet de l'e-mail est extrait du titre HTML (utilisez du texte brut pour cette partie, pas d'entités html ou de balises).

En utilisant cette méthode, je vous laisse élaborer une manière élégante de définir le destinataire du courrier.

10
Emmanuel Paris

Bien qu'il semble qu'à l'heure actuelle la solution mailto: pour définir l'objet et le corps de l'e-mail ne fonctionne pas, cela ne serait en aucun cas adéquat si vous vouliez définir le corps de l'e-mail pour contenir du HTML et toujours utiliser l'icône de messagerie électronique du système Apple via UIActivityViewController.

C'est exactement ce que nous voulions faire: utiliser l'icône système, mais faire en sorte que l'e-mail contienne un corps HTML et un objet personnalisé.

Notre solution était un peu un hack, mais cela fonctionne bien, du moins pour le moment. Il implique l'utilisation de MFMailComposeViewController, mais il vous permet toujours d'utiliser l'icône de messagerie système avec UIActivityViewController.

Étape 1: Créez une classe wrapper conforme à UIActivityItemSource comme ceci:

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

Étape 2: sous-classe UIActivityViewController et en faire un MFMailComposeViewControllerDelegate comme suit:

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

REMARQUE: lorsque vous appelez super initWithActivityItems, Vous encapsulez l'objet que vous partagerez dans votre ActivityItemSource personnalisé

Étape 3: lancez votre propre MFMailComposeViewController au lieu de celui du système lorsqu'un utilisateur appuie sur l'icône Courrier.

Vous feriez cela dans la méthode activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType dans la classe 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];

    }

Dans la méthode mailComposeControllerWithObject, vous instanciez une instance de la classe MFMailComposeViewController et la configurez pour contenir les données que vous souhaitez. Notez également que vous définiriez le activityViewController comme délégué de la vue de composition.

La raison pour laquelle cela fonctionne est que lorsqu'un modal de composition est affiché, il empêche les autres modaux d'être affichés, c'est-à-dire que l'affichage de votre propre vue de composition bloque la vue de composition du système. Certainement un hack, mais il fait le travail.

J'espère que cela t'aides.

8
ilyashev

Je ne suis pas sûr des destinataires, mais il semble que dans iOS 7 et versions ultérieures, vous pouvez définir l'objet d'un e-mail en vous conformant au protocole UIActivityItemSource et en implémentant la méthode activityViewController:subjectForActivityType:.

1
Tim Camber

Vous devez être en mesure d'inclure les destinataires à l'aide d'un objet NSUrl avec le schéma mailto: (ou sms: pour les messages texte).

De la référence de classe UIActivity:

IActivityTypeMail L'objet publie le contenu fourni dans un nouveau message électronique. Lorsque vous utilisez ce service, vous pouvez fournir des objets NSString et UIImage et des objets NSURL pointant vers des fichiers locaux en tant que données pour les éléments d'activité. Vous pouvez également spécifier des objets NSURL dont le contenu utilise le schéma mailto.

Par conséquent, quelque chose comme ça devrait fonctionner:

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];
1
henning77