¿Cómo utilizo UIActivityItemProvider para enviar un correo electrónico con datos adjuntos con UIActivityViewController?

Estoy intentando usar UIActivityItemProvider para compartir un file desde mi aplicación mediante un file adjunto de correo electrónico. También necesito rellenar la línea de asunto del correo electrónico y especificar el nombre del file adjunto para que sea algo diferente al nombre del file almacenado en el dispositivo.

Aquí está el código que estoy usando. El problema es que el file adjunto falta en el correo electrónico.

@interface ItemProvider:UIActivityItemProvider @property (nonatomic, strong) NSURL *filepath; @property (nonatomic, strong) NSString *emailBody; @property (nonatomic, strong) NSString *emailSubject; @end @implementation ItemProvider - (id)initWithPlaceholderItem:(id)placeholderItem { //Initializes and returns a provider object with the specified placeholder data return [super initWithPlaceholderItem:placeholderItem]; } - (id)item { //Generates and returns the actual data object return [NSDictionary dictionary]; } // The following are two methods in the UIActivityItemSource Protocol // (UIActivityItemProvider conforms to this protocol) - both methods requinetworking #pragma mark UIActivityItemSource //- Returns the data object to be acted upon. (requinetworking) - (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType { if ([activityType isEqualToString:UIActivityTypeMail]) { return @{@"body":self.emailBody, @"url":self.filepath}; } return @{@"body":self.emailBody, @"url":self.filepath}; } //- Returns the placeholder object for the data. (requinetworking) //- The class of this object must match the class of the object you return from the above method - (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController { return @{@"body":self.emailBody, @"url":self.filepath}; } -(NSString *) activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType { return self.emailSubject; } @end 

Y luego, en mi opiniónController, hago esto:

  ItemProvider *provider = [[ItemProvider alloc] initWithPlaceholderItem:@{@"body":emailBody, @"url":filePath}]; provider.emailBody = emailBody; provider.emailSubject = info.title; provider.filepath = filePath; NSArray *activityItems = @[provider]; // Build a collection of custom activities (if you have any) // NSMutableArray *customActivities = [[NSMutableArray alloc] init]; UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil]; [self presentViewController:activityController animated:YES completion:nil]; 

Estoy enviando correo electrónico con datos adjuntos sin ItemProvider. funciona bien 🙂

 NSMutableArray *selDocs = [[NSMutableArray alloc] init]; for (Document *theDoc in self.selectedDocs) { NSURL *fileUrl = [NSURL fileURLWithPath:theDoc.filePath]; [selDocs addObject:fileUrl]; } NSArray *postItems = [NSArray arrayWithArray:selDocs]; UIActivityViewController *avc = [[UIActivityViewController alloc] initWithActivityItems:postItems applicationActivities:nil]; [avc setValue:@"Your email Subject" forKey:@"subject"]; avc.completionHandler = ^(NSString *activityType, BOOL completed){ NSLog(@"Activity Type selected: %@", activityType); if (completed) { NSLog(@"Selected activity was performed."); } else { if (activityType == NULL) { NSLog(@"User dismissed the view controller without making a selection."); } else { NSLog(@"Activity was not performed."); } } }; [self presentViewController:avc animated:YES completion:nil]; 

Para aquellos que siguen tropezando con una solución para esto, hay una solución más elegante para personalizar UIActivityViewController . Para abordar la pregunta original, la razón por la que el file adjunto no se muestra es porque se supone que es un object separado de UIActivityItemProvider .

Por lo tanto, la solución es crear dos subclasss UIActivityItemProvider , una para envolver 'emailBody' y 'emailSubject' y otra para envolver los datos adjuntos. El beneficio de utilizar un UIActivityItemProvider para el file adjunto es que tiene la oportunidad de demorar el procesamiento del file adjunto hasta que sea necesario, en lugar de hacerlo antes de presentar UIActivityViewController .

Implementar la class AttachmentProvider para proporcionar el file adjunto así:

 @implementation AttachmentProvider : UIActivityItemProvider - (id)item { if ([self.activityType isEqualToString:UIActivityTypeMail]) { /* Replace with actual URL to a file. Alternatively * you can also return a UIImage. */ return [NSData dataWithContentsOfURL:dataURL]; } return nil; } @end 

Implementar la class EmailInfoProvider al proveedor el cuerpo del correo electrónico y la class de sujeto así:

 @implementation EmailInfoProvider : UIActivityItemProvider - (id)item { return @"Your email body goes here"; } - (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType { if ([activityType isEqualToString:UIActivityTypeMail]) { return @"Your subject goes here"; } return nil; } @end 

A continuación, puede crear un UIActivityViewController con estos dos elementos en su viewController así:

 - (void)shareAction { AttachmentProvider *attachment = [[AttachmentProvider alloc] init]; EmailInfoProvider *emailContent = [[EmailInfoProvider alloc] init]; // You can provider custom -(id)init methods to populate EmailInfoProvider UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[attachment, emailContent] applicationActivities:nil]; [self presentViewController:activityController animated:YES completion:nil]; }