Подтвердить что ты не робот

Как установить получателей для UIActivityViewController в iOS 6?

Я использую новый класс UIActivityViewController в iOS6, чтобы предоставить пользователю различные параметры совместного доступа. Вы можете передать массив параметров, таких как текст, ссылки и изображения, и все остальное.

Как определить получателей? Например, обмен сообщениями по почте или SMS должен иметь возможность принимать получателей, но я не могу понять, как вызвать это поведение.

Я не хочу, чтобы использовать MFMessageComposeViewController и UIActivityViewController отдельно, поскольку это просто побеждает цель контроллера общего доступа.

Любые предложения?

Ссылка на класс UIActivityViewController

Изменить: теперь это было отправлено Apple и впоследствии объединено с дублированным отчетом об ошибке.

Отчет об ошибках в OpenRadar

4b9b3361

Ответ 1

Вся информация здесь относится к 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

Ответ 2

Чтобы добавить тему к электронной почте с помощью UIActivityViewController на iOS6, это лучшее решение, которое может использовать любой пользователь. Все, что вам нужно сделать, это вызвать следующее при инициализации UIActivityViewController.

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

И ваш UIActivityViewController заполнен субъектом.

Ответ 3

Я просто придумал решение этой проблемы (в моем случае задал вопрос по электронной почте): так как внутри UIActivityViewController вызовет в какой-то момент метод setMessageBody: isHTML: класс MFMailComposeViewController, просто перехват этого вызова и внутри вызовите метод setSubject:. Благодаря методу "swizzling method" это выглядит так:

#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).

Используя этот метод, я расскажу вам об элегантном способе установки получателя для почты.

Ответ 4

Пока кажется, что в настоящее время mailto: решение для настройки темы и тела электронной почты не работает, это ни в коем случае не будет адекватным, если вы хотите, чтобы тело электронной почты содержало HTML и все еще использовало Apple значок электронной почты системы через UIActivityViewController.

Это именно то, что мы хотели сделать: используйте значок системы, но в элементе электронной почты есть тело HTML и пользовательский объект.

Наше решение было чем-то вроде взлома, но оно работает хорошо, по крайней мере на данный момент. Это связано с использованием MFMailComposeViewController, но он по-прежнему позволяет использовать значок системной почты с помощью UIActivityViewController.

Шаг 1. Создайте класс оболочки, соответствующий источнику UIActivityItem, например:

    @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 вместо системного, когда пользователь нажимает на значок Mail.

Вы сделали бы это в методе 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 в качестве делегата представления компоновки.

Причина этого заключается в том, что когда отображается модаз модажа, это предотвращает отображение других модалов, т.е. вы показываете свои собственные представления компоновки, которые система не может отображать. Определенно, взлом, но он выполняет свою работу.

Надеюсь, что это поможет.

Ответ 5

Вы должны иметь возможность включать получателей, используя объект NSUrl, с помощью схемы mailto: (или смс: для текстовых сообщений).

Из ссылки класса UIActivity:

UIActivityTypeMailОбъект помещает предоставленный контент в новый сообщение электронной почты. При использовании этой службы вы можете предоставить NSString и Объекты UIImage и объекты NSURL, указывающие на локальные файлы в качестве данных для элементы деятельности. Вы также можете указать объекты NSURL, содержимое которых используйте схему mailto.

Следовательно, что-то вроде этого должно работать:

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

Ответ 6

Я не уверен о получателях, но похоже, что в iOS 7 и более поздних версиях вы можете настроить тему сообщения по протоколу UIActivityItemSource и реализовать метод activityViewController:subjectForActivityType:.