Custom Stories with Open Graph

Open Graph lets apps tell stories on Facebook through a structured, strongly typed API. When people engage with these stories they are directed to your app or, if they don't have your app installed, to your app's Play Store page, driving engagement and distribution for your app.
Stories have the following core components:
  • An actor: the person who publishes the story, the user.
  • An action the actor performs, for example: cookrun or read.
  • An object on which the action is performed: cook a meal, run a race, read a book.
  • An app: the app from which the story is posted, which is featured alongside the story.
We provide some built in objects and actions for frequent use cases, and you can also create custom actions and objects to fit your app.
Once posted to Facebook, Open Graph stories look like this:
In this document we will go through the steps that you need to follow to publish an Open Graph from your Android app using the Share Dialog or using API calls. In both cases you will have to go through steps 1 and 2:
  1. Setting up your app to use Open Graph
  2. Creating an Open Graph Story
Then you can choose how to post by following one of:

Setting up your app to use Open Graph

Set up your app's namespace

A namespace is required if you're going to be creating a custom Open Graph action for your app. To add a namespace, go to the app dashboard, select your app, click on ''Settings'' and add a unique qualifier in the Namespace field under Basic Info. The app settings page will tell you if your namespace is unique.

Enable deep linking

One of the most attractive features of sharing Open Graph stories from your app, is that when people engage with these stories they can be directed to your app or your app's Play Store page, driving engagement and new installs. This is done through the use of app links, in a process called deep linking.
We will cover how to implement deep linking later into this tutorial, for now enable it from the app dashboard on the ''Android'' section of your app's settings. To enable deep linking you will have to have enabled Login in the same interface first.

Creating an Open Graph Story

The next step is creating a custom Open Graph story (action + object combination) for your app.
In addition to allowing you to create your own custom story, Open Graph also provides somebuilt-in action types that work with built-in objects. If built-in types fit your use case you will not need to create a custom story, you can use these built-in objects directly.
In order to create a custom Open Graph story, in your app's dashboard, select ''Open Graph'' from the left-hand navigation and click on the ''Add Custom Story'' button. A story is comprised of a verb (action) and noun (object). Use the wizard to create custom action and object types. For example, ''eat a dish'':

Editing Open Graph types

Once you've created a story, you can further customize it by editing each type to add the attributes of your choice. Click on the "Action Types" tab at the top. You will see a page listing your objects and actions.
You can also see your objects by selecting the "Object Types" tab. Click on your "dish" object. You will see a page where you can configure your object type in a more detail, as well as a list of all of your object properties. Take note of this page, we will reference it later.
Go back to the "Action Types" tab for your app and click on your "eat" action. Again you will see a list of properties for your action and if you scroll to the bottom of the page you will also see a list of "Capabilities". For more information on what these capabilities do, consult our documentation. You can enable these capabilities as needed.

Posting with the Share Dialog

The Share dialog lets you build great, native sharing experiences for people using your app. It works by making a one-line call to the SDK that configures the content to share, does an app switch to the Facebook app, and returns to the app once people have shared.
Share Dialog is supported by version 3.5 and higher of the Facebook for Android app.
In order to share a custom story using the share dialog, you have to go through the following five steps:
  1. Setup the share dialog
  2. Publish the story
  3. Handling responses from the share dialog
  4. Using the Feed Dialog as fallback
  5. Linking posts back to your native app
When publishing your story (step 2), you have the following options:

Setup the share dialog

On Android, apps must use a UiLifecycleHelper to set a callback to handle the result of opening the Share Dialog. First, add a UiLifecycleHelper class level instance with:
private UiLifecycleHelper uiHelper;
Then configure the UiLifecycleHelper in onCreate with:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);
}
Next, configure a callback handler that's invoked when the Share dialog closes and control returns to the calling app:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    uiHelper.onActivityResult(requestCode, resultCode, data, new FacebookDialog.Callback() {
        @Override
        public void onError(FacebookDialog.PendingCall pendingCall, Exception error, Bundle data) {
            Log.e("Activity", String.format("Error: %s", error.toString()));
        }

        @Override
        public void onComplete(FacebookDialog.PendingCall pendingCall, Bundle data) {
            Log.i("Activity", "Success!");
        }
    });
}
Finally, configure other methods on uiHelper to handle Activity lifecycle callbacks correctly.
@Override
protected void onResume() {
    super.onResume();
    uiHelper.onResume();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

@Override
public void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
public void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}
Now your Activity is setup to use the Share dialog.
The Share dialog supports status updates, link shares and publishing Open Graph actions. Each type of sharing lets people tag friends and places and choose an audience.

