Digital Developer Conference: Cloud Security 2021 -- Build the skills to secure your cloud and data Register free

Archived | Introduction to the Facebook SDK for Android

Archived content

Archive date: 2021-11-18

This content is no longer being updated or maintained. The content is provided “as is.” Given the rapid evolution of technology, some content, steps, or illustrations may have changed.

In this tutorial, I give you an overview of the Facebook SDK for Android, and show you how to integrate it into your app and how to use the Login, Graph, and Share APIs, which are commonly used in mobile apps. The tutorial covers how to set up the application with Facebook, permissions, application development modes, and test users, and then shows you a sample app and code.

Prerequisites

To follow along with this tutorial, you need the following skills and tools:

  • Basic knowledge of Java technology
  • Basic knowledge of Android
  • Java Development Kit (version 10.0.1, as of this writing)
  • Android Studio (version 3.2.1, as of this writing)

Register and set up your application with Facebook

Before you begin, you need to register your app with Facebook. The process of registering an application with Facebook and setting up the application is as follows:

Typical steps for new apps

During application registration, the application is added, the app ID created, and the app settings properly defined and configured. This includes updating the Android string resource file with app ID information and setting the roles and test users for app testing.

Add new app

To register your application, go to Facebook’s developer website and click on Add New App.

Register the app with Facebook

Next, create the new app’s ID.

Create app ID

In the Create a New App ID dialog, enter a Display Name and Contact Email for your application.

Create a new app ID

Pressing the Create App ID button will generate the app ID and take you to the application’s dashboard.

The app dashboard

On the top left of the Dashboard you will find a drop-down to navigate across your different apps, and next to it you will see the assigned App ID. The application ID and associated secret key (clientSecret) are used in your application when making the different Facebook API calls.

You can view and manage the application development status, view the app’s analytics, manage the app’s basic and advanced settings, manage roles and test users, manage the app review process, and manage the Facebook products used by the app.

App dashboard

You can press Skip and go directly to the Basic and Advanced settings. In the Basic settings, press Add Platform to add your Android app and your related website, as illustrated here:

Add platform

Then enter the requested information:

Add platform - details

On the Basic settings page, enter the Google Play Package name, the Default Activity Class Name, and the key hashes for the app, as well as any other settings like enabling single sign-on (SSO) and deep linking.

Keyhashes and single sign-on

Keyhashes are required to authenticate the exchange of information between your app and Facebook. Without a keyhash, the Facebook integration may not work properly once you put your app in the store.

You can enable SSO for your app. SSO is a way to login and authorize the user by delegating authentication to the official Facebook native app, if it has been installed in the handset. If the user is already authenticated with the Facebook native app, they won’t be prompted for a username or password on your app. If SSO is enabled but the Facebook native app is not installed, or if SSO is not enabled, then authentication defaults to the OAuth-based Webview Facebook screen interfaces and flows. Note that in this tutorial I only cover the Webview screens, but it is a good idea to enable SSO to make it easier for the user to login, if the Facebook native app is installed.

To enable SSO, you need to specify the app’s keyhash (debug or release as appropriate) and turn on SSO in the app settings, as illustrated above.

To create the app’s keyhash, use the keytool command line as follows (note that these examples are for MacOS):

Debug mode:

 keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

Release mode:

keytool -exportcert -alias YOUR_RELEASE_KEY_ALIAS -keystore YOUR_RELEASE_KEY_PATH | openssl sha1 -binary | openssl base64

Next, enter the generated keyhash value in the Key Hashes field.

App modes and test users

As with any software that you write, there are development and testing phases, and there is going live. In Facebook, when you register your application, it starts in Development Mode by default. This mode keeps the app visible only to you (hidden from the App Center), and the app is automatically approved for all login permissions and features requested so that you can test your application. Once you are ready to test your application and integrations with Facebook, you can use Test Users for your end-to-end testing. Test Users are not actual Facebook users and are a great way to test your app end-to-end.

You can create test users directly within the app dashboard in the Roles tab. Click on the Add button in the upper right.

Test users

You can add more test users, edit test users’ information and permissions, set expiration times, and more as needed. (See Test Users in the docs for more information.)

Once you are ready to release the app, just toggle the app Status on the top of the app Dashboard. If your app is using permissions or features that require app review, you must submit your app for app review before making your app public.

For more information, see the Facebook page on Managing Development Cycles.

Understanding access tokens and permissions

Facebook uses access tokens to validate and authenticate the client and control the access to the Facebook platform services and resources.

Facebook defines the following types of access tokens:

  1. User Access
  2. App Access
  3. Page Access
  4. Client Tokens

In this tutorial, I only cover the User Access token. Facebook APIs that read, modify, or write user data require that a User Access token be specified.

You can read more about the different kinds of access tokens by visiting Facebook’s Access Tokens page.

