Как исключить приложения Notes и Reminders из UIActivityViewController?

Я создаю UIActivityViewController и передать String а также URL к этому. Это, очевидно, настраивает UIActivityViewController использовать некоторые элементы, которые я хочу исключить (моя цель - поделиться информацией о моем приложении).

Мне удалось исключить множество системных действий (например, "Добавить в список чтения"), установив соответствующие excludedActivityTypes,

Однако я не могу исключить приложения "Напоминания" и "Заметки". Может кто-нибудь предложить способ сделать это? Эти приложения появляются в списке на 3-м и 4-м месте, поэтому Twitter и Facebook становятся невидимыми, если пользователь не выполняет прокрутку

8 ответов

Решение

Есть способ, но включает в себя частный API.

Иногда Apple делает исключения, особенно если вы исправляете ошибку.

Давайте углубимся в детали...


UIActivityViewController имеет закрытый метод, называемый "_availableActivitiesForItems:", который возвращает массив объектов UISocialActivity.

У UISocialActivity есть интересное свойство, называемое "activityType", которое возвращает тип активности в формате домена.

После некоторых тестов мне удалось обнаружить типы действий Reminder и Notes:

  • com.apple.reminders.RemindersEditorExtension
  • com.apple.mobilenotes.SharingExtension

К сожалению, передача этих двух типов в ".excludedActivityTypes" не имеет никакого значения.

"_availableActivitiesForItems:" на помощь!

СТАРЫЙ ПУТЬ:

Обновление: я нашел лучший способ сделать это.

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

Заголовок:

#import <UIKit/UIKit.h>

@interface UISocialActivity : NSObject

- (id)activityType;

@end

@interface UIActivityViewController (Private)

- (id)_availableActivitiesForItems:(id)arg1;

@end

@interface ActivityViewController : UIActivityViewController

@end

Реализация:

@implementation ActivityViewController

- (id)_availableActivitiesForItems:(id)arg1
{
    id activities = [super _availableActivitiesForItems:arg1];
    NSMutableArray *filteredActivities = [NSMutableArray array];

    [activities enumerateObjectsUsingBlock:^(UISocialActivity*  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        if (![[obj activityType] isEqualToString:@"com.apple.reminders.RemindersEditorExtension"] &&
            ![[obj activityType] isEqualToString:@"com.apple.mobilenotes.SharingExtension"]) {
            [filteredActivities addObject:obj];
        }

    }];

    return [NSArray arrayWithArray:filteredActivities];
    }
    @end

НОВЫЙ ПУТЬ:

Заголовок:

@interface UIActivityViewController (Private)

- (BOOL)_shouldExcludeActivityType:(UIActivity*)activity;

@end

@interface ActivityViewController : UIActivityViewController

@end

Реализация:

@implementation ActivityViewController

- (BOOL)_shouldExcludeActivityType:(UIActivity *)activity
{
    if ([[activity activityType] isEqualToString:@"com.apple.reminders.RemindersEditorExtension"] ||
        [[activity activityType] isEqualToString:@"com.apple.mobilenotes.SharingExtension"]) {
        return YES;
    }
    return [super _shouldExcludeActivityType:activity];
}

@конец

"Незаконно", но это работает.

Было бы здорово узнать, действительно ли он проходит проверку Apple.

Если вы не хотите подкласс UIActivityViewController Вы можете включить их в свой .excludedActivityTypes при создании вашего UIActivityViewController,

Цель C:

UIActivityViewController *activityController = [[UIActivityViewController alloc]initWithActivityItems:sharingItems applicationActivities:nil];
activityController.excludedActivityTypes = @[
    UIActivityTypeAssignToContact,
    UIActivityTypePrint,
    UIActivityTypeAddToReadingList,
    UIActivityTypeSaveToCameraRoll,
    UIActivityTypeOpenInIBooks,
    @"com.apple.mobilenotes.SharingExtension",
    @"com.apple.reminders.RemindersEditorExtension"
];
[self presentViewController:activityController animated:YES completion:nil];

Свифт 3:

let activityController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
activityController.excludedActivityTypes = [
    UIActivityType.assignToContact,
    UIActivityType.print,
    UIActivityType.addToReadingList,
    UIActivityType.saveToCameraRoll,
    UIActivityType.openInIBooks,
    UIActivityType(rawValue: "com.apple.reminders.RemindersEditorExtension"),
    UIActivityType(rawValue: "com.apple.mobilenotes.SharingExtension"),
]
present(activityController, animated: true, completion: nil)