Publish Open Graph actions

Open Graph is a great way for apps to share rich stories through structured content. Open Graph actions help people tell richer stories by giving apps more control over the story being told and the language used to express the story in the news feed. Using the Share dialog makes that easier than ever for people. The Share dialog lets apps publish Open Graph actions without using Facebook Login and without having to ask people for a publish permission (e.g. publish_actions).
Here are a few examples of how apps can use built-in or custom action types and share those actions using the SDK.
There are two types of Open Graph objects: app-owned and user-owned. App-owned objects are a good fit where all of the people using an app share the same objects. For example, all people using Spotify share the song/album/artist catalog. User-owned objects are a good fit for apps where people create and own the app's content, for example, photo or note sharing apps.
Apps can use the Share dialog to publish actions that point to either type of object.

Publish actions on app-owned objects

Say a book-reading app lets people share stories like "Eddie read a book." To do that, the app has an app-owned book library and uses <meta> tags to create books. The app shares stories about book reading using the following:
OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class);
action.setProperty("book", "https://example.com/book/Snow-Crash.html");

FacebookDialog shareDialog = new FacebookDialog.OpenGraphActionDialogBuilder(this, action, "books.reads", "book")
        .build();
uiHelper.trackPendingDialogCall(shareDialog.present());
This displays a Share dialog that looks like this:

Publish actions on user-owned objects

A cooking app lets people share content about meals they've cooked, and everyone owns their own meal-related content. To enable this, the app creates a user-owned meal object at the time of the share and connects to people with a cook action to tell a story like "Eddie cooked a meal." The app shares this using:
OpenGraphObject meal = OpenGraphObject.Factory.createForPost("cooking-app:meal");
meal.setProperty("title", "Buffalo Tacos");
meal.setProperty("image", "http://example.com/cooking-app/images/buffalo-tacos.png");
meal.setProperty("url", "https://example.com/cooking-app/meal/Buffalo-Tacos.html");
meal.setProperty("description", "Leaner than beef and great flavor.");

OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class);
action.setProperty("meal", meal);

FacebookDialog shareDialog = new FacebookDialog.OpenGraphActionDialogBuilder(this, action, "cooking-app:cook", "meal")
        .build();
uiHelper.trackPendingDialogCall(shareDialog.present());
This displays a Share dialog that looks like this:

Attach images to Open Graph actions and objects

Stories are better with pictures, and mobile devices are a great source of photos to attach to Open Graph actions and objects. For example, a "cooked a meal" story is better when people attach pictures from their phone's Gallery to the "cook" action.
Apps can always attach images that are web accessible using URLs. This section explains how to attach photos from the device to Open Graph actions and objects. Before attaching images on the device, apps must configure a ContentProvider from the SDK in the AndroidManifest.xml. Remember to substitute your {Facebook-app-id} in the XML snippet below:
<provider android:authorities="com.facebook.app.NativeAppCallContentProvider{Facebook-app-id}"
          android:name="com.facebook.NativeAppCallContentProvider" />

Attach images to an action

To attach pictures of a recipe to the "cook" action, an app should load images as a Bitmap and pass those to the Share dialog when it's opened. Example:
OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class);
action.setProperty("meal", "https://example.com/cooking-app/meal/Lamb-Vindaloo.html");

Bitmap bitmap = ... load an image ...; 
List<Bitmap> images = new ArrayList<Bitmap>();
images.add(bitmap);

FacebookDialog shareDialog = new FacebookDialog.OpenGraphActionDialogBuilder(this, action, "cooking-app:cook", "meal")
        .setImageAttachmentsForAction(images, true)
        .build();
uiHelper.trackPendingDialogCall(shareDialog.present());
The Share dialog will show a preview of the story and use Bitmap passed above in the story preview instead of using the object's image.
Note: if people took the images with a camera, the app can ask to enable the "User Generated Photos" capability on the action type in the App Dashboard. With this flag set to true (as above), the story will be displayed as an intentional photo share on News Feed and Timeline. If this flag is false, the default Open Graph story with a small image will be used on News Feed and Timeline.

Attach images to a user-owned object

In this scenario, people write recipes and share when they cook them. In Open Graph, this is modeled as a user-owned recipe object and a cook action. Share dialog can publish both at the same time as:
OpenGraphObject recipe = OpenGraphObject.Factory.createForPost("cooking-app:recipe");
recipe.setProperty("title", "Shrimp Curry");
recipe.setProperty("image", "https://example.com/cooking-app/meal/Shrimp-Curry.html");
recipe.setProperty("description", "...recipe text...");