In the SDK, access tokens are represented by the AccessToken class, which represents an immutable access token for using Facebook APIs, and includes associated metadata such as expiration date and permissions. You can test if there is an active token by calling AccessToken.isCurrentAccessTokenActive().

A typical login sequence is illustrated below. In this sequence, a user decides to login and grants permissions. Next, the app/SDK passes the access request and permissions to Facebook. Once a user is authenticated and the permissions are granted, the app receives a User Access Token that gives temporary access to Facebook APIs and user data. The default expiration period for data access is 90 days.

Login sequence

Requesting and granting permissions gives the application access to user data or to operations such as sharing or updating basic information, or the friend’s list. You can see the current access tokens associated with your account by visiting the Access Token page.

Applications should be mindful of the types and amounts of permissions the app requests from the user. A minimalistic approach to permissions reduces user hesitation when installing the app, helping with app adoption. Requesting certain permissions requires app review before you can make your app public. The only permissions that do not require app review are the basic profile (the user’s Facebook ID, first name, last name, middle name, picture, and short name) and the user’s email address.

All other permissions can result in app review by Facebook before the app can go public. For more information see Facebook’s App Review process.

For information about all the permissions associated with the Facebook login, see Facebook’s Permissions Reference.

Overview of the Facebook SDK for Android

The Facebook SDK for Android consists of Java programming language on top of Facebook platform REST APIs. The SDK is open source, and it is hosted at GitHub’s facebook / facebook-android-sdk repository. Note that due to the evolving nature of the Facebook API and the open source SDK, you can expect future changes that might require application updates.

The Facebook SDK for Android consists of a number of related SDKs that all together provide the collection of APIs to build social apps across Android, iOS, React Native, and other platforms. The Facebook SDK for Android consists of 7 related SDKs as illustrated here:

Components of the Facebook SDK for Android

As a developer, you can include the complete set of SDKs or just individual SDKs as needed. Including only the SDKs that your app needs is a simple way of managing the overall app size. The following table describes each SDK in more detail including a link to the related official documentation.

Table 1. Components of the Facebook SDK for Android

Component Description Documentation
Core APIs Core APIs including Graph, App Events, Analytic APIs. Graph API, Facebook Analytics, App Events
Login API to login using Facebook and request app permissions. The Facebook Login SDK
Share API to share or send a messages. The Facebook Sharing SDK
Places API to search for places, place discovery, location sharing, and geo-tagging. The Facebook Places SDK
Messenger API to share both links and media from your apps to Messenger, and enable bot chat extentions. The Facebook Messenger SDK
App Links API to deep link to content within the mobile app. The Facebook App Links SDK

Visit the Facebook SDK for Android documentation page for the complete, official documentation.

In addition to the SDKs listed above, Facebook also provides other SDKs such as the Account Kit SDK which enables login using a phone number or email address without requiring a password, and an Audience Network SDK for audience-centric, targeted, and rich adversiting.

This tutorial only covers the following SDKs and functionality:

  1. Login API
  2. Graph API
  3. Sharing API

Integrating the Android SDK

To integrate the Android SDK, you can download the open source SDK from GitHub, or you can download the SDK’s Android Archive Library (aar) libraries from the Facebook Android SDK direct downloads page. However, the prefered way is to use Gradle’s dependency management using Maven Central or JCenter repository. Add the repository to the project’s Gradle file, and the dependencies to the app’s Gradle file.

  1. Add to the project’s Gradle file either Maven Central or JCenter as the SDK repository:

    Listing 1. Add the repository (Project Gradle file)

    repositories {
      // You can use mavenCentral() or jcenter()
      mavenCentral() 
    }
    
  2. Next, add the appropriate dependencies to the app Gradle file at /app/build.gradle. Recall that you can either include only the components that your app needs, or you can include the whole SDK.

    Listing 2. Add the whole Android SDK dependencies (App Gradle file)

    dependencies { 
      // Facebook Android SDK (everything)
      compile 'com.facebook.android:facebook-android-sdk:4.+'
    }
    

    Or, include the individual SDKs, as follows:

    Listing 3. Add the individual dependencies (App Gradle file)

    dependencies { 
      // Facebook SDK Core only (Analytics)
      compile 'com.facebook.android:facebook-core:4.+'
      // Facebook Login only
      compile 'com.facebook.android:facebook-login:4.+'
      // Facebook Share only
      compile 'com.facebook.android:facebook-share:4.+'
      // Facebook Places only
      compile 'com.facebook.android:facebook-places:4.+'
      // Facebook Messenger only
      compile 'com.facebook.android:facebook-messenger:4.+'
      // Facebook App Links only
      compile 'com.facebook.android:facebook-applinks:4.+'
    }
    

    Selecting individual SDKs gives you more control and flexibility over the mobile app size.

The sample app

Let’s now look at a sample app — specifically, an Android app with the views, layouts, and functionality illustrated below:

Sample app

