57

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.

Daniel Storm
  • 18,301
  • 9
  • 84
  • 152
Andriy Gordiychuk
  • 6,163
  • 1
  • 24
  • 59

9 Answers9

57

If you don't want to subclass UIActivityViewController you can include them in your .excludedActivityTypes when creating your UIActivityViewController.

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

Swift 4.2:

let activityController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
activityController.excludedActivityTypes = [
    UIActivity.ActivityType.assignToContact,
    UIActivity.ActivityType.print,
    UIActivity.ActivityType.addToReadingList,
    UIActivity.ActivityType.saveToCameraRoll,
    UIActivity.ActivityType.openInIBooks,
    UIActivity.ActivityType(rawValue: "com.apple.reminders.RemindersEditorExtension"),
    UIActivity.ActivityType(rawValue: "com.apple.mobilenotes.SharingExtension")]
present(activityController, animated: true, completion: nil)
Daniel Storm
  • 18,301
  • 9
  • 84
  • 152
35

Swift 2.2 version. Tested in iOS9.3. Works.

UPDATE and got approved by App Store Review.

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
    }

}

Also useful

 "com.apple.mobileslideshow.StreamShareService"

gets rid of the "cloud" one.

enter image description here

Fattie
  • 27,874
  • 70
  • 431
  • 719
guido
  • 2,792
  • 1
  • 21
  • 40
  • did you manage to get the app using this code approved by Apple? :) – Andriy Gordiychuk May 13 '16 at 19:14
  • Don't know yet. Gonna submit in about a week. Have a bit of hope as it seems that danielbmarques got his approved using the objC version (see comments in top answer). – guido May 13 '16 at 19:16
  • 2
    Apple Review just approved my app with this in it – guido May 27 '16 at 19:54
  • Really superb and useful answer - thanks so much. Sending bounty. – Fattie Aug 03 '16 at 16:57
  • I am curious, how did you find what string type refers to what app button? For example, how to find what dropbox string type is? Also, is there a way to get a list of all activities registered in a DEVICE? – GeneCode Sep 28 '16 at 03:31
  • 2
    Don't remember honestly, but I imagine of you print out actType to the console it would give you all the strings for the apps that appear. – guido Sep 28 '16 at 03:39
21

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.

Amal T S
  • 3,327
  • 2
  • 24
  • 57
Matteo Pacini
  • 21,796
  • 7
  • 67
  • 74
9

Anybody stumbling in this post in 2019. The key for the Reminders extension changed with iOS 13 and is now:

(rawValue: "com.apple.reminders.sharingextension")
TimLR
  • 267
  • 2
  • 10
6

You can not exclude these since Notes and Reminders are not declared as UIActivities in the Apple Documentation. Only a problem as of iOS9 and hopefully Apple will provide this option. The declared UIActivities until this moment are:

UIActivityTypePostToFacebook, 
UIActivityTypePostToTwitter, 
UIActivityTypePostToWeibo, 
UIActivityTypeMessage, 
UIActivityTypeMail, 
UIActivityTypePrint, 
UIActivityTypeCopyToPasteboard, 
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo,
UIActivityTypeAirDrop
Sushil Sharma
  • 2,321
  • 3
  • 29
  • 49
scbojer
  • 144
  • 4
  • 1) Of course they are declared as UIActivities. The problem is that the corresponding UIActivityType is not included 2) quite pointless to suggest that question which was asked 1 month ago is a duplicate of question which was asked TODAY :) I know that in the meantime it is not possible to exclude these items using standard methods. However, there might be some hack that someone knows. If not, Apple will fix this at some point and the question will get answered (and those who favourited it will get notification) :) – Andriy Gordiychuk Sep 22 '15 at 14:33
2

Thank you for this! On xcode 8.1, swift 3, I was able to use to get:

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

test ing
  • 31
  • 2
2

For Swift3+, there is no need for any Private API hacks. Simply use the public "excludedTypes" array on the UIActivityViewController. As there is still no UIActivityType for these (as they're Apple's built extensions), you need to refer to it via String. You could use this format for any third-party sharing extensions too.

e.g.

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)
mm282
  • 453
  • 3
  • 7
  • This is helpful and works for some sharing extensions, but seems not to for others: see @eranmarom's answer at https://stackoverflow.com/questions/32522977/uiactivityviewcontroller-exclude-non-apple-sharing-extensions – CKP78 Oct 11 '17 at 14:05
1

Only way I have found is to create your own custom activities, pass parameters to them directly (not through the activity sheet) and then pass some random variable (not String, URL, Image) through the activity sheet.

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

But then again, why would you want to use the ActivityViewController in the first place if you can't use any of the functionality... Hopefully there will be a better solution soon

eirik
  • 407
  • 1
  • 4
  • 9
1

I could not send _shouldExcludeActivityType to Super as recommended by Matteo Pacini, but this is how I could come around this:

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

 }