Bitmap images = ... load image ...;
List<Bitmap> images = new ArrayList<Bitmap>();
images.add(bitmap1);

OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class);
action.setProperty("recipe", recipe);

FacebookDialog shareDialog = new FacebookDialog.OpenGraphActionDialogBuilder(this, action, "fbsdktoolkit:climb", "route")
    .setImageAttachmentsForObject("recipe", images, true)
    .build();
uiHelper.trackPendingDialogCall(shareDialog.present());

Tag people and places

To tag friends, apps can pass Facebook user IDs when sharing an action. For example:
GraphUser user = GraphObject.Factory.create(GraphUser.class);
user.setId("{friend-id-1}");

List<GraphUser> tags = new ArrayList<GraphUser>();
tags.add(user1);

action.setTags(tags);
To tag a place, pass a Facebook Place ID. Apps can read Facebook place IDs from the Places Search API - for example to find places around the current location. Apps can also use the Place Picker to choose places.
To add the place to an action:
GraphPlace place = GraphObject.Factory.create(GraphPlace.class);
place.setId("141887372509674"); // Facebook Seattle
action.setPlace(place);
An action with people and place tags looks like:

Handling responses from Share dialog

After the Share dialog completes, control returns to the app and the SDK calls onActivityResult with the results of the share. Your app can handle the response by adding a FacebookDialog.Callbackto the activity's UiHelper. See Setup for an example.
In the callback's handlers, the following parameters are available:
NameCode to readTypeNotes
Did completeFacebookDialog.getNativeDialogDidCompletebooleanAlways available.true if the dialog completed successfully; falseif the dialog completed with an error.
Completion gestureFacebookDialog.getNativeDialogCompletionGestureStringOnly available if the user logged into your app using Facebook and did complete is true. Value is either postor cancel.
Post IDFacebookDialog.getNativeDialogPostIdStringOnly available if the user is logged into your app using Facebook, has granted a publish permission (e.g.publish_actions), and the user chose to share the story. If present, this is the ID of the published story.
Read these fields using static methods on FacebookDialog:
boolean didCancel = FacebookDialog.getNativeDialogDidComplete(data);
String completionGesture = FacebookDialog.getNativeDialogCompletionGesture(data);
String postId = FacebookDialog.getNativeDialogPostId(data);
If the Share Dialog returned with an error, check the error passed to the Share Dialog handler.

Using the Feed Dialog as fallback

The Share dialog can't be displayed if people don't have the Facebook app installed. Use:
if (FacebookDialog.canPresentOpenGraphActionDialog(getApplicationContext(),
                                                   FacebookDialog.OpenGraphActionDialogFeature.OG_ACTION_DIALOG)) {
    OpenGraphAction action = GraphObject.Factory.create(OpenGraphAction.class);
    action.setProperty("book", "https://example.com/book/Snow-Crash.html");

    FacebookDialog shareDialog = new FacebookDialog.OpenGraphActionDialogBuilder(this, action, "books.reads", "book")
            .build();
    uiHelper.trackPendingDialogCall(shareDialog.present());
}
Based on the value of canPresent, apps may disable or hide a sharing button or fall back to the Feed dialog to share on the web. See the HelloFacebookSample included with the SDK for an example.
Note: The Feed dialog doesn't support sharing Open Graph actions. In those cases, apps should do a link share via Feed dialog.

Troubleshooting:

Can I test the Share dialog on an Android emulator?

Yes - a .apk of the Facebook app is included in the SDK download package. To install it, run:
$> adb install ~/facebook-android-sdk-3.5/bin/FBAndroid-{version}.apk

What happens if something goes wrong?

Apps should handle errors that might happen when people share content.

Share dialog fails when attaching errors, what's wrong?

If you're marking images as user_generated, make sure: + make sure images are at least 480 pixels in both dimensions + images from he app are loaded from the drawable/ directory. Loading them from the resolution-specific sub-directories can cause Android to downsize them below the 480x480 minimum size.

My app isn't getting callbacks on success / failure, what's wrong?

Make sure you're using a UiHelper instance as described in the Setup instructions.

Additional resources

See these documents for more information about using Share dialog:

API reference

Samples