In this sample app, you’ll see 2 different ways to login (using Facebook’s LoginButton and using the Login API), how to get the user’s basic profile information, how to get the user’s friends list, how to reauthorize permissions, and 2 ways to share (using Facebook’s ShareDialog and ShareButton).

The application consists of 3 classes:

  • MainActivity — the main activity for the application.
  • Friend — a class that represents a friend.
  • FriendArrayAdapter — an array adapter for the friend list.

The application includes the following resource files:

  • main.xml — defines a LinearLayout for the main screen.
  • rowlayout.xml — defines a LinearLayout for the the friend list.
  • string.xml — defines the various string resources.

The Android Manifest

All Android apps have an associated Android Manifest. Let’s take a look at the manifest for this sample app.

A few important items:

  1. Set the permission to access the android.permission.INTERNET (line 7).
  2. Define the meta-data to set the Facebook application ID. Recall that you can get the app ID from the dashboard. Set the app ID in the strings.xml file, together with other application strings such as the button strings (line 13).
  3. Define the FacebookContentProvider, which is used to share content if sharing binary attachments such as photos (line 26).

Listing 4. Android Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cenriqueortiz.usingandroidsdk"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name">

        <meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id"/>

        <activity android:name=".MainActivity"
            android:label="@string/app_name"
            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation">
            <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    <provider android:authorities="com.facebook.app.FacebookContentProvider{@string/facebook_app_id}"
      android:name="com.facebook.FacebookContentProvider"
      android:exported="true"/>

    </application>

</manifest>

The string.xml file

The following code snippet shows the string.xml file for this sample app. Note the facebook_app_id (line 3) which you can find on the app’s Facebook Dashboard.

Listing 5. The string.xml file

<resources>
    <string name="app_name">Using FB Android SDK</string>
    <string name="facebook_app_id">[INSERT THE APP ID HERE]</string>
    <string name="loginactivity_name">Login Activity</string>
    <string name="login">Login</string>
    <string name="logout">Logout</string>
    <string name="share">Share</string>
    <string name="friends">Get Friends</string>
    <string name="reauthorize">Reauthorize</string>
    <string name="noprofileinfo">No profile Info.</string>
    <string name="me">Me Request</string>
    <string name="blankspace"></string>
</resources>

The screen layout resource file

The following code snippet shows the main.xml layout resource file for the app’s main screen. This file has a LinearLayout with a number of Buttons, a TextView, and a ListView. Also, note the 2 Facebook button views:

  1. com.facebook.login.widget.LoginButton, which uses the Facebook SDK LoginButton (line 10).
  2. com.facebook.share.widget.ShareButton, which is the Facebook SDK ShareButton (line 57).

Listing 6. The main.xml layout resource file

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/white">

        <com.facebook.login.widget.LoginButton
            android:id="@+id/login_fbbutton"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"/>

        <Button
            android:id="@+id/login_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_gravity="center_horizontal"
            android:text="@string/login"
            />

        <Button
            android:id="@+id/me_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_gravity="center_horizontal"
            android:text="@string/me"
            />

        <Button
            android:id="@+id/friends_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_gravity="center_horizontal"
            android:text="@string/friends"
            />

        <Button
            android:id="@+id/reauthorize_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_gravity="center_horizontal"
            android:text="@string/reauthorize"
            />

        <Button
            android:id="@+id/share_button"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:layout_gravity="center_horizontal"
            android:text="@string/share"
            />

        <com.facebook.share.widget.ShareButton
            android:id="@+id/fb_share_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="FB ShareButton"
            android:layout_margin="5dp"/>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#444"
            android:layout_margin="5dp"/>

            <TextView
                android:id="@+id/textView_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:text="@string/noprofileinfo"/>

         <TableRow
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#444"
            android:layout_margin="5dp"/>

        <ListView
            android:id="@+id/listview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textFilterEnabled="true"
            android:layout_margin="5dp"/>

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"/>

</LinearLayout>

The following sections cover the application code in detail.

The MainActivity

Before we start, let’s go over the beginning of MainActivity.java, the app’s main class. Note that the defined FacebookCallback is invoked by LoginManager when the login requests complete; this callback is used by some of the API calls covered below. The MainActivity class also defines all of the activity’s lifecycle methods as expected, and defines onActivityResult() which is called when the Facebook UI login activities complete; note the call to CallbackManager.onActivityResult() which is necessary to ensure that the SDK callback manager properly handles login state changes.

Listing 7. The MainActivity

/**
 * MainActivity.
 */
public class MainActivity extends Activity {

    private static final String EMAIL = "email";
    private static final String USER_POSTS = "user_posts";
    private static final String BIRTHDAY = "user_birthday";
    private static final String FRIENDS = "user_friends";
    private static final String AUTH_TYPE = ""; //"rerequest";
    private static final List<String> mPermissions = Arrays.asList(EMAIL, USER_POSTS, BIRTHDAY, FRIENDS);
    private final ArrayList<Friend> mFriends = new ArrayList<>();
    private FriendsArrayAdapter mFriendsArrayAdapter;
    private LoginManager mLoginManager;
    private CallbackManager mCallbackManager;
    private static final String TAG = MainActivity.class.getSimpleName();

