Social Media Site Sharing with the iOS6 SDK

Christine Abernathy, October 15, 2012

Christine Abernathy, an engineer on the Developer Relations team at Facebook, was nice enough to write this great article on sharing content via Facebook on iOS 6. Let us and her know what you think in the comments.

Also, if this is your first time here, we offer the best collection of curated open source components for iOS apps around. Check out what we have to offer!

— Aaron

p.s. please take a moment to vote for this on Hacker News if you liked it!


The iOS6 SDK released by Apple enhanced their social framework allowing you to share to social media sites beyond Twitter. Now you can share content, pictures and images with social sites such as Facebook and Sina Weibo using built-in UI provided by the Apple SDKs.

In this tutorial, I’ll walk you through the Facebook sharing features and how you can implement them using the Apple-provided frameworks.


Overview: Social Features

There are three ways you can share to social media sites:

  1. The UIActivityViewController class allows your app to provide several services in context, one of which would be posting content to social media sites.
  2. The SLComposeViewController class is targeted more to social media sites, allowing users of your app to compose a post to send to those sites.
  3. The SLRequest is the third way that you can integrate with social media sites. This provides you a way to wrap HTTP requests to these sites to perform servers, such as sharing content directly via an API provided by that site. For example, posting to Facebook requires you to send an HTTP POST to the http://graph.facebook.com/[FacebookUserId]/feed endpoint with the data you wish to post. Using this class requires more work than the previous two but provides more functionality.

I’ll walk through how you can use each of these classes to post content to Facebook and Twitter. Here are the topic areas I’ll cover:

  • Sharing via the Share Sheet
  • Sharing via the Composer
  • Sharing via the Social Media Site APIs (Facebook)
  • Sharing via the Social Media Site APIs (Twitter)

Sharing via the Share Sheet

Using the UIActivityViewController is the easiest way to implement sharing. It’s scope is broad and gives uses the option to share content based on the type of content. For example, if you pass in info that you’re sharing text, users will see options to share via e-mail, SMS, Twitter, Facebook, etc. The advantage again, is the ease of implementation.

Step 1: Add a button to your view that will launch the share sheet.

  1. Go to your .xib file and add a Round Rect Button to your view.
  2. Add an action for this button to your view controller implementation file.

Step 2: Add the logic behind the button.

  1. Let’s find an image that you’ll use for sharing. Find your favorite image (PNG format), download it and drag it into your project.
  2. Find the action method that was pre-populated in the previous step.
  3. Add the following code:
    NSString *message = @"Hello World!";
    UIImage *imageToShare = [UIImage imageNamed:@"test.jpg"];
    
    NSArray *postItems = @[message, imageToShare];
    
    UIActivityViewController *activityVC = [[UIActivityViewController alloc]
                                      initWithActivityItems:postItems
                                      applicationActivities:nil];
    
    [self presentViewController:activityVC animated:YES completion:nil];

Step 3: Build and Test

Build and run the project on an iOS6 simulator. If this is the first time using your simulator log in to your Facebook and Twitter accounts to test out sharing to those social networks. You can log in by going to the device’s Setting app and entering your login info for Twitter and Facebook. Head back to the app and re-launch it. Click on the button. You should see something similar to this when you click the button then select Facebook and next Twitter:

This is the simplest form of sharing. Now let’s move on to the next one, using the SLComposeViewController class to narrow the share site choices to only social networks.


Sharing via the Composer

If you’re looking for an easy way to implement user sharing targeted to one or more social site, then take a look at the SLComposeViewController class. You can add code to share specifically to Facebook, Twitter and other supported sites.

Step 1: Add the additional required framework.

  1. Go to your target in Xcode and then click on the Build Phases tab.
  2. Open up the Link Binary With Libraries section.
  3. Add the Social.framework.

Step 2: Add buttons to your view that will launch the composers.

  1. Go to your .xib file and add two Round Rect Button objects to your view. One will launch the Facebook composer. The second button will launch the Twitter composer.
  2. Add an action for the two buttons to your view controller implementation file.

