The Facebook SDK for iOS provides hooks into the iOS6 share sheet so your app can use a share sheet if the user has an iOS 6+ device. You can provide a fallback for older OS devices by using the Feed Dialog or the Graph API's me/feed
endpoint to publish a story.
The Facebook SDK's FBDialogs
class has convenience class methods that start with presentOSIntegratedShareDialogModallyFrom:*
that you can use to show the share sheet if it's supported. These methods return YES if the share sheet is supported and the user signed into Facebook on the device.
This document walks through the following:
Note: To see an example of making the API call with the SDK, skip to the Publish the Story section.
Before you begin, make sure you already set up Facebook Login. This ensures you have the prerequisites and your app is ready for additional Facebook integration.
The completed sample allows users to log in with Facebook and publish a link on their timeline with the share sheet if it's supported or a fallback share user interface that publishes using the Graph API.
The implementation builds on top of Facebook Login, adding a button that either opens up the share sheet or a view where the user can share a predefined link. The share view shows a preview of the link image and a text field where the user can enter an optional message. When the user taps on the share button, a story is published to their timeline and an alert pops up with the story's ID.
Flow with iOS share sheet:
Flow with fallback share view:
The sample contains a main view controller that displays the initial view. You'll add a second view controller for the fallback share preview. The share view controller is presented modally. When the user taps a share button, the story is published in the share view controller. Then, a confirmation alert displays. When the user dismisses the alert, the share view controller closes.
In this step, you'll add a button in the initial view controller. When the user clicks the button, either the share sheet or the share view displays.
Make the following changes in your main view controller's nib file:
Round Rect Button
object to the view. Set the button title to ''Publish''.When you've completed these steps, your implementation file should have the defined outlet and an empty publishButtonAction:
action method.
If you followed the Facebook Login doc, you should have a sessionStateChanged:
method defined in your view controller implementation file that controls the logged-in and logged-out UI. Modify this method to show the publish button only when the user is authenticated:
- (void)sessionStateChanged:(NSNotification*)notification { if (FBSession.activeSession.isOpen) { self.publishButton.hidden = NO; [self.authButton setTitle:@"Logout" forState:UIControlStateNormal]; } else { self.publishButton.hidden = YES; [self.authButton setTitle:@"Login" forState:UIControlStateNormal]; } }
This step sets up the share preview display. The story information is hardcoded for simplicity. At the end of this step, the display can be linked to the main view controller. You'll set up publishing in a later step.
First, add a new view controller for the share view display. From the Xcode File menu select New > File, select the Objective-C class template, name the class ShareViewController
, make it a subclass of UIViewController
and select the ''With XIB for user interface'' option.
Open up the ShareViewController
nib file and add the UI components for the story preview and post. You'll add components for the published story's image and a text input field for a user message. Finally, you'll add a toolbar with two buttons, one to cancel and a second to publish the story.
Before you add the UI components, select the nib, then File Inspector, and then turn off ''Use Autolayout''.
Toolbar:
Toolbar
object to the top of the view. In the size inspector, anchor the toolbar to the top of the view by adjusting the Autosizing struts.Bar Button Item
object represents the cancel button. Set the title to ''Cancel''.Flexible Space Bar Button Item
object to the toolbar and place it to the right of the ''Cancel'' button. This ensures the button you add next appears on the right of the toolbar.Bar Button Item
object to the toolbar and place it to the right of the space button. This represents the post button. Set the title to ''Post''.Message:
Text View
object to the view below the toolbar. Stretch it out to take up most of the view's width.Image:
Image View
object to the view to the right of the ''Message'' text view.Aspect Fit
.When you've added the UI components, you're nib should look like this:
In this step, you'll add logic to control the message UI. The message UI is implemented with a UITextView
. You'll add logic to show the placeholder text when appropriate. You'll also add logic to dismiss the text input whenever the user taps outside the input field.
Open up the ShareViewController
implementation file and list UITextViewDelegate
as one of the protocols the class conforms to, so you can respond when the user starts or stops editing text:
@interface ShareViewController ()
<UITextViewDelegate>
Next, define a constant string for the placeholder text by adding the following code before the class interface declaration:
NSString *const kPlaceholderPostMessage = @"Say something about this...";
Next, add a private helper method, which you'll use to set the placeholder message:
- (void)resetPostMessage { self.postMessageTextView.text = kPlaceholderPostMessage; self.postMessageTextView.textColor = [UIColor lightGrayColor]; }
Then, implement UITextViewDelegate
methods that handle text input editing changes. You'll clear the placeholder text whenever editing begins. You'll set the placeholder text when editing is done and the input text is empty:
- (void)textViewDidBeginEditing:(UITextView *)textView { // Clear the message text when the user starts editing if ([textView.text isEqualToString:kPlaceholderPostMessage]) { textView.text = @""; textView.textColor = [UIColor blackColor]; } } - (void)textViewDidEndEditing:(UITextView *)textView { // Reset to placeholder text if the user is done // editing and no message has been entered. if ([textView.text isEqualToString:@""]) { [self resetPostMessage]; } }
Next, add logic to detect if a user taps outside the text view and close the keyboard:
/* * A simple way to dismiss the message text view: * whenever the user clicks outside the view. */ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *) event { UITouch *touch = [[event allTouches] anyObject]; if ([self.postMessageTextView isFirstResponder] && (self.postMessageTextView != touch.view)) { [self.postMessageTextView resignFirstResponder]; } }
In this step, you'll configure the information displayed in the share preview. You'll define a new property that holds this data in an NSMutableDictionary
object. You'll use the same property later on when making the API call to publish the story.
First, define the new property to hold the display data:
@property (strong, nonatomic) NSMutableDictionary *postParams;
Synthesize this new property:
@synthesize postParams = _postParams;
Set the display data value in the view controller's initWithNibName:bundle:
method by adding the following code to the custom initialization section:
self.postParams = [[NSMutableDictionary alloc] initWithObjectsAndKeys: @"https://developers.facebook.com/ios", @"link", @"https://raw.github.com/fbsamples/ios-3.x-howtos/master/Images/iossdk_logo.png", @"picture", nil];
Pass the display data to the share view UI components by adding this code to the end of the viewDidLoad
method:
// Show placeholder text [self resetPostMessage]; // Set the preview image self.postImageView.image = [UIImage imageNamed:@"iossdk_logo.png"];
In this step, you'll implement the cancel action.
First, fill out the cancelButtonAction:
method to dismiss the share view when the user taps the ''Cancel'' button:
- (IBAction)cancelButtonAction:(id)sender { [[self presentingViewController] dismissModalViewControllerAnimated:YES]; }
In this step, you'll set up the logic that presents the share sheet or the fallback share view if the share sheet cannot be shown. You can publish the story using the share sheet. You'll add logic for the fallback story publish in the next step.
Open the main view controller and import the ShareViewController
class, so you can initialize and present it:
#import "ShareViewController.h"
Next, fill out the publishButtonAction:
implementation to first try and show the share sheet and if that is not successful it initializes and presents the share view controller:
- (IBAction)publishButtonAction:(id)sender { // First check if we can use the native dialog, otherwise will // use our own BOOL displayedNativeDialog = [FBDialogs presentOSIntegratedShareDialogModallyFrom:self initialText:@"" image:[UIImage imageNamed:@"iossdk_logo.png"] url:[NSURL URLWithString:@"https://developers.facebook.com/ios"] handler:^(FBOSIntegratedShareDialogResult result, NSError *error) { // Only show the error if it is not due to the dialog // not being supporte, i.e. code = 7, otherwise ignore // because our fallback will show the share view controller. if (error && [error code] == 7) { return; } NSString *alertText = @""; if (error) { alertText = [NSString stringWithFormat: @"error: domain = %@, code = %d", error.domain, error.code]; } else if (result == FBNativeDialogResultSucceeded) { alertText = @"Posted successfully."; } if (![alertText isEqualToString:@""]) { // Show the result in an alert [[[UIAlertView alloc] initWithTitle:@"Result" message:alertText delegate:self cancelButtonTitle:@"OK!" otherButtonTitles:nil] show]; } }]; // Fallback, show the view controller that will post using me/feed if (!displayedNativeDialog) { ShareViewController *viewController = [[ShareViewController alloc] initWithNibName:@"ShareViewController" bundle:nil]; [self presentViewController:viewController animated:YES completion:nil]; } }
Build and run the project on an iOS6 simulator or device so you can exercise the iOS share sheet. Make sure it runs without errors. Once authenticated, tap ''Publish'' and verify that the share sheet is shown. You must be signed into Facebook on the device for this flow to work. Enter an additional message and click the post button. Check your timeline to verify that the story is published correctly.
Build and run the project on an iOS5 simulator or device so you can exercise the fallback flow. Make sure it runs without errors. Once authenticated, tap ''Publish'' and verify that the share preview UI looks good. Make any necessary adjustments to the UI components. Test that the message input placeholder text is shown and cleared correctly. Tap outside the message to make sure the keyboard closes. Finally, verify that tapping the cancel button dismisses the share view.
In this final step, you'll add logic to publish the story using the fallback method. Before publishing the story you'll check if the user had previously granted you publish_actions
permissions and if not, you'll request this permission.
Open up the ShareViewController
implementation file and import the Facebook SDK so you can make the publish request:
#import <FacebookSDK/FacebookSDK.h>
Next, add a helper method to publish the story:
- (void)publishStory { [FBRequestConnection startWithGraphPath:@"me/feed" parameters:self.postParams HTTPMethod:@"POST" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) { NSString *alertText; if (error) { alertText = [NSString stringWithFormat: @"error: domain = %@, code = %d", error.domain, error.code]; } else { alertText = @"Posted successfully."; } // Show the result in an alert [[[UIAlertView alloc] initWithTitle:@"Result" message:alertText delegate:self cancelButtonTitle:@"OK!" otherButtonTitles:nil] show]; }]; }
Next, fill out the postButtonAction:
method to ask for publish the story after checking if you have publish_actions
permissions for the user on this device:
- (IBAction)postButtonAction:(id)sender { // Hide keyboard if showing when button clicked if ([self.postMessageTextView isFirstResponder]) { [self.postMessageTextView resignFirstResponder]; } // Add user message parameter if user filled it in if (![self.postMessageTextView.text isEqualToString:kPlaceholderPostMessage] && ![self.postMessageTextView.text isEqualToString:@""]) { [self.postParams setObject:self.postMessageTextView.text forKey:@"message"]; } // Ask for publish_actions permissions in context if ([FBSession.activeSession.permissions indexOfObject:@"publish_actions"] == NSNotFound) { // No permissions found in session, ask for it [FBSession.activeSession requestNewPublishPermissions: [NSArray arrayWithObject:@"publish_actions"] defaultAudience:FBSessionDefaultAudienceFriends completionHandler:^(FBSession *session, NSError *error) { if (!error) { // If permissions granted, publish the story [self publishStory]; } }]; } else { // If permissions present, publish the story [self publishStory]; } }
An alert appears after the story is published whether the request succeeds or fails. When the alert is dismissed, dismiss the share view controller. To respond to the alert, first add UIAlertViewDelegate
to the list of protocols the ShareViewController
class conforms to.
Next, implement the UIAlertView
delegate method that is notified when the alert is dismissed, and then dismiss the share view:
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { [[self presentingViewController] dismissModalViewControllerAnimated:YES]; }
Build and run the project on an iOS5 simulator or device so you can exercise the fallback flow. Make sure it runs without errors. Once authenticated, tap ''Publish''. Then, on the share view, enter a message and tap ''Post''. You should see the permissions dialog asking for publish permissions. If you allow publish permissions, you should see an alert confirming that the story published. Check your timeline to verify the story published correctly.
Test the fallback share on iOS6 for the scenario where you are not signed into Facebook on the device. You shouldn't see the share sheet for this test.
The Graph API Explorer provides a way for you to debug any Graph API issues. If you're having problems publishing a story, try using the Graph API Explorer, as it may give you more error into and help you out.
HelloFacebookSample
: sample in the SDK that shows how to use the native dialog and fallback to a Graph API call