Last month I attended CocoaConf DC. Jonathan Blocksom presented one of my favorite sessions, which covered UIActivityViewController and social networking. I recently had the opportunity to work with theUIActivityViewController, so I thought I would use this post to discuss what I learned at CocoaConf DC from Jonathan along with my hands on experience.

With the release of iOS 6.0, Apple has made it much easier to incorporate social networking, especially Facebook and Sina Weibo, into an app. It also gives developers the ability to provide the user with a consistent user experience even with services that are not built into iOS. We will be using Google+ in the following example to demonstrate this capability. Let's get started.

At the most basic level, using just a few lines of code, our app can easily share with any of the supported social networks by taking advantage of some system level functionality.

Note that on a device this screen would also show an option to share using the Messages app. That app is not available on the simulator so it is automatically filtered out by the system. The code to display the sharing screen is quite simple.

NSString *shareString = @"CapTech is a great place to work.";
UIImage *shareImage = [UIImage imageNamed:@"captech-logo.jpg"];
NSURL *shareUrl = [NSURL URLWithString:@"http://www.captechconsulting.com"];
 
NSArray *activityItems = [NSArray arrayWithObjects:shareString, shareImage, shareUrl, nil];
 
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
activityViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
 
[self presentViewController:activityViewController animated:YES completion:nil];

Looking at the code, you can see that we pass three parameters into the UIActivityViewController. The first is a simple string, the second is an image and the last is a URL. Only one of the three items is required; the others can be left out if not needed.

In this example we are demonstrating sharing only, so the options for saving to camera roll, printing and copying do not apply. Adding just one more line of code will remove those options from the list.

activityViewController.excludedActivityTypes @[UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll];

You can see that adding the sharing capability is very simple. But, what if the text we want to share is longer, maybe too long for Twitter, or we want to customize the text we are sharing for each source? We are passing all three parameters into the UIActivityViewController before the destination is selected, which completely eliminates that ability. Fortunately, Apple provides another option, which is to subclass UIActivityItemProvider. When subclassing, the method activityViewController:itemForActivityType: will be called when the item is selected. At this point we will know which option was selected and can customize the text that will be shared accordingly.

UIActivityItemProvider conforms to the UIActivityItemSource protocol. UIActivityItemSource has two methods that must be implemented. The first is activityViewControllerPlaceholderItem: in which we simply return an empty string as demonstrated below.

return @"";

The second method is activityViewController:itemForActivityType: and this is where we customize the text that we want to have returned. The code below shows our implementation of this, which will customize the text for Facebook, Twitter, and Sina Weibo while keeping the same generic text as before for any other source selected.

NSString *shareString = @"CapTech is a great place to work";
 
if ([activityType isEqualToString:UIActivityTypePostToFacebook]) {
 shareString = [NSString stringWithFormat:@"Attention Facebook: %@", shareString];
} else if ([activityType isEqualToString:UIActivityTypePostToTwitter]) {
 shareString = [NSString stringWithFormat:@"Attention Twitter: %@", shareString];
} else if ([activityType isEqualToString:UIActivityTypePostToWeibo]) {
 shareString = [NSString stringWithFormat:@"Attention Weibo: %@", shareString];
}
 
return shareString;

Now when we select Twitter, for example, we will see the text is specific to Twitter.

But we can still take this a step further. Now that our text has been customized and we are using all of the sources that are available within iOS we can start looking at expanding our reaches to other social platforms. Lets take a look at Google+.

The first step is to create a custom UIActivity, which we will name GooglePlusActivity. There are several methods that must be implemented, however, most of them are quite simple.

  • activityTitle will return the string that is displayed below the icon for our new activity.
  • activityType will return the string to represent our new activity.
  • activityImage returns a UIImage that is the icon we want to appear in the list of activities as one of the options.
  • canPerformWithActivityItems: requests permission to perform the sharing activity. In our case we will always return YES, but this is where you would do validation if there were certain parameters that needed to be met before sharing is enabled.
  • prepareWithActivityItems: is used in preparation for the sharing activity. We are going to store the text and URL for later use. Note that the image will not be shared to Google+. This is for simplicity because the Google+ API does not allow all three to be posted at the same time.

Here is a look at the code.

- (NSString *)activityTitle {
 return @"Google+";
}
 
- (NSString *)activityType {
 return @"com.captech.googlePlusSharing";
}
 
- (UIImage *)activityImage {
 return [UIImage imageNamed:@"Google-icon.png"];
}
 
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
 return YES;
}
 
- (void)prepareWithActivityItems:(NSArray *)activityItems {
 for (NSObject *item in activityItems) {
 if ([item isKindOfClass:[NSString class]]) {
 self.text = (NSString *)item;
 } else if ([item isKindOfClass:[NSURL class]]) {
 self.url = (NSURL *)item;
 }
 }
}

The activity is ready to be displayed in the list of available options. Next we need to make it appear in the list when the share button is pressed. The code below is the update that needs to be made when presenting theUIActivityViewController.

GooglePlusActivity *gPlusActivity = [[GooglePlusActivity alloc] init];
 
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityProviders applicationActivities:@[gPlusActivity]];

If we tap the Google+ button at this point nothing will happen. So we need to give the activity some behavior. There are two options for the behavior. The first is to implement activityViewController: which will return aUIViewController. That returned UIViewController would then handle completion of the sharing action. The second option, and the one that we will use, is to implement the performActivity method. In this method we will authenticate with Google. Upon authentication our app will get a callback to the method finishedWithAuth:error: If there is no error returned then we will share the text and URL specified. When the sharing is complete, our app will be notified of success or failure in finishedSharing:.

Since this is not a discussion on how to use the Google+ API, I will not show all the steps in signing in and posting (although it is available in the downloadable source code at the end of this post) but instead will simply point out how to implement the sharing steps. The following code completes GooglePlusActivity

- (void)performActivity {
 GPPSignIn *signIn = [GPPSignIn sharedInstance];
 signIn.clientID = kClientId;
 signIn.scopes = [NSArray arrayWithObjects:
 kGTLAuthScopePlusLogin, // defined in GTLPlusConstants.h
 nil];
 signIn.delegate = self;
 
 [signIn authenticate];
}
 
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error {
 if (error != nil) {
 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"There was an error loggin in." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
 [alert show];
 } else {
 // share
 id shareBuilder = [[GPPShare sharedInstance] shareDialog];
 
 // you're sharing based on the URL you included.
 [shareBuilder setURLToShare:self.url];
 [shareBuilder setPrefillText:self.text];
 
 [shareBuilder open];
 }
 
 [self activityDidFinish:YES];
}
 
- (void)finishedSharing: (BOOL)shared {
 if (shared) {
 NSLog(@"User successfully shared!");
 } else {
 NSLog(@"User didn't share.");
 }
}

When we run the app now we will see that we are presented with a sign-in screen followed by the sharing screen. You will notice we still have the default text. To customize this text go back to our ActivityProvider and add the following code in activityViewController:itemForActivityType:

if ([activityType isEqualToString:@"com.captech.googlePlusSharing"]) {
 shareString = [NSString stringWithFormat:@"Attention Google+: %@", shareString];
}

At last, we can share unique content to any source, including those that are not built into iOS. As a note, the Google+ API will transition your app to the background and use safari to complete the post. It does, however, return to your app when the post is completed using a custom URL as described in the Google+ API Getting Started guide.