Several samples included with the SDK download demonstrate the Share dialog:
  • HelloFacebookSample: shows basic usage of the Share dialog
  • RPSSample: game sample that includes sharing Open Graph actions using Share dialog
On OS X: the samples are in ~/Documents/facebook-android-sdk-{version}/samples.
On Windows: the samples are in %HOMEPATH%\facebook-android-sdk-{version}\samples.

Posting using API calls

The Facebook SDK for Android provides methods you can use to create Open Graph objects using theObject API. Once you create these objects, you can use the Facebook SDK to share Open Graph stories on Facebook.
The Request class in the Facebook SDK is used to create Open Graph objects and to publish stories with these objects. There are two types of objects you can create: user-owned objects and app-owned objects. Creating an app-owned object requires an app access token. These objects should be created outside your app to avoid embedding your app access token inside your app. You can use the Object Browser or follow the steps in the Using Object API doc to create app-owned objects. This document showcases the use of the Facebook SDK to create user-owned objects.
Creating an object and publishing a story require that people using your app grant it permission to write to their account. Your app should ensure that people using it have granted publish_actionspermissions and, if they have not, pass them through a new permissions request flow in context, for example when they try to share a story.
This document walks through the following topics:

Prerequisites

Get the initial sample app

The starter code for this doc can be found on GitHub. If you haven't done so, clone the how-to samples for the Facebook SDK:
git clone https://github.com/fbsamples/android-3.0-howtos.git
Then, import the Android project found under the ObjectAPIHowTo/Initial folder.

Set up a Facebook app

You'll also need to use your own Facebook app to publish the Open Graph actions. Follow these steps:
  • Create a Facebook app in the App Dashboard or use an existing app you own.
  • Go to your app's Basic settings page.
  • Edit the Basic Info section:
    • App Domains: Enter an app domain for a domain you own, ex: example.com.
  • Edit the Website with Facebook Login section:
    • Site URL: Enter a website URL, ex: http://www.example.com. Note, this does not have to be a working URL for this sample. The website URL does have to exist in the domain you defined earlier.
  • Edit the Native Android App section:
    • Key Hashes: Enter your app signature or key hash. If you don't have it yet, get your key hash.
    • Facebook Login: Enable this setting.

Configure the Facebook settings in the app

Open up the Android project and configure it to use your Facebook app ID. Edit theres/values/strings.xml file and modify the app_id parameter:
<string name="app_id">497048500343780</string>
Replace the value with your app ID.
If you wish to check out the completed sample, make the same modifications to that project after importing it. If you get any errors sharing a story, try turning off the explicitly shared feature in the completed sample. To do this, edit MainFragment.java and comment out this line:
readAction.setExplicitlyShared(true);

Sample Overview

The completed sample lets people log in with Facebook and share an Open Graph story on their timeline. In this sample the story shared is that a person has ''read a book''. The story is told using thecommon read action and the common book object.

UI features

The app displays a book as well as a Share button that's visible if people are logged in. When people tap the Share button, a successful post displays a story ID and the story is published to their timeline:

Overview of initial code

The initial Android project has Facebook Login implemented and includes logic to handle thepublish_actions permission request. The project includes all the UI components you'll need for the sample. What's missing is Facebook functionality that you'll add to implement Open Graph sharing.
The main classes in the projects are:
  • MainActivity: The main Activity for that project that hosts the main Fragment
  • MainFragmentFragment hosted by MainActivity that contains logic to authenticate the user handle incoming new permission requests. The fragment's layout (res/layout/main.xml) contains the UI for the Facebook Login button, the sample book image, and the Share button. The Share button is hidden in the layout and session state logic in the fragment is used to make the button visible when people log in.

Step 1: Create an object instance

In this step, you'll add logic that uses the Object API to create a new instance of a book on Facebook.
Open up the MainFragment class file. It contains an empty publishStory() method where you'll be making your changes.
To create an object and publish an action, you'll need to request new permissions, namely thepublish_actions permissions. Add the following code to the publishStory() method to check if your app has the required permissions and if not, to trigger a new permissions request:
Session session = Session.getActiveSession();
if (session != null) {
    // Check for publish permissions
    List<String> permissions = session.getPermissions();
    if (!isSubsetOf(PERMISSIONS, permissions)) {
        pendingPublishReauthorization = true;
        Session.NewPermissionsRequest newPermissionsRequest = new Session
            .NewPermissionsRequest(this, PERMISSIONS);
        session.requestNewPublishPermissions(newPermissionsRequest);
    }
    return;
}
After the permissions check code, add logic to the method to create a batch request then add a request to the batch for the object creation:
// Show a progress dialog because the batch request could take a while.
progressDialog = ProgressDialog.show(getActivity(), "",
        getActivity().getResources().getString(R.string.progress_dialog_text), true);