    ///////////////////////////////////////////////////////////////////////////////////
    // LoginManager FacebookCallback, used by LoginManager (and Facebook LoginButton)
    ///////////////////////////////////////////////////////////////////////////////////
    private FacebookCallback<LoginResult> mFacebookCallback = new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            Log.d(TAG, "***** mFbLoginButton.onSuccess().granted: " +
                    loginResult.getRecentlyGrantedPermissions().toString() +
                    " denied: " + loginResult.getRecentlyDeniedPermissions().toString());
        }

        @Override
        public void onCancel() {
            Log.d(TAG, "***** mFbLoginButton.OnError().onCancel");
        }

        @Override
        public void onError(FacebookException e) {
            // Handle exception
            Log.d(TAG, "***** mFbLoginButton.OnError().FacebookException: " + e);
        }
    };

    /**
     * Activity onActivityResult.
     * Calls the Facebook's onActivityResult Callback.
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG,"***** onActivityResult: " + resultCode);
        mCallbackManager.onActivityResult(requestCode, resultCode, data);
        resetScreenViews();
    }

    /**
     * Helper method to reset the different views in the main screen.
     * Update Login Button text accordingly, and clear text fields.
     */
    private void resetScreenViews() {
        final Button loginButton;
        loginButton = findViewById(R.id.login_button);
        if (loginButton != null) {
            if (AccessToken.isCurrentAccessTokenActive()) {
                loginButton.setText(R.string.logout);
            } else {
                loginButton.setText(R.string.login);
                mFriends.clear();
                TextView tv = findViewById(R.id.textView_name);
                tv.setText(R.string.blankspace);
            }
        }
    }

    /**
     * Activity onCreate.
     * Initializes the Activity, and the Facebook Login Widget Button.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d( "***** MainActivity", "onCreate");
        setContentView(R.layout.main);

        // Get instances for CallbackManager and LoginManager, and register the LoginManager callback
        mCallbackManager = CallbackManager.Factory.create();
        mLoginManager = LoginManager.getInstance();
        LoginManager.getInstance().registerCallback(mCallbackManager, mFacebookCallback);
        :
        :

The rest of this tutorial focuses on how to use the Login, Graph, and Sharing APIs.

Using the Login API

The user must log in before they can access any of the Facebook resources. The Facebook Login API provides 2 main functions:

  1. User authentication using Facebook credentials
  2. Requesting permissions and granting permissions for user data access or for operations such as sharing, getting the user’s profile, getting the user’s list of friends, or accessing pages

Once a user has been authenticated and granted permissions, the app will receive a User Access Token that is passed to subsequent API calls. You’ll recall that if SSO has been enabled and the Facebook native app is installed on the handset, authentication is delegated to the Facebook native app; otherwise, the app defaults to OAuth Webview-based authentication and permission flow.

Using Facebook’s LoginButton

In this section, you’ll learn how to initiate the login flow using Facebook SDK com.facebook.login.widget.LoginButton, a native button control provided by the SDK that keeps login state and performs the login/logout for the app. For this button to work, it requires that the app ID be specified in the AndroidManifest.xml.

Let’s look at the login button’s definition in the main.xml layout resource file:

Listing 8. The LoginButton (com.facebook.login.widget.LoginButton)

<com.facebook.login.widget.LoginButton
    android:id="@+id/login_fbbutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"/>

The above displays a Facebook login or logout native button that uses Facebook’s branding colors.

Now it’s time to set up the LoginButton. First, you need to get the reference to the LoginButton itself, set the permissions, the auth type, and register the FacebookCallback:

Listing 9. Using the LoginButton

:
:
/////////////////////////////////////////////////////////////////////////////////////////
// This snippet of code shows how to use Facebook's Login Button.
//  After getting the reference to LoginButton, set its callback.
// Register the mFbLoginButton callback (which sets the LoginManager callback)
/////////////////////////////////////////////////////////////////////////////////////////
LoginButton mFbLoginButton;
mFbLoginButton = findViewById(R.id.login_fbbutton);
mFbLoginButton.setReadPermissions(mPermissions);
mFbLoginButton.setAuthType(AUTH_TYPE);
mFbLoginButton.registerCallback(mCallbackManager, mFacebookCallback);
:
:

The LoginManager calls the FacebookCallback (defined earlier in this tutorial) when the login completes successfully, is canceled, or if there is an error.

Using the LoginButton is very simple, as it hides most of the logic that you would have to do if using the LoginManager directly, as shown next.

Login using Facebook’s Login Manager

You can use the LoginManager directly to login the user. The LoginManager manages login and permissions for Facebook.

As in the above example, let’s look at the button’s definition in the main.xml layout resource file:

Listing 10. The login button

<Button
  android:id="@+id/login_button"
  android:layout_width="match_parent"
  android:layout_height="40dp"
  android:layout_gravity="center_horizontal"
  android:text="@string/login"
  />

The code above defines a basic ButtonView that you can style as needed. Next is the code to set up the ButtonView. You’ll need to get a reference to the ButtonView itself, set the button’s text based on the current access token state, and set the button click listener.

Listing 11. Using the LoginManager

:
:
/////////////////////////////////////////////////////////////////////////////////////////
// This code snippet shows how to use LoginManager (versus LoginButton)
/////////////////////////////////////////////////////////////////////////////////////////
final Button mLoginButton;
mLoginButton = findViewById(R.id.login_button);
if (mLoginButton != null) {
    // Update Login Button text accordingly
    if (AccessToken.isCurrentAccessTokenActive()) {
        mLoginButton.setText(R.string.logout);
    } else {
        mLoginButton.setText(R.string.login);
    }
    // Set Login Button on click callback
    mLoginButton.setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "***** mLoginButton.onClick");

                if (AccessToken.isCurrentAccessTokenActive()) {
                    Log.d(TAG, "***** mLoginButton.onClick -> Logout");
                    LoginManager.getInstance().logOut();
                    mLoginButton.setText(R.string.login); // toggle button text to read "login"
                    resetScreenViews();
                } else {
                    Log.d(TAG, "***** mLoginButton.onClick -> Login");
                    LoginManager.getInstance().logInWithReadPermissions(MainActivity.this, mPermissions);
                    mLoginButton.setText(R.string.logout); // toggle button text to read "logout"
                }
            }

        });
}
:
:

When the button is clicked, the button’s click listener is called. The click listener in turn calls the LoginManager to login with permissions (logInWithReadPermissions()) or logout() as appropriate, based on the state of the current access token (AccessToken.isCurrentAccessTokenActive()).

Check out Facebook’s Login for Android — Quickstart which walks you through the different steps for setting up and using the Login API, and learn more about Facebook Login Security.

The social graph and the Graph API

Facebook uses a graph to represent user data, in what they call the Facebook social graph. To access the social graph, Facebook defines the Graph API. The following diagram illustrates the social graph:

The social graph

In Facebook’s social graph, there are:

  • Nodes or individual objects, such as a User, a Photo, a Page, or a Comment. Graph API objects are assigned a unique ID and are easily addressable using a URL scheme that can be further qualified to address a specific object/connection. The general structure of an object URL is: “https://graph.facebook.com/ObjectID/ConnectionType” where ObjectID is the object’s unique ID and ConnectionType is one of the connection types supported by the object.

  • Edges or connections or relationships between a collection of objects and a single object. For example, a page might support the following connections:

    • feed/wall
    • photos
    • notes
    • posts
    • members
  • Fields that are the actual data or attributes about an object, such as a User’s name or gender, or a Page’s name.

With the Graph API, you can retrieve an object, delete an object, and publish objects. You can search, update objects, filter results, and even dynamically discover the connections/relationships of an object. You can also retrieve the fields (details) for a given object or node.

This tutorial covers two examples of using the Graph API:

  1. Retrieving the user profile for the currently logged in user (/me)
  2. Retrieving the user’s friends list

Using the Graph API to make a Me request

This section covers how to make a Me request.

Similarly to the login button, let’s first define a ButtonView for the Me request button:

Listing 12. The Me request ButtonView

<Button
  android:id="@+id/me_button"
  android:layout_width="match_parent"
  android:layout_height="40dp"
  android:layout_gravity="center_horizontal"
  android:text="@string/me"
  />

Let’s also define a textView to display the results of the Me request:

Listing 13. The Me request textView

<TextView
  android:id="@+id/textView_name"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_margin="5dp"
  android:text="@string/noprofileinfo"/>

When the Me request button is clicked, the click listener invokes the asynchronous method GraphRequest.newMeRequest() to make the actual Me request to Facebook, passing the current access token and defining a GraphRequest.GraphJSONObjectCallback() that is called when the newMeRequest() completes. The callback parses the JSON response and populates the textView with the response.

Listing 14. Using the Graph API to get the user’s profile

:
:
/////////////////////////////////////////////1////////////////////////////////////////////
// The following code snippet shows how to make a Facebook Me request.
//  Get reference to the Me request button, set its "on click handler", which makes
//      the Graph API
/////////////////////////////////////////////////////////////////////////////////////////
Button mMeButton;
mMeButton = findViewById(R.id.me_button);
mMeButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG,"***** mMeButton.onClick");

        if (AccessToken.isCurrentAccessTokenActive()) {

            Log.d(TAG,
                    "***** mMeButton.onClick, isCurrentAccessTokenActive: " +
                            AccessToken.isCurrentAccessTokenActive() + " / " +
                            AccessToken.getCurrentAccessToken().getPermissions());

            // Me Facebook Request
            GraphRequest meRequest = GraphRequest.newMeRequest(
                    AccessToken.getCurrentAccessToken(),
                    new GraphRequest.GraphJSONObjectCallback() {
                        public void onCompleted(JSONObject json, GraphResponse response) {
                            Log.d(TAG,"***** meRequestCallback: " + response.getJSONObject());

                            TextView tv;
                            String s = "";
                            tv = findViewById(R.id.textView_name);
                            try {
                                s = " ID: " + response.getJSONObject().getString("id") + "\n";
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }

                            try {
                                s += " Name: " + response.getJSONObject().getString("name") + "\n";
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }

                            try {
                                s += " Email: " + response.getJSONObject().getString("email") + "\n";
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            try {
                                s += " Birthday: " + response.getJSONObject().getString("birthday") + "\n";
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            s += " Permissions: " + AccessToken.getCurrentAccessToken().getPermissions().toString();
                            tv.setText(s);
                        }

                    });
            Bundle parameters = new Bundle();
            parameters.putString("fields", "id, name, email, birthday");
            meRequest.setParameters(parameters);
            meRequest.executeAsync();
        }
    }
});
:
:

In the above example, the app requests specific object fields, id, name, email, and birthday, by passing a Bundle as a parameter, as highlighted next:

Listing 15. Request specific object fields for the Me request API call

Bundle parameters = new Bundle();
parameters.putString("fields", "id, name, email, birthday");
meRequest.setParameters(parameters);
meRequest.executeAsync();

The following snippet shows the Me request JSON response:

Listing 16. Example of Me request JSON response

{"id":"106615540438964","name":"Annod Leywor","email":"annod_puryjks_leywor@tfbnw.net","birthday":"01\/19\/2000"}

Using the Graph API to make a Friends request

This section covers how to make a Friends request.

Let’s first look at the related user interface views, as defined in the main.xml resource file. The ButtonView is used to initiate the request, and the ListView is used to display the list of friends that’s received from Facebook.

Listing 17. ButtonView and ListView for the Friends request

<Button
    android:id="@+id/friends_button"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_gravity="center_horizontal"
    android:text="@string/friends"
    />

<ListView
  android:id="@+id/listview"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textFilterEnabled="true"
  android:layout_margin="5dp"/>

Next, let’s look at the code behind the Friends request. As with the Me request, you first get a reference to the ButtonView. A click listener for the button is defined, which when invoked calls the asynchronous method GraphRequest.newMyFriendsRequest() passing as arguments the AccessToken.getCurrentAccessToken() and a GraphRequest.GraphJSONArrayCallback() that is called when the request completes. On completion, the callback parses the JSON response and populates the ListView.

Listing 18. The Friends request

/////////////////////////////////////////////////////////////////////////////////////////
// Using the Friends Request
/////////////////////////////////////////////////////////////////////////////////////////
Button mFriendsButton;
mFriendsButton = findViewById(R.id.friends_button);
mFriendsButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG,"***** mFriendsButton.onClick");

        if (AccessToken.isCurrentAccessTokenActive()) {
            Log.d(TAG,"***** mFriendsButton.onClick, isCurrentAccessTokenActive: " + AccessToken.isCurrentAccessTokenActive() + " / " +
                    AccessToken.getCurrentAccessToken().getPermissions());
        }

        // My Friends Request.
        GraphRequest friendsRequest = GraphRequest.newMyFriendsRequest(
                AccessToken.getCurrentAccessToken(),
                new GraphRequest.GraphJSONArrayCallback() {
                    public void onCompleted(JSONArray json, GraphResponse response) {
                        if (json == null) {
                            Log.d(TAG,"***** mFriendsButton.onCompleted, json is NULL");
                            return;
                        } else {
                            Log.d(TAG,"***** mFriendsButton.onCompleted, json: " + json);
                        }
                        mFriends.clear();
                        try {
                            for (int i=0; i<json.length(); i++) {
                                JSONObject o = json.getJSONObject(i);
                                String n = o.getString("name");
                                String id = o.getString("id");
                                Friend f = new Friend();
                                f.setId(id);
                                f.setName(n);
                                mFriends.add(f);
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        mFriendsArrayAdapter.notifyDataSetChanged();
                    }
                });

        Bundle parameters = new Bundle();
        parameters.putString("fields", "id, name, email, birthday");
        friendsRequest.setParameters(parameters);
        friendsRequest.executeAsync();

    }
});

//////////////////////////////////////////////////////////////////////////
// Setup the ListView Adapter that is loaded when selecting "get friends"
//////////////////////////////////////////////////////////////////////////
ListView mListView;
mListView = findViewById(R.id.listview);
mFriendsArrayAdapter = new FriendsArrayAdapter(MainActivity.this, R.layout.rowlayout, mFriends);
mListView.setAdapter(mFriendsArrayAdapter);

The GraphRequest.newMyFriendsRequest() API call returns a JSON file. Here is an example of the Me request JSON response:

Listing 19. Example of Friends request JSON response

[{"id":"108073063622369","name":"Mark Alcbeijbfhjgj Fergiesen"},{"id":"103290550773109","name":"Margaret Alcbgfdicahfi Wisemanberg"},{"id":"105320080571114","name":"Tommy Pearson"},{"id":"103683167403118","name":"Betty Crocker"}]

In support of the friends list ListView, you have FriendsArrayAdapter, an ArrayAdapter that maintains the ListView that’s updated using the received Friend information. The following code snippet shows the FriendsArrayAdapter:

Listing 20. The FriendsArrayAdapter

/**
 * ListView Friends ArrayAdapter
 */
