varios - desactivar codigo iphone
¿Cómo configuro los destinatarios para UIActivityViewController en iOS 6? (6)
Estoy usando la nueva clase UIActivityViewController
en iOS6 para proporcionar al usuario varias opciones de uso compartido. Puede pasarle una serie de parámetros, como texto, enlaces e imágenes, y hace el resto.
¿Cómo defino los destinatarios? Por ejemplo, compartir por correo o SMS debería poder aceptar destinatarios, pero no puedo encontrar la manera de invocar este comportamiento.
No quiero tener que tener que usar MFMessageComposeViewController
y UIActivityViewController
separado, ya que eso acaba con el propósito del controlador compartido.
¿Alguna sugerencia?
Referencia de clase UIActivityViewController
Editar: ahora se envió Apple y luego se fusionó con un informe de error duplicado.
Acabo de encontrar una solución a este problema (en mi caso establezco el tema del correo electrónico): como internamente el UIActivityViewController llamará en algún momento al método setMessageBody: isHTML: de la clase MFMailComposeViewController, simplemente intercepte esa llamada y dentro haga una llamar al método setSubject: Gracias a la técnica "método swizzling", parece que:
#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
Llame a la siguiente línea de código antes de usar UIActivityViewController:
MethodSwizzle([MFMailComposeViewController class], @selector(setMessageBody:isHTML:), @selector(setMessageBodySwizzled:isHTML:));
A continuación, pase al UIActivityViewController un UIActivityItemProvider personalizado que para UIActivityTypeMail devuelve un NSString HTML como:
<html><head>
<title>Subject of the mail</title>
</head><body>
Body of the <b>mail</b>
</body></html>
El asunto del correo electrónico se extrae del título de HTML (use texto sin formato para esa parte, sin entidades html o etiquetas).
Usando ese método, te dejo elaborar una manera elegante de configurar al destinatario para el correo.
Debería poder incluir los destinatarios utilizando un objeto NSUrl con el esquema mailto: (o sms: para mensajes de texto).
De la referencia de la clase UIActivity:
UIActivityTypeMail El objeto publica el contenido proporcionado en un nuevo mensaje de correo electrónico. Al utilizar este servicio, puede proporcionar objetos NSString y UIImage y objetos NSURL apuntando a archivos locales como datos para los elementos de actividad. También puede especificar objetos NSURL cuyos contenidos usan el esquema mailto.
Por lo tanto, algo como esto debería funcionar:
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];
No estoy seguro acerca de los destinatarios, pero parece que en iOS 7 y posterior puede establecer el tema de un correo electrónico al ajustarse al protocolo UIActivityItemSource
y al implementar el método activityViewController:subjectForActivityType:
Para agregar sujeto al correo electrónico usando UIActivityViewController en iOS6, esta es la mejor solución que cualquiera puede usar. Todo lo que tiene que hacer es invocar lo siguiente al inicializar UIActivityViewController.
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities];
[activityViewController setValue:@"My Subject Text" forKey:@"subject"];
Y su UIActivityViewController se completa con un asunto.
Si bien parece que en la actualidad la solución mailto: para configurar el cuerpo y el asunto del correo electrónico no funciona, en todo caso no sería adecuada si desea configurar el cuerpo del correo electrónico para que contenga HTML y seguir utilizando el icono de correo electrónico del sistema de Apple. a través de UIActivityViewController.
Eso era exactamente lo que queríamos hacer: usar el ícono del sistema, pero hacer que el correo electrónico contenga un cuerpo HTML y un tema personalizado.
Nuestra solución fue algo así como un truco, pero funciona bien, al menos por el momento. Implica el uso de MFMailComposeViewController, pero todavía le permite usar el icono de correo del sistema con UIActivityViewController.
Paso 1: crea una clase contenedora conforme a UIActivityItemSource como sigue:
@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;
}
Paso 2: Subclase UIActivityViewController y conviértalo en MFMailComposeViewControllerDelegate de la siguiente manera:
@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;
}
NOTA: cuando llama a super initWithActivityItems
está super initWithActivityItems
el objeto que compartirá en su ActivityItemSource personalizado.
Paso 3: inicie su propio MFMailComposeViewController en lugar del sistema uno cuando un usuario toque el icono de Correo.
Haría esto en activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
method en la clase 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];
}
En el método mailComposeControllerWithObject
una instancia de la clase MFMailComposeViewController y la configura para que contenga los datos que desee. Tenga en cuenta también que establecería activityViewController
como el delegado de la vista de composición.
La razón por la que esto funciona es que cuando se muestra un modal de redacción, evita que se muestren otros modales, es decir, que muestre sus propios bloques de visualización de redacción para que no se muestre la vista de composición del sistema. Definitivamente un truco, pero hace el trabajo bien.
Espero que esto ayude.
Todo el crédito aquí va a Emanuelle, ya que se le ocurrió la mayor parte del código.
Aunque pensé que publicaría una versión modificada de su código que ayuda a establecer el destinatario.
Usé una Categoría en 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