// Create a batch request
RequestBatch requestBatch = new RequestBatch();

// Request: Object request
// --------------------------------------------

// Set up the OpenGraphObject representing the book.
OpenGraphObject book = OpenGraphObject.Factory.createForPost("books.book");

String imageUrl = "https://furious-mist-4378.herokuapp.com/books/a_game_of_thrones.png";
book.setImageUrls(Arrays.asList(imageUrl));
book.setTitle("A Game of Thrones");
book.setUrl("https://YOUR_APP_DOMAIN/books/a_game_of_thrones/");
book.setDescription("In the frozen wastes to the north of Winterfell, sinister and supernatural forces are mustering.");
// books.book-specific properties go under "data"
book.getData().setProperty("isbn", "0-553-57340-3");

// Set up the object request callback
Request.Callback objectCallback = new Request.Callback() {

    @Override
    public void onCompleted(Response response) {
        // Log any response error
        FacebookRequestError error = response.getError();
        if (error != null) {
            dismissProgressDialog();
            Log.i(TAG, error.getErrorMessage());
        }
    }
};

// Create the request for object creation
Request objectRequest = Request.newPostOpenGraphObjectRequest(Session.getActiveSession(),
        book, objectCallback);

// Set the batch name so you can refer to the result
// in the follow-on publish action request
objectRequest.setBatchEntryName("objectCreate");

// Add the request to the batch
requestBatch.add(objectRequest);

// TO DO: Add the publish action request to the batch