Версия Swift 2.2. Протестировано в iOS9.3. Работает.

ОБНОВЛЕНИЕ и получил одобрение обзора App Store.

import UIKit

class ActivityViewController: UIActivityViewController {

    func _shouldExcludeActivityType(activity: UIActivity) -> Bool {
        let activityTypesToExclude = [
            "com.apple.reminders.RemindersEditorExtension",
            "com.apple.mobilenotes.SharingExtension",
            UIActivityTypeOpenInIBooks,
            UIActivityTypePrint,
            UIActivityTypeAssignToContact,
            "com.google.Drive.ShareExtension"
        ]

        if let actType = activity.activityType() {
            if activityTypesToExclude.contains(actType) {
                return true
            }
            else if super.excludedActivityTypes != nil {
                return super.excludedActivityTypes!.contains(actType)
            }
        }
        return false
    }

}

Также полезно

 "com.apple.mobileslideshow.StreamShareService"

избавляется от "облачного".

Кто-нибудь наткнется на этот пост в 2019 году. Ключ для расширения напоминаний изменился с iOS 13 и теперь:

(rawValue: "com.apple.reminders.sharingextension")

Вы не можете исключить их, так как заметки и напоминания не объявлены как UIActivities в документации Apple. Только проблема с iOS9 и, надеюсь, Apple предоставит эту опцию. Заявленные UIActivities до этого момента:

UIActivityTypePostToFacebook, 
UIActivityTypePostToTwitter, 
UIActivityTypePostToWeibo, 
UIActivityTypeMessage, 
UIActivityTypeMail, 
UIActivityTypePrint, 
UIActivityTypeCopyToPasteboard, 
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo,
UIActivityTypeAirDrop

Для Swift3+ не требуется никаких взломов Private API. Просто используйте публичный массив "selectedTypes" в UIActivityViewController. Поскольку для них до сих пор нет UIActivityType (поскольку они являются встроенными расширениями Apple), вам нужно обращаться к нему через String. Вы также можете использовать этот формат для любых сторонних расширений обмена.

например

let avc = UIActivityViewController(activityItems: ["my item"], applicationActivities: nil)
avc.excludedActivityTypes = [ .copyToPasteboard, 
    UIActivityType(rawValue: "com.apple.reminders.RemindersEditorExtension"),
    UIActivityType(rawValue: "com.apple.mobilenotes.SharingExtension") ]

avc.completionWithItemsHandler = { (activity, success, items, error) in
        print("AVC finished \(success) \(activity as Optional) \(items as Optional) \(error as Optional)")
    }
present(avc, animated: true, completion: nil)

Спасибо тебе за это! На xcode 8.1, swift 3 мне удалось получить:

UIActivityType (rawValue: "com.apple.reminders.RemindersEditorExtension"), UIActivityType (rawValue: "com.apple.mobilenotes.SharingExtension"),

Единственный способ, который я нашел, - это создать свои собственные пользовательские действия, передать им параметры напрямую (не через лист активности), а затем передать некоторую случайную переменную (не String, URL, Image) через лист активности.

MyCustomPinterestShareActivity* pinterest = [[MyCustomPinterestShareActivity alloc] init];
MyCustomFacebookGroupsActivity* facebook = [[MyCustomFacebookGroupsActivity alloc] init];
MyCustomInstagramActivity* instagram = [[MyCustomInstagramActivity alloc] init];

NSArray *activities = @[facebook,instagram,pinterest];

NSArray *activityItems = @[someVarThatCanBeWhateverTypeJustNotStringURLOrImg];

UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems
                                                                           applicationActivities:activities];

Но опять же, зачем вам в первую очередь использовать ActivityViewController, если вы не можете использовать какую-либо функциональность... Надеюсь, скоро будет лучшее решение

Я не смог отправить _shouldExcludeActivityType Super в соответствии с рекомендациями Маттео Пачини, но вот как я мог обойти это:

@interface CustomActivityViewController()

- (BOOL)_shouldExcludeActivityType:(UIActivity *)activity;

@end

@implementation CustomActivityViewController

(...)

- (BOOL)_shouldExcludeActivityType:(UIActivity *)activity{

    if([[activity activityType]   isEqualToString:@"com.apple.reminders.RemindersEditorExtension"] || [[activity activityType] isEqualToString:@"com.apple.mobilenotes.SharingExtension"]){

    return YES;
}

    return [[super excludedActivityTypes]containsObject:activity.activityType];

 }
Другие вопросы по тегам