public class FriendsArrayAdapter extends ArrayAdapter<Friend> {
    private final Activity mContext;
    private final ArrayList<Friend> mFriends;
    private int mResourceId;

    /**
     * Constructor
     * @param context the application content
     * @param resourceId the ID of the resource/view
     * @param friends the bound ArrayList
     */
    FriendsArrayAdapter(
            Activity context, 
            int resourceId, 
            ArrayList<Friend> friends) {
        super(context, resourceId, friends);
        this.mContext = context;
        this.mFriends = friends;
        this.mResourceId = resourceId;
    }

    /**
     * Updates the view
     * @param position the ArrayList position to update
     * @param convertView the view to update/inflate if needed
     * @param parent the groups parent view
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolderItem viewHolder;
        if (convertView == null) {
            LayoutInflater inflater = (mContext).getLayoutInflater();
            convertView = inflater.inflate(mResourceId, parent, false);
            // Set up the ViewHolder
            viewHolder = new ViewHolderItem();
            viewHolder.textViewItem = convertView.findViewById(R.id.textViewItem);
            // Store the holder with the view.
            convertView.setTag(viewHolder);
        } else {
            // Use the viewHolder
            viewHolder = (ViewHolderItem) convertView.getTag();
        }

        // object item based on the position
        Friend f = mFriends.get(position);
        if (f != null) {
            // Get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
            String txt = f.getId() + " | " + f.getName();
            viewHolder.textViewItem.setText(txt);
            viewHolder.textViewItem.setTag(f.getId());
        }
        return convertView;
    }

    // ViewHolder to cache views
    static class ViewHolderItem {
        TextView textViewItem;
    }
}

A ViewHolder design pattern is used to improve app UI performance by minimizing the number of lookups needed to find View elements. To learn more about this pattern, see Making ListView Scrolling Smooth.

Finally, the Friend class holds the information for each friend in the JSON response by Facebook:

Listing 21. The Friend class

/**
 * Represents a Friend
 */
public class Friend {
    private String id;
    private String name;
    private byte[] picture;
    private Bitmap pictureBitmap;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public byte[] getPicture() {
        return picture;
    }

