Twitter Sharing Text

14 September 2014

Daily Offers allows you to share the details of the selected offer on Twitter or Facebook, or via text message or email. The offer details can also be copied to the clipboard or printed. This is how that looks in iOS 7:

The Daily Offers share action sheet

This is trivial to implement using the UIActivityViewController class. You specify the data objects on which the view controller should act, then present the view controller, which displays the standard services. For example:

NSString *textToShare = // etc.
NSURL *urlToShare = // etc.

UIActivityViewController *activityViewController =
  [[UIActivityViewController alloc] initWithActivityItems:@[string, URL] applicationActivities:nil];
[navigationController presentViewController:activityViewController animated:YES completion:nil];

Although straightforward, one problem with this approach is that it assumes you want the same data object to be shared for each service. This wasn’t what I wanted for Daily Offers, because I knew that often the selected offer details text would be too long for the 140 character tweet limit mandated by Twitter.

The solution to this problem is to subclass the UIActivityProviderItem class. Instances of this class act as a proxy for data passed to the activity view controller. Here’s the header file code for SPSActivityItemProvider:

//
//  SPSActivityItemProvider.h
//  Daily Offers
//
//  Created by John Topley on 08/02/2014.
//  Copyright (c) 2014 John Topley. All rights reserved.
//

@interface SPSActivityItemProvider : UIActivityItemProvider

- (instancetype)initWithPlaceholderItem:(id)placeholderItem twitterItem:(NSString *)twitterItem;

@end

The UIActivityItemProvider class has an initWithPlaceholderItem: initializer method. In my subclass I make this initWithPlaceholderItem:twitterItem: to make it explicit that we’re doing something different for Twitter. Here’s the implementation code:

//
//  SPSTwitterActivityItemProvider.m
//  Daily Offers
//
//  Created by John Topley on 08/02/2014.
//  Copyright (c) 2014 John Topley. All rights reserved.
//

#import "SPSActivityItemProvider.h"

@implementation SPSActivityItemProvider {
    NSString *_twitterItem;
}

- (instancetype)initWithPlaceholderItem:(id)placeholderItem twitterItem:(NSString *)twitterItem
{
    self = [super initWithPlaceholderItem:placeholderItem];

    if (self) {
        _twitterItem = twitterItem;
    }

    return self;
}

- (id)item
{
    if ([self.activityType isEqualToString:UIActivityTypePostToTwitter]) {
        return _twitterItem;
    } else {
        return self.placeholderItem;
    }
}

@end

As you can see, there’s not much to it. The initializer method invokes the superclass initializer, passing it the default placeholder text. It also assigns the passed text for Twitter to an instance variable. I should probably switch to using a property instead of an instance variable, but is it worth revisiting this code now we’re in the brave new world of Swift?

The item method is the one method that UIActivityItemProvider subclasses must override. This is the callback method that gets invoked when iOS asks for the item’s data. The method checks to see if the activity type is UIActivityTypePostToTwitter. If it is, then it simply returns the text to use for Twitter, otherwise it returns the default placeholder text that was passed to the initializer.

This is the code behind the Share navigation bar button in the Offer Details screen:

- (IBAction)share
{
   SPSActivityItemProvider *activityItemProvider =
     [[SPSActivityItemProvider alloc] initWithPlaceholderItem:[self sharedText]
                                                  twitterItem:[self twitterSharedText]];
     
   UISimpleTextPrintFormatter *printFormatter =
     [[UISimpleTextPrintFormatter alloc] initWithText:[self sharedText]];
     
   NSArray *sharedItems = @[activityItemProvider, printFormatter];
   UIActivityViewController *controller =
     [[UIActivityViewController alloc] initWithActivityItems:sharedItems applicationActivities:nil];
     
   controller.excludedActivityTypes =
     @[UIActivityTypePostToWeibo, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll];
     
   [self presentViewController:controller animated:YES completion:nil];
}

An SPSActivityItemProvider instance is created and passed the standard offer details text to share, as well as the special Twitter variant returned by the twitterSharedText method (this method truncates the offer details to 140 characters, inserting an ellipsis if required). This instance is put into an array along with a UISimpleTextPrinterFormatter instance used for printing the offer details.

A UIActivityViewController is created as before and passed the array of items for sharing. Some activity types that aren’t applicable are excluded. Finally, the activity view controller’s user interface is presented and the offer details can go viral on social media.

A tweet being composed within Daily Offers