UIActivityViewController workaround to 'Share in WhatsApp' in iOS

Posted on Thu 19 May 2016 in engineering

NOTE: this post was originally posted on Medium, so some comments still leaving there: medium.com/@patoroco.


UIActivityViewController was introduced in iOS 6 as a helper to share texts, links or images between apps.

It's really easy to work with default services (share on Twitter, Facebook, Mail…), and since several iOS versions, it's also integrated with third-party apps like Slack or Telegram.

Share Activity

Use it is simple, you only need to create and present a UIActivityViewController as follows:

UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
UIActivityViewController *activityView = [[UIActivityViewControllerWithoutWhatsApp alloc] initWithActivityItems:shareObject applicationActivities:nil];
[root presentViewController:activityView animated:YES completion:nil];

A typical setup looks like that, but sometime you don't want to allow to send SMS, or Mails from your action, so you can set an array of excludedActivityTypes as follows:

activityView.excludedActivityTypes = @[UIActivityTypeMessage, UIActivityTypeMail];

There are several 'built-in' activities, but you can craft yourself UIActivity to do specific actions, a good compilation is available in Github/UIActivityCollection.

In our case, and because we suffered a bug related with last WhatsApp version, which showed a message when try to share with one of your whatsapp contacts:

This item cannot be shared. Please select a different item.

We decided to workaround it using URLSchemes, and we found SSCWhatsAppActivity, a UIActivity subclass which shows an icon on share menu, but it appeared next to the original whatsapp icon, so we needed to remove this first.

As logic indicated, we looked for whatsapp activity identifier, and add to excludeActivityTypes array as follows:

activityView.excludedActivityTypes = @[@"net.whatsapp.WhatsApp.ShareExtension"];

But it’s not possible to remove third-party activities from menu, at least directly. So, after play some minutes with <objc/runtime.h>, we finally found a private method which seemed to be related with our purpose: _shouldExcludeActivityType:

#import "UIActivityViewControllerWithoutWhatsApp.h"


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


@implementation UIActivityViewControllerWithoutWhatsApp
- (BOOL)_shouldExcludeActivityType:(UIActivity *)activity
{
    if ([[activity activityType] isEqualToString:@"net.whatsapp.WhatsApp.ShareExtension"]) {
        return YES;
    }

    return [super _shouldExcludeActivityType:activity];
}
@end

And, you know what? It works! Thanks Apple to do that so straightforward.

iOS