Search code examples
ioscocoa-touchuiactivityviewcontrolleruiactivity

How to exclude Notes and Reminders apps from the UIActivityViewController?


I am creating a UIActivityViewController and pass String and URL to it. This, obviously, configures the UIActivityViewController to use some items which I want to exclude (my objective is to share the info about my app).

I have managed to exclude lots of system provided activities (like 'Add to Reading list') by setting the appropriate excludedActivityTypes.

However, I am unable to exclude Reminders and Notes apps. Can someone suggest a way of doing it? These apps appear 3rd and 4th on the list and therefore make Twitter and Facebook not visible unless user scrolls.


Solution

  • There is a way, but involves private API.

    Sometimes Apple makes exceptions, especially if you fix a bug.

    Let's dive into details...


    UIActivityViewController has got a private method called "_availableActivitiesForItems:", which returns an array of UISocialActivity objects.

    UISocialActivity has got an interesting property, called "activityType", which returns a domain-formatted activity type.

    After some tests, I managed to discover the Reminder and Notes activity types:

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

    Unfortunately, passing those two types into ".excludedActivityTypes" didn't make any difference.

    "_availableActivitiesForItems:" to the rescue!

    OLD WAY:

    Update: I've found a better way to do it.

    The first solution I've posted doesn't work in some cases, thus shouldn't be considered stable.

    Header:

    #import <UIKit/UIKit.h>
    
    @interface UISocialActivity : NSObject
    
    - (id)activityType;
    
    @end
    
    @interface UIActivityViewController (Private)
    
    - (id)_availableActivitiesForItems:(id)arg1;
    
    @end
    
    @interface ActivityViewController : UIActivityViewController
    
    @end
    

    Implementation:

    @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
    

    NEW WAY:

    Header:

    @interface UIActivityViewController (Private)
    
    - (BOOL)_shouldExcludeActivityType:(UIActivity*)activity;
    
    @end
    
    @interface ActivityViewController : UIActivityViewController
    
    @end
    

    Implementation:

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

    @end

    "Illegal", but it works.

    It would be great to know if it actually passes Apple validation.