Step 3: Add the logic behind the buttons

  1. Find the action method that was pre-populated in the previous step that you tied to Facebook.
  2. Add the following code:
    SLComposeViewController *fbVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
    
    [fbVC setInitialText:@"Hello Facebook"];
    [fbVC addURL:[NSURL URLWithString:@"https://developers.facebook.com/ios"]];
    [fbVC addImage:[UIImage imageNamed:@"test.jpg"]];
    
    [self presentViewController:fbVC animated:YES completion:nil];
  3. Find the action method that was pre-populated in the previous step that you tied to Twitter.
  4. Add the following code:
    SLComposeViewController *twitterVC = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
    
    [twitterVC setInitialText:@"Hello Twitter"];
    [twitterVC addURL:[NSURL URLWithString:@"https://dev.twitter.com/docs"]];
    [twitterVC addImage:[UIImage imageNamed:@"test.jpg"]];
    
    [self presentViewController:twitterVC animated:YES completion:nil];

Step 4: Build and Test

Build and run the project on an iOS6 simulator. Click on the Facebook composer button. You should see something similar to this:

Click on the Twitter composer button. You should see something similar to this:


Sharing via the Social Media Site APIs (Facebook)

Facebook provides APIs that allow you to write to their social graph. For more info visit the Facebook Developers site.

Step 1: Create a Facebook App

  1. Create a new app on the Facebook App Dashboard, enter your app’s basic information.


  2. Once created, note the app ID shown at the top of the dashboard page. You’ll be using it later.
  3. Configure the Native iOS App settings in the dashboard page.


  4. Open up your app’s .plist file in Xcode and make sure your bundle identifier matches the entry in your Facebook App setting’s Bundle ID field.


Step 2: Add the additional required framework.

  1. Go to your target in Xcode and then click on the Build Phases tab.
  2. Open up the Link Binary With Libraries section.
  3. Add the Accounts.framework.

Step 3: Add a button to your view that will trigger the share via the Facebook API.

  1. Go to your .xib file and add a Round Rect Button to your view.
  2. Add an action for this button to your view controller implementation file.

Step 4: Add the logic behind the button.

When the user clicks on the button, you’ll enable the user to post a status update to Facebook. This flow will show you the essential parts of the integration. You’ll create a very simple user interface for the status entry, using a UIAlertView instance configured to show a text input. The UIAlertView will have a submit and cancel button. When the user clicks submit, you’ll ask for additional permissions to publish the post, then make a call to the Facebook Graph API status post endpoint using the SLRequest class and passing in a parameter for the status message.