    public void setPicture(byte[] picture) {
        this.picture = picture;
    }

    public Bitmap getPictureBitmap() {
        return pictureBitmap;
    }

    public void setPictureBitmap(Bitmap pictureBitmap) {
        this.pictureBitmap = pictureBitmap;
    }
}

Reauthorizing data access

When a user access token expires, typically 90 days after the user was last active, the app won’t have access to the user’s data. To regain access, your app must reauthorize permissions. To reauthorize, call the LoginManager.reauthorizeDataAccess() method, which presents the Facebook permissions screen for the user to grant or decline permissions. The following code snippet show how to use the reauthorizeDataAccess() method:

Listing 22. Reauthorize request

/////////////////////////////////////////////////////////////////////////////////////////
// Reauthorize Request
/////////////////////////////////////////////////////////////////////////////////////////
Button mReauthorizeButton;
mReauthorizeButton = findViewById(R.id.reauthorize_button);
mReauthorizeButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mLoginManager.reauthorizeDataAccess(MainActivity.this);
    }
});

When the reauthorization completes, the onActivityResult() method is called, which in turn calls mCallbackManager.onActivityResult().

The Share API

This section covers 2 approaches to sharing data:

  • Using Facebook’s ShareButton
  • Using the ShareDialog interface directly

Facebook Share APIs allow you to share different types of content. Beginning with SDK version 4.0, the following content models are supported:

