In this tutorial, we are going to learn how to integrate Facebook SDK for Android application login and also we will retrieve and display Facebook user profile information. Using the latest version of Facebook's SDK for Android, it takes only a few minutes to add this feature to your app.
To integrate Facebook login in your android application, Facebook account is an essential requirements.
Add Facebook SDK to your project
Step 1. Head over to Facebook Developer website to create your app and get your application ID by clicking on the Add a new app button.
Step 2. Go to Dashboard and click on Choose Platform tehn select Android as your platform from the window pop-up.
Step 3. The Facebook SDK is available on Maven Central. Add the Maven Central Repository to build.gradle (project):
repositories { mavenCentral() }
Step 4. Add compile 'com.facebook.android:facebook-android-sdk:[4,5)'
to your build.gradle (module) dependencies.
Step 5. Open your strings.xml file and add a new string with the name facebook_app_id
containing the value of your Facebook App ID
<string name="facebook_app_id">111</string>
Step 6. Open AndroidManifest.xml file and ddd a uses-permission
element to the manifest
<uses-permission android:name="android.permission.INTERNET"/>
Step 7. Add a meta-data
element to the application
element
<application android:label="@string/app_name" ...> ... <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/> ... </application>
Step 8. In the bottom form, enter the package name of your app and the name of your Activity.
Step 9. To fill in the Key Hashes field, open a terminal window and run the keytool
command to generate a key hash using the debug keystore located at ~/.android/debug.keystore. This is what the command should look like.
# on MAC and any Linux OS keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
The default password for the debug keystore is android. Enter that password when prompted. The output of the command should be a string of 28 characters. Copy it, go back to your browser, and paste the string into the Key Hashes field.
Also you can get hash key using following snippet
public void getFacebookHashKey(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES); for (Signature signature : info.signatures) { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(signature.toByteArray()); String hashKey = new String(Base64.encode(md.digest(), 0)); Log.i(TAG, "getFacebookHashKey(): " + hashKey); } } catch (NoSuchAlgorithmException e) { Log.e(TAG, "getFacebookHashKey()", e); } catch (Exception e) { Log.e(TAG, "getFacebookHashKey()", e); } }
Creating Login activity
Add two widgets to main_activity.xml file.
LoginButton
to allow the user to log in to FacebookTextView
to display the result of the latest login attemptYou can place them inside a RelativeLayout
.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <com.facebook.login.widget.LoginButton android:id="@+id/btnLogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> <TextView android:id="@+id/tvStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" /> </LinearLayout>
Now let's modify MainActivity
activity. Remember that the name of this class and the package that it belongs to should match the values you entered while registering your app with Facebook.
Declare the widgets you defined in the activity's layout as fields of this class and declare a CallbackManager
as another field.
private TextView tvStatus; private LoginButton btnLogin; private CallbackManager callbackManager;
The CallbackManager
is used to manage the callbacks used in the app.
private CallbackManager callbackManager;
Next, initialize your instance of CallbackManager
using the CallbackManager.Factory.create
method.
callbackManager = CallbackManager.Factory.create();
Call setContentView
to set the layout defined above as the layout of this Activity and then use findViewById
to initialize the widgets.
setContentView(R.layout.main_activity); tvStatus = (TextView) findViewById(R.id.tvStatus); btnLogin = (LoginButton)findViewById(R.id.btnLogin); tvStatus.setText("Status: ready");
It's time to create a callback to handle the results of the login attempts and register it with the CallbackManager
. Custom callbacks should implement FacebookCallback
. The interface has methods to handle each possible outcome of a login attempt:
onSuccess
is called.onCancel
is called.onError
is called.To register the custom callback, use the registerCallback
method.
When the onSuccess
method is called, a LoginResult
is passed as a parameter. Retrieve the access token it contains using getAccessToken
and use its getUserId
method to get the user's ID. To get the token in the form of a String
, use getToken
.
Tapping the login button starts off a new Activity, which returns a result. To receive and handle the result, override the onActivityResult
method of your Activity and pass its parameters to the onActivityResult
method of CallbackManager
.
Below is full code of MainActivity
.
public class MainActivity extends AppCompatActivity { private TextView tvStatus; private LoginButton btnLogin; private CallbackManager callbackManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); callbackManager = CallbackManager.Factory.create(); setContentView(R.layout.activity_main); tvStatus = (TextView) findViewById(R.id.tvStatus); btnLogin = (LoginButton)findViewById(R.id.btnLogin); tvStatus.setText("Status: ready"); btnLogin.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { AccessToken token = loginResult.getAccessToken(); tvStatus.setText(String.format("User ID: %s\n Auth Token: %s", token.getUserId(), token.getToken())); } @Override public void onCancel() { tvStatus.setText("Status: Login attempt canceled."); } @Override public void onError(FacebookException e) { tvStatus.setText("Status: Login attempt failed."); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { callbackManager.onActivityResult(requestCode, resultCode, data); } }
Creating Profile activity
Let's add some more code to get Profile
and track it updates. Layout is the same.
public class MainActivity extends AppCompatActivity { private TextView tvStatus; private LoginButton btnLogin; private CallbackManager callbackManager; ProfileTracker profileTracker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); callbackManager = CallbackManager.Factory.create(); profileTracker = new ProfileTracker() { @Override protected void onCurrentProfileChanged(Profile oldProfile, Profile newProfile) { updateProfileView(newProfile); } }; profileTracker.startTracking(); setContentView(R.layout.activity_main); tvStatus = (TextView) findViewById(R.id.tvStatus); btnLogin = (LoginButton)findViewById(R.id.btnLogin); try { Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } catch (NullPointerException e) { tvStatus.setText("Status: ready"); } btnLogin.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } @Override public void onCancel() { tvStatus.setText("Status: Login attempt canceled."); } @Override public void onError(FacebookException e) { tvStatus.setText("Status: Login attempt failed."); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { callbackManager.onActivityResult(requestCode, resultCode, data); } protected void onStop() { super.onStop(); profileTracker.stopTracking(); } @Override public void onResume() { super.onResume(); Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } private void updateProfileView(Profile profile) { if (profile != null) { String status = String.format("Status: logged!\nUser: %s", profile.getName()); Log.d("DBG", profile.getProfilePictureUri(200,200).toString()); tvStatus.setText(status); } else { tvStatus.setText("Status: ready"); } } }
You can see screen of Activity in end of tutorial.
How to check login status and logout
You can check log in status usign following method
public boolean isLoggedIn() { AccessToken accessToken = AccessToken.getCurrentAccessToken(); return accessToken != null; }
For log out use following snippet
public void logOut() { LoginManager.getInstance().logOut(); }
How to define custom login button
Define Button
somewhere in layout
<Button android:id="@+id/btnLogin" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LOG IN WITH FACEBOOK" android:layout_below="@id/vDivider" android:layout_centerHorizontal="true" android:onClick="logIn"/>
Snippet of MainActivity.java.
public class MainActivity extends AppCompatActivity { private CallbackManager callbackManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // FACEBOOK LOGIN callbackManager = CallbackManager.Factory.create(); if (isLoggedIn()) { Profile profile = Profile.getCurrentProfile(); Log.d(Constants.TAG, profile.getFirstName()); } } public void logIn(View v) { LoginManager.getInstance().logInWithReadPermissions(MainActivity.this, Arrays.asList("public_profile")); LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { AccessToken token = loginResult.getAccessToken(); Toast.makeText(MainActivity.this, String.format("User ID: %s\n Auth Token: %s", token.getUserId(), token.getToken()), Toast.LENGTH_SHORT).show(); } @Override public void onCancel() {} @Override public void onError(FacebookException e) { Log.d(Constants.TAG, e.toString()); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { callbackManager.onActivityResult(requestCode, resultCode, data); } }
The logInWithPermissionName
methods always open a UI and prompt someone for additional permissions if needed. To get addiitional permissions from someone, make this request with the Facebook SDK for Android:
LoginManager.getInstance().logInWithReadPermissions( MainActivity.this, Arrays.asList("email"));
How to get user profile
After login you can get basic user profile using
Profile profile = Profile.getCurrentProfile(); Log.d(Constants.TAG, profile.getName()); Log.d(Constants.TAG, profile.getUri(200, 200));
Also you can use Graph API to get additional information
GraphRequest request = GraphRequest.newMeRequest( AccessToken.getCurrentAccessToken(), new GraphRequest.GraphJSONObjectCallback() { @Override public void onCompleted(JSONObject object, GraphResponse response) { Log.d(Constants.TAG, object.toString()); } }); Bundle parameters = new Bundle(); parameters.putString("fields", "id,name,link,email,gender,birthday,work"); request.setParameters(parameters); request.executeAsync();
Creating Share activity
In this example we'll implement sharing from your Android app to Facebook. When someone shares from your app, their content appears on their Timeline and may appear in their friends' News Feeds.
First, you need to set up a ContentProvider
in your AndroidManifest.xml where 111 is your app ID. Add it before </application>
<provider android:authorities="com.facebook.app.FacebookContentProvider111" android:name="com.facebook.FacebookContentProvider" android:exported="true"/>
When people share links from your app to Facebook, it includes attributes that show up in the post:
contentURL
, the link to be sharedcontentTitle
that represents the title of the content in the link (deprecated)imageURL
, the URL of thumbnail image that will appear on the post (deprecated)contentDescription
of the content, usually 2-4 sentences (deprecated)ShareLinkContent linkContent = new ShareLinkContent.Builder() .setContentUrl(Uri.parse("http://en.proft.me")) .build(); ShareDialog dlgShare = new ShareDialog(getActivity()); dlgShare.show(linkContent);
You can debug share link at Sharing Debugger.
People can share photos from your app to Facebook with the ShareDialog
or with a custom interface.
If you want to share photo you must request more permissions when declare LoginButton
like this
btnLogin.setReadPermissions("email,publish_actions");
Build your share content for photos into the SharePhotoContent
model. For a list of all attributes, see SharePhotoContent reference.
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); SharePhoto photo = new SharePhoto.Builder() .setBitmap(icon) .setCaption("Android icon") .build(); SharePhotoContent content = new SharePhotoContent.Builder() .addPhoto(photo) .build(); dlgShare.show(content);
The Like button is a quick way for people to share content with their friends. A tap on the Like button will like pieces of content from your app and share them on Facebook. The Like button can be used to like a Facebook Page or any Open Graph object and can be referenced by URL or ID. To add a Like button add the following code snippet to your view:
btnLike = (LikeView) findViewById(R.id.btnLike); btnLike.setObjectIdAndType("http://en.proft.me", LikeView.ObjectType.PAGE);
Full activity_main.xml layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <com.facebook.login.widget.LoginButton android:id="@+id/btnLogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> <TextView android:id="@+id/tvStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp"/> <Button android:id="@+id/btnShareLink" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:text="Share link" android:onClick="shareLink" /> <Button android:id="@+id/btnShareImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:text="Share image" android:onClick="shareImage"/> <com.facebook.share.widget.LikeView android:id="@+id/btnLike" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone"/> </LinearLayout>
Full code of MainActivity
public class MainActivity extends AppCompatActivity { private TextView tvStatus; private LoginButton btnLogin; private CallbackManager callbackManager; ProfileTracker profileTracker; Button btnShareLink, btnShareImage; LikeView btnLike; ShareDialog dlgShare; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); callbackManager = CallbackManager.Factory.create(); profileTracker = new ProfileTracker() { @Override protected void onCurrentProfileChanged(Profile oldProfile, Profile newProfile) { updateProfileView(newProfile); } }; profileTracker.startTracking(); setContentView(R.layout.activity_main); dlgShare = new ShareDialog(this); tvStatus = (TextView) findViewById(R.id.tvStatus); btnLogin = (LoginButton)findViewById(R.id.btnLogin); btnShareLink = (Button) findViewById(R.id.btnShareLink); btnShareImage = (Button) findViewById(R.id.btnShareImage); btnLike = (LikeView) findViewById(R.id.btnLike); btnLike.setObjectIdAndType("http://en.proft.me", LikeView.ObjectType.PAGE); try { Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } catch (NullPointerException e) { tvStatus.setText("Status: ready"); } dlgShare.registerCallback(callbackManager, new FacebookCallback<Sharer.Result>() { @Override public void onSuccess(Sharer.Result result) { Toast.makeText(MainActivity.this, "Successfully shared", Toast.LENGTH_SHORT).show(); } @Override public void onCancel() { Toast.makeText(MainActivity.this, "Sharing cancelled", Toast.LENGTH_SHORT).show(); } @Override public void onError(FacebookException e) { Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } }); // // LOGIN callback // btnLogin.setReadPermissions("email,publish_actions"); btnLogin.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } @Override public void onCancel() { tvStatus.setText("Status: Login attempt canceled."); } @Override public void onError(FacebookException e) { tvStatus.setText("Status: Login attempt failed."); } }); // // SHARE LINK callback // btnShareLink.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ShareDialog.canShow(ShareLinkContent.class)) { ShareLinkContent linkContent = new ShareLinkContent.Builder() .setContentUrl(Uri.parse("http://en.proft.me")) .setContentTitle("Proft blog") .setImageUrl(Uri.parse("http://en.proft.me/static/img/melogo.png")) .setContentDescription("Test message from Android.") .build(); dlgShare.show(linkContent); } } }); // // SHARE IMAGE callback // btnShareImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ShareDialog.canShow(SharePhotoContent.class)) { Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); SharePhoto photo = new SharePhoto.Builder() .setBitmap(icon) .setCaption("My caption") .build(); SharePhotoContent content = new SharePhotoContent.Builder() .addPhoto(photo) .build(); dlgShare.show(content); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { callbackManager.onActivityResult(requestCode, resultCode, data); } protected void onStop() { super.onStop(); profileTracker.stopTracking(); } @Override public void onResume() { super.onResume(); Profile profile = Profile.getCurrentProfile(); updateProfileView(profile); } private void updateProfileView(Profile profile) { if (profile != null) { String status = String.format("Status: logged!\nUser: %s", profile.getName()); Log.d("VVV", profile.getProfilePictureUri(200,200).toString()); tvStatus.setText(status); btnShareLink.setVisibility(View.VISIBLE); btnShareImage.setVisibility(View.VISIBLE); btnLike.setVisibility(View.VISIBLE); } else { tvStatus.setText("Status: ready"); btnShareLink.setVisibility(View.GONE); btnShareImage.setVisibility(View.GONE); btnLike.setVisibility(View.GONE); } } }
Result
How to get user's photos
To request user's photos I'm going to use Graph API. The Android SDK has support for integrating with Facebook Graph API. With the GraphRequest
and GraphResponse
classes, you can make requests and get responses in JSON asynchronously.
First of all we need clasess for deserialization list of photos and one photo with url.
File FacebookResponsePhotos.java
class FacebookResponsePhotos { class Photo { String created_time; String id; } class Cursors { String before; String after; } class Paging { Cursors cursors; } public List<Photo> data; public Paging paging; public List<Photo> getPhotos() { return data; } }
File FacebookResponsePhoto.java
class FacebookResponsePhoto { class Image { int height; int width; String source; } public List<Image> images; public String id; public List<Image> getImages() { return images; } public String getHeight960() { String url = ""; if (images.size() > 0) { for(Image img : images){ if(img.height == 960) { url = img.source; break; } } } return url; } }
Second we need permission for user_photos
.
btnLogin = (LoginButton)findViewById(R.id.btnLogin); btnLogin.setReadPermissions("public_profile,user_photos");
After successful login we can use following method to get list of photos and one photo with url
public void getUserPhotos() { new GraphRequest(AccessToken.getCurrentAccessToken(), "/me/photos", null, HttpMethod.GET, new GraphRequest.Callback() { public void onCompleted(GraphResponse response) { Log.d(Constants.TAG, "PHOTOS " + response.getJSONObject().toString()); FacebookResponsePhotos fbResponse = new Gson().fromJson( response.getJSONObject().toString(), FacebookResponsePhotos.class); for (FacebookResponsePhotos.Photo p : fbResponse.getPhotos()) { getPhotoUrl(p.id); } } } ).executeAsync(); } public void getPhotoUrl(String photoID) { new GraphRequest(AccessToken.getCurrentAccessToken(), "/" + photoID + "?fields=images", null, HttpMethod.GET, new GraphRequest.Callback() { public void onCompleted(GraphResponse response) { Log.d(Constants.TAG, "PHOTO " + response.getJSONObject().toString()); FacebookResponsePhoto fbResponse = new Gson().fromJson( response.getJSONObject().toString(), FacebookResponsePhoto.class); Log.d(TAG, "onCompleted URL: " + fbResponse.getHeight960()); } } ).executeAsync(); }