Let’s go ahead and add code to do all this.

  1. The ACAccountStoreclass provides access to the social media site accounts. First, set up a private property for the account store in your implmentation file and synthesize the property:
    // ....
    
    @interface ViewController ()
    @property (strong, nonatomic) ACAccountStore *accountStore;
    
    // ....
    
    @implementation ViewController
    @synthesize accountStore = _accountStore;
  2. Initialize the account store instance in your viewDidLoadmethod:
    //....
    
    [super viewDidLoad];
    
    self.accountStore = [[ACAccountStore alloc] init];
  3. Set up a private property that will represent the Facebook user in the account store. Synthesize this new property:
    // ....
    @property (strong, nonatomic) ACAccountStore *accountStore;
    @property (strong, nonatomic) ACAccount *fbAccount;
    
    // ....
    
    @synthesize accountStore = _accountStore;
    @synthesize fbAccount = _fbAccount;
  4. Set up a private property that you’ll use later to indicate a Facebook API request. This sets things up for the Twitter example. Also synthesize this new property.
    // ....
    
    @property (strong, nonatomic) ACAccount *fbAccount;
    @property (strong, nonatomic) NSString *slService;
    
    // ....
    
    @synthesize fbAccount = _fbAccount;
    @synthesize slService = _slService;
  5. Find the action that was pre-populated in the previous step for the Facebook API share.
  6. Add the following code to that method, replacing <YOUR_APP_ID>with your Facebook app ID:
    // Set some default permissions
    
    NSArray *permissions = @[@"email"];
    
    // Set the dictionary that will be passed on to request account access
    
    NSDictionary *fbInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                          @"<YOUR_APP_ID>", ACFacebookAppIdKey,
                          permissions, ACFacebookPermissionsKey,
                          ACFacebookAudienceOnlyMe, ACFacebookAudienceKey,
                          nil];
    
    // Get the Facebook account type for the access request
    
    ACAccountType *fbAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    
    // Request access to the Facebook account with the access info
    
    [self.accountStore requestAccessToAccountsWithType:fbAccountType options:fbInfo completion:^(BOOL granted, NSError *error) {
       if (granted) {
           // If access granted, then get the Facebook account info
    
           NSArray *accounts = [self.accountStore accountsWithAccountType:fbAccountType];
    
           self.fbAccount = [accounts lastObject];
    
           // Set the service type for this request. This will be
           // used by the share input flow to configure it's UI.
    
           self.slService = SLServiceTypeFacebook;
    
           // Since this handler can be called on an arbitrary queue
           // will show the UI in the main thread.
    
           [self performSelectorOnMainThread:@selector(showSimpleTextInput) withObject:nil waitUntilDone:NO];
       } else {
           NSLog(@"Access not granted");
       }
    }];
  7. Note that when the user has granted your app access, you’re calling a method showSimpleTextInput that has yet to be defined. This is where you’ll present a simple user interface for the user to enter a status update. In your real world app, you’ll likely make user interface much nicer, perhaps create a new view with a user interface to match those provided by Apple’s built-in UI. Define the private helper method, showSimpleTextInput:
    - (void) showSimpleTextInput {
    
      // Define the alert view parameters
      // that depend on the service type
    
      NSString *title;
      NSString *shareButtonText;
    
      if ([self.slService isEqualToString:SLServiceTypeFacebook]) {
          title = @"Facebook";
          shareButtonText = @"Post";
      } else {
          title = @"Twitter";
          shareButtonText = @"Send";
      }
    
      UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:@"" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:shareButtonText, nil];
    
      // Set the alert view property to display a text input
      alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
    
      [alertView show];
    }
  8. When you set up the alert view you configured your view controller implementation file to be the delegate. This is so you can respond to a submit action and post the status update. Now, set up your view controller implementation class to conform to the UIAlertViewDelegate delegate:
    @interface ViewController () <UIAlertViewDelegate>
  9. Implement the delegate method that responds to button clicks. In your implementation you’ll ask for the publish_actionsFacebook permission that is required for status posts. If permission is granted, you’ll make the actual request in a method that you’ll define next:
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
      // Share button is index=1
    
      if (buttonIndex == 1) {
    
          if ([self.slService isEqualToString:SLServiceTypeFacebook]) {
    
              NSArray *permissions = @[@"email", @"publish_actions"];
    
              // Set the dictionary that will be passed on to request
              // account access
    
              NSDictionary *fbInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                      @"&lt;YOUR_APP_ID&gt;", ACFacebookAppIdKey,
                                      permissions, ACFacebookPermissionsKey,
                                      ACFacebookAudienceOnlyMe, ACFacebookAudienceKey,
                                      nil];
    
              // Get the Facebook account type for the access request
    
              ACAccountType *fbAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    
              // Request access to the Facebook account with the access info
    
              [self.accountStore requestAccessToAccountsWithType:fbAccountType options:fbInfo completion:^(BOOL granted, NSError *error) {
                   if (granted) {
                       // If access granted, then get the Facebook account info
    
                       NSArray *accounts = [self.accountStore accountsWithAccountType:fbAccountType];
    
                       self.fbAccount = [accounts lastObject];
    
                       // Set the service type for this request. This will be
                       // used by the share input flow to configure it's UI.
                       self.slService = SLServiceTypeFacebook;
    
                       // Since this handler can be called on an arbitrary queue
                       // will show the UI in the main thread.
    
                       [self performSelectorOnMainThread:@selector(sendFacebookRequest:) withObject:[[alertView textFieldAtIndex:0] text] waitUntilDone:NO];
                   } else {
                       NSLog(@"Access not granted");
                   }
               }];
          }
      }
    }
  10. As you did in similar code you added previously, swap out &lt;YOUR_APP_ID&gt; with your Facebook app ID. Note that this code is very similar to the one you added earlier when the user clicked on your view. The iOS6 Facebook integration requires you to ask for read type permissions initially. You cannot ask for write type or publish type permissions the first time around. The SDK will return an error. You therefore need to ask for publish_actions permissions in context, and in this case you’re doing this when the user explicitly chooses to share. The user will then see a one-time permissions request alert. Unless they remove their Facebook log in info from the iOS Settings app, or they revoke permissions for your app, they will not see the permissions pop up again on that device. If they use another device, they will see the permissions prompt once more.
  11. Define the helper method sendFacebookRequestthat performs the API share request by posting to Facebook when the user grants your app access.
    - (void) sendFacebookRequest:(NSString *)message {
      // Put together the post parameters. The status message
      // is passed in the message parameter key.
    
      NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:message, @"message", nil];
    
      // Set up the Facebook Graph API URL for posting to a user's timeline
      NSURL *requestURL = [NSURL URLWithString:@"https://graph.facebook.com/me/feed"];
    
      // Set up the request, passing all the required parameters
      SLRequest *fbShareRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodPOST URL:requestURL parameters:params];
    
      // Set up the account for this request
      fbShareRequest.account = self.fbAccount;
    
      // Perform the request
      [fbShareRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
           // In the completion handler, echo back the response
           // which should the Facebook post ID
    
           NSString *response = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
           NSLog(@"returned info: %@", response);
       }];
    }