// Execute the batch request
requestBatch.executeAsync();
Replace YOUR_APP_DOMAIN with the app domain you've specified in your Facebook app's basic settings.
The code first sets up a ProgressDialog that displays text while the request is taking place. A newRequestBatch object is then created and an OpenGraphObject representation of a book object is set up with the desired parameters.
One of the parameters is a URL for the book. This URL doesn't need to exist and may only be used in the context of handling deep links back to the app. In your real world app, you'd want this to be a valid link if you have mobile web or desktop versions of your app.
Once the book object is set up, a Request instance is created to post it to theme/objects/books.book endpoint (determined automatically based on the object's type). This request is given a name: ''objectCreate'', for use in the batched request. This request is then added to the request batch and the batch executed. You'll be adding a second request to the batch in the next step.

Step 2: Publish the story

In this step, you'll publish the Open Graph action using the Open Graph object instance created in the previous step.
In the publishStory() method, look for the following placeholder comment:
// TO DO: Add the publish action request to the batch
Add the publish action code at that point:
// Request: Publish action request
// --------------------------------------------
OpenGraphAction readAction = OpenGraphAction.Factory.createForPost("books.reads");
// Refer to the "id" in the result from the previous batch request
readAction.setProperty("book", "{result=objectCreate:$.id}");

// Set up the action request callback
Request.Callback actionCallback = new Request.Callback() {

    @Override
    public void onCompleted(Response response) {
        dismissProgressDialog();
        FacebookRequestError error = response.getError();
        if (error != null) {
            Toast.makeText(getActivity()
                .getApplicationContext(),
                error.getErrorMessage(),
                Toast.LENGTH_LONG).show();
        } else {
            String actionId = null;
            try {
                JSONObject graphResponse = response
                .getGraphObject()
                .getInnerJSONObject();
                actionId = graphResponse.getString("id");
            } catch (JSONException e) {
                Log.i(TAG,
                        "JSON error "+ e.getMessage());
            }
            Toast.makeText(getActivity()
                .getApplicationContext(),
                actionId,
                Toast.LENGTH_LONG).show();
        }
    }
};

// Create the publish action request
Request actionRequest = Request.newPostOpenGraphActionRequest(Session.getActiveSession(),
        readAction, actionCallback);

// Add the request to the batch
requestBatch.add(actionRequest);
The code sets up an OpenGraphAction object that represents a books.reads action with a bookparameter. The parameter's value is set to the id value from a successful object creation request. The object creation request is identified by the ''objectCreate'' name. The code then sets up aRequest.Callback to handle the publish action request. A successful post returns an action ID that's displayed in a Toast. Errors are also displayed back to the user as a Toast. A Request instance is then created that sets up a post to the me/books.reads Graph API endpoint (again determined automatically from the action's type), with the action info. This request is then added to the request batch and the batch executed.
Build and run the project to make sure it runs without errors. Tap the ''Log In'' button to log in with Facebook. Once authenticated, tap ''Share'' to post the book read story. Verify that you see a message with the posted story ID. Check your Activity Log to verify the object was created and the action published.
Check the Object Browser and select your app from the App drop-down. Then select your name from the Owner drop-down, and "book" from the Type drop-down. This should display the newly created book object:

Step 3: Upload an image for the object

In this step, you'll make use of Facebook staging resources to upload an image representing the object and then attach the image to the object during the object creation step.
The way it's set up in the completed sample, you'll optionally upload an image or use a pre-existing image that's available via a URL. So far, the sample has been using the pre-existing image URL.
First, add a private constant to turn on the feature that uploads an image when the object is created:
static final boolean UPLOAD_IMAGE = true;
Then, if the UPLOAD_IMAGE flag is enabled, set up the image upload request as the first request in the batch request:
...
RequestBatch requestBatch = new RequestBatch();

// Request: Staging image upload request
// --------------------------------------------

// If uploading an image, set up the first batch request
// to do this.
if (UPLOAD_IMAGE) {
    // Set up image upload request parameters
    Bundle imageParams = new Bundle();
    Bitmap image = BitmapFactory.decodeResource(this.getResources(),
            R.drawable.a_game_of_thrones);

    // Set up the image upload request callback
    Request.Callback imageCallback = new Request.Callback() {

        @Override
        public void onCompleted(Response response) {
            // Log any response error
            FacebookRequestError error = response.getError();
            if (error != null) {
                dismissProgressDialog();
                Log.i(TAG, error.getErrorMessage());
            }
        }
    };

    // Create the request for the image upload
    Request imageRequest = Request.newUploadStagingResourceWithImageRequest(Session.getActiveSession(),
    image, imageCallback);

    // Set the batch name so you can refer to the result
    // in the follow-on object creation request
    imageRequest.setBatchEntryName("imageUpload");

    // Add the request to the batch
    requestBatch.add(imageRequest);
}
...   
The code obtains a Bitmap representation of a book image that's included in the project, then creates a Request to post that image to the me/staging_resources Graph API endpoint. The image upload request is identified by the ''imageUpload'' name. The code sets up a Request.Callback to log any errors that occur during the request. This request is then added to the request batch.
Then, when setting up the book's image property use the result from the image upload request if that flow is enabled:
...
OpenGraphObject book = OpenGraphObject.Factory.createForPost("books.book");

// Set up the book image; if we uploaded the image, it is the "uri" result from the previous
// batch request, otherwise it is just a URL.
String imageUrl = UPLOAD_IMAGE ? "{result=imageUpload:$.uri}" :
        "https://furious-mist-4378.herokuapp.com/books/a_game_of_thrones.png";
book.setImageUrls(Arrays.asList(imageUrl));
...
Build and run the project to make sure it runs without errors. Once authenticated, tap Share to post the book read story. After the story is successfully posted, check your timeline to verify that the story shows up there.

Step 4: Turn on explicit sharing

The app's published stories currently only show up in the Activity Log. As these stories are being explicitly shared with the knowledge of people using your app, you can enable explicit sharing to ensure that the stories show up on the timeline. This capability is added in the App Dashboard by editing theRead action type that's created automatically when the first action is published:
Click the Read link to edit this action type. In the Capabilities section, turn on the ''Explicitly Shared'' flag and save your changes:
Now, in your Android project, edit the publishStory() method to set the action'sfb:explicitly_shared parameter to true:
....
readAction.setProperty("book", "{result=objectCreate:$.id}");
// Turn on the explicit share flag
readAction.setExplicitlyShared(true);
...
Build and run the project to make sure it runs without errors. Once authenticated, tap Share to post the book read story. After the story is successfully posted, check your timeline to verify that the story shows up there.
To use the explicitly shared capability in your app, make sure you comply with the guidelinesto ensure your action is approved during the submission process.

Troubleshooting

When adding the Facebook SDK as a library to your project, you may get a Jar mismatch related to theandroid-support-v4.jar file. You can handle this by using the Android SDK Manager to update both versions of this file to the latest release, or sync the files by copying (not moving) one project's version of the support library into the other project's libs folder.
You may also add the following code before making any requests to get a debug log of the request and help debug any issues you're facing:
Settings.addLoggingBehavior(LoggingBehavior.REQUESTS);

Additional resources

Was this document helpful?