Table 2. Sharing API: Supported content types

Content Type Model Notes
Links ShareLinkContent Share a Link.
Photos SharePhotoContent Share photos. Must have the native Facebook for Android app installed.
Videos ShareVideoContent Share videos.
Multimedia ShareMediaContent Share a combination of photos and videos. Must have the native Facebook for Android app installed. Up to 6 items per request.

In this example, I only cover using the ShareLinkContent content model.

If your app is going to share binary attachments such as images, you need to define a FacebookContentProvider in the AndroidManifest.xml, as shown here:

Listing 23. Defining FacebookContentProvider in the AndroidManifest.xml

<provider android:authorities="com.facebook.app.FacebookContentProvider{@string/facebook_app_id}"
    android:name="com.facebook.FacebookContentProvider"
    android:exported="true"/>

Note how the authorities attribute concatenates @string/facebook_app_id from the string.xml file.

Using the Facebook ShareButton interface

The Facebook SDK provides com.facebook.share.widget.ShareButton, a native button that follows Facebook’s official branding look and feel, keeps the login state, and provides basic login/logout flow functionality.

First, let’s cover the ShareButton view in the main.xml resource file:

Listing 24. The ButtonView for using the Facebook ShareButton

<com.facebook.share.widget.ShareButton
            android:id="@+id/fb_share_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="FB ShareButton"
            android:layout_margin="5dp"/>