Step 5: Build and Test

Build and run the project on an iOS6 simulator. Click on the Facebook API share button. You should see an alert pop up with a text input. Enter some text and click the submit button. Your flow should look like this:


Sharing via the Social Media Site APIs (Twitter)

Twitter provides a rich set of APIs including those that allow you to update the current user’s status. For more information visit the Twitter API Resources.

Step 1: Add a button to your view that will trigger the share via the Twitter API.

  1. Go to your .xib file and add a Round Rect Button to your view.
  2. Add an action for this button to your view controller implementation file.

Step 2: Add the logic behind the button.

When the user clicks on the button, you’ll enable the user to post a status update to Twitter. You’ll reuse the same UI flow you created for the Facebook API share. You’ll make a minor UI tweak in the UIAlertView you display. You’ll also make a call to the Twitter API’s status update endpoint using the SLRequest class and passing in a parameter for the status message.

Let’s go ahead and add code for these modifications.

  1. Set up a private property that will represent the Twitter user in the account store. Synthesize this new property:
    // ....
    @property (strong, nonatomic) NSString *slService;
    @property (strong, nonatomic) ACAccount *twitterAccount;
    
    // ....
    
    @synthesize slService = _slService;
    @synthesize twitterAccount = _twitterAccount;
  2. Find the action that was pre-populated in the previous step for the Twitter API share. The code you add will request access for the Twitter account in the account store. When access has been granted, you’ll call the showSimpleTextInputmethod defined earlier to show the pop up where the user can enter a status update:
    // Get the Twitter account type for the access request
    
    ACAccountType *twitterAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
    
    // Request access to the Twitter account with the access info
    [self.accountStore requestAccessToAccountsWithType:twitterAccountType options:nil completion:^(BOOL granted, NSError *error) {
       if (granted) {
           // If access granted, then get the Twitter account info
           NSArray *accounts = [self.accountStore accountsWithAccountType:twitterAccountType];
    
           self.twitterAccount = [accounts lastObject];
           self.slService = SLServiceTypeTwitter;
    
           // Since this handler can be called on an arbitrary queue
           // will show the UI in the main thread.
    
           [self performSelectorOnMainThread:@selector(showSimpleTextInput) withObject:nil waitUntilDone:NO];
       } else {
           NSLog(@"Access not granted");
       }
    }];
  3. Modify the alertView:clickedButtonAtIndexmethod you implemented earlier to detect an update originating from the selection of Twitter. Call a method that you’ll define next to make the Twitter API request:
    // ....
                       NSLog(@"Access not granted");
                   }
               }];
          } else if ([self.slService isEqualToString:SLServiceTypeTwitter]) {
              // Make a call to send the Twitter status update
              [self sendTwitterRequest:[[alertView textFieldAtIndex:0] text]];
          }
      }
    }
  4. Define the helper method sendTwitterRequestthat performs the API status update:
    - (void) sendTwitterRequest:(NSString *)message {
    
      // Put together the send parameters. The status message
      // is passed in the status parameter key.
    
      NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:message, @"status", nil];
    
      // Set up the Twitter API URL for posting to a user's timeline
      NSURL *requestURL = [NSURL URLWithString:@"https://api.twitter.com/1.1/statuses/update.json"];
    
      // Set up the request, passing all the required parameters
      SLRequest *twitterShareRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:requestURL parameters:params];
    
      // Set up the account for this request
      twitterShareRequest.account = self.twitterAccount;
    
      // Perform the request
      [twitterShareRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
    
           // In the completion handler, echo back the response
           // which should the Tweets object
    
           NSString *response = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
           NSLog(@"returned info: %@", response);
       }];
    }

Step 3: Build and Test

Build and run the project on an iOS6 simulator. Click on the Twitter API share button. You should see an alert pop up with a text input. Enter some text and click the submit button. Your flow should look like this:


Resources

Visit the Facebook developers site to download the Facebook SDK for iOS, as well as in-depth iOS samples and code snippets.