UIActivityViewController workaround to 'Share in WhatsApp' in iOS

UIActivityViewController was introduced in iOS 6 as a helper to share texts, links or images between apps.
It's really easy to work with the default services (share on Twitter, Facebook, Mail…), and for several iOS versions now it has also been integrated with third-party apps like Slack or Telegram.
Using 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 sometimes you don't want to allow sending SMS or emails 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 your own UIActivity to do specific actions; a good compilation is available in Github/UIActivityCollection.
In our case, because we ran into a bug related to the latest WhatsApp version, which showed this message when trying 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 the latter first.
Logically, we looked for the WhatsApp activity identifier and added it to the excludedActivityTypes array as follows:
activityView.excludedActivityTypes = @[@"net.whatsapp.WhatsApp.ShareExtension"];But it’s not possible to remove third-party activities from the menu, at least not directly. So, after playing for a few minutes with <objc/runtime.h>, we finally found a private method that seemed related to 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];
}
@endAnd, you know what? It works! Thanks, Apple, for making it so straightforward.