Next, the following code snippet shows how to create a ShareLinkContent to share a basic hyperlink when the ShareButton is clicked and its click listener is called:

Listing 25. Using the Facebook ShareButton

/////////////////////////////////////////////////////////////////////////////////////////
// The following code snippet uses the Facebook Share Button.
//  Get reference to share button, set click listener callback.
/////////////////////////////////////////////////////////////////////////////////////////
final ShareButton fbShareButton;
fbShareButton = findViewById(R.id.fb_share_button);
fbShareButton.setEnabled(true);
fbShareButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG,"***** fbShareButton.onClick");
        // For this example, sharing URL via ShareLinkContent.
        final String url = "http://developers.facebook.com/android";
        ShareLinkContent linkContent = new ShareLinkContent.Builder()
                .setContentUrl(Uri.parse(url))
                .build();
        fbShareButton.setShareContent(linkContent);
    }
});

Using the Facebook ShareButton is fairly straightforward: Define the ShareButton in the layout resource file, set a click listener, create the content model as appropriate, and call the ShareButton.setShareContent() method.

Using the ShareDialog Interface

Another approach to sharing data is to use the ShareDialog directly, but first let’s cover the ButtonView to trigger the sharing:

Listing 26. The ButtonView for using the ShareDialog

<Button
  android:id="@+id/share_button"
  android:layout_width="match_parent"
  android:layout_height="40dp"
  android:layout_gravity="center_horizontal"
  android:text="@string/share"
  />

The next step is setting the click listener for the ButtonView, setting the FacebookCallback that is called when sharing completes successfully, is cancelled, or an error is encountered. When the button is clicked, the appropriate content model is created, in this case a ShareLinkContent which is passed to the method ShareDialog.show() if the share dialog supports such a content model.

Listing 27. Using the Facebook ShareDialog

/////////////////////////////////////////////////////////////////////////////////////////
// The following code snippet uses the Facebook Share Dialog.
//  Get reference to share button, set click listener callback.
/////////////////////////////////////////////////////////////////////////////////////////
Button mShareButton;
mShareButton = findViewById(R.id.share_button);
mShareButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mCallbackManager = CallbackManager.Factory.create();
        ShareDialog shareDialog = new ShareDialog(MainActivity.this);
        shareDialog.registerCallback(mCallbackManager, new FacebookCallback<Sharer.Result>() {
            @Override
            public void onSuccess(Sharer.Result result) {
                Log.d(TAG,"***** mShareButton.onClick.shareDialog.registerCallback->onSuccess(): " + result.toString());
            }

            @Override
            public void onCancel() {
                Log.d(TAG,"***** mShareButton.onClick.shareDialog.registerCallback->onCancel()");
            }

            @Override
            public void onError(FacebookException error) {
                Log.d(TAG,"***** mShareButton.onClick.shareDialog.registerCallback->onError(): " + error.toString());
            }
        });

        // For this example, sharing URL via ShareLinkContent.
        final String url = "http://developers.facebook.com/android";
        if (ShareDialog.canShow(ShareLinkContent.class)) {
            Log.d(TAG, "shareOnWall.ShareDialog.canShow");
            ShareLinkContent linkContent = new ShareLinkContent.Builder()
                    .setContentUrl(Uri.parse(url))
                    .build();
            shareDialog.show(linkContent, ShareDialog.Mode.AUTOMATIC);
        }

    }
});

The above code snippet is similar to using the ShareButton, but uses a bit more code for the callback and to test if the ShareDialog can show the requested content model.

For more information on how to share content with Facebook, read Sharing on Android on the Facebook for Developers site.

Summary

Needless to say, this tutorial has covered a lot of information. It started with information on how to register your application with Facebook, touched on app modes and the use of test users, and covered access tokens and permissions. The tutorial then covered the Facebook SDK for Android and how to integrate the Android SDK into your app and build process. It then showed you a sample app that demonstrated how to use the Login API, the Graph API, and the Sharing API.

This tutorial has only covered a fraction of what the SDK offers. The Facebook API and the related Android SDK offer a large number of APIs and functionality. I encourage you to read Getting Started with the Facebook SDK for Android and the Graph API Overview, as well as Authentication Versus Data Access and Access Tokens.