Adding Facebook Login to Android App






4.78/5 (6 votes)
Integrating Facebook Login to Android Application. Now a days almost every web and mobile app provides an option to Login with Facebook. This is because most of the people have a facebook account and facebook has provide an easy to integrate SDK to add Facebook Login to your mobile app.
Now a days almost every web and mobile app provides an option to Login with Facebook. This is because most of the people have a facebook account and facebook has provide an easy to integrate SDK to add Facebook Login to your mobile app, morever while logging in with facebook you don’t need to remember your UserId and password.
Facebook SDK takes care of user’s privacy as well, When people log into your app with Facebook they can grant permissions to your app so you can retrieve information or perform actions on Facebook on their behalf. Most of the permissions require your review before granting it to the android app. Please visit the page Permissions Reference – Facebook Login for more information on facebook login permissioins.
In this tutorial we will be discussing how to integrate Facebook Login into your android application. We will create a simple facebook login android application. various steps like generating your application signature, registering facebook application, downloading facebook sdk among other steps. Here is an official documentation of facebook integration.
Moreover Adding Facebook Login to your app allows you to use Facebook Analytics data such as the no of installs, the time spent by users on your app and much more.
There are two ways to implement Facebook login on Android:
LoginButton
class – Which provides a button you can add to your UI. It follows the current access token and allows people to log in and out.LoginManager
class – To initiate login without using a UI element.
In this tutorial we will be using LoginButton
Class to connect to Facebook. Facebook LoginButton
element wraps functionality available in the LoginManager
. So when someone clicks on the button, the login is initiated with the set permissions. The button follows the login state, and displays the correct text based on someone’s authentication state.
Pre-requisites
- Android Studio installed on your PC (Unix or Windows).
- A real time android device (Smartphone or Tablet) configured with Android Studio.
- Make sure you have Facebook App installed on your android device and it is running Android 4.0.3 or higher.
Create a New Project.
- Create a New Android Studio Project by going to File -> New -> New Project.
- Name the Project, give a unique package name and then click next
- Make sure you select Minimum SDK as API 15 : Android 4.0.3(Ice Cream Sandwich) or higher. This is required for Facebook SDK to function correctly.
- Choose the activity type as Empty Activity and click next.
- Name the activity, We have used LoginActivity as the activity name. Make sure Generate Layout File check box is selected.
This will create your project and initialize all the components.
Adding Facebook SDK to your project.
Add this to build.gradle before dependencies:
repositories {
mavenCentral()
}
- In your project open [your_app] | build.gradle
- Build your project. Now you will be able to import com.facebook.FacebookSdk into your app.
- Add the following code to build.gradle to your build.gradle dependencies and sync your project.
build.gradle
compile 'com.facebook.android:facebook-android-sdk:4.6.0'
Creating a Facebook App ID
- Go to Facebook Developers and click on Android Logo.
- Enter your App Name as shown below
- Click on Create New Facebook App ID button. This will open create new App ID dialog Box as shown below
- choose a category and click on Create App ID button.
- This will open a new page with Info on facebook login for android, scroll down until you find App info section. Enter your app Interests as shown in figure below and click on Next.
Since we have not put the app in Google Play Store It will generate warning message as below. Make sure you have entered correct package name and click on Use this package name button.
- Add development and release key hashes. To ensure the authenticity of the interactions between your app and Facebook, you need to provide the Android key hash for your development environment. If the app has already been published, you should also add your release key hash. To create facebook android native app you need to provide your Android application signature in facebook app settings.
You can generate your application signature (keyhash) using keytool that comes with java. You must have openssl on your computer otherwise first install openssl and set it in your system environment path.
For Windows Pc: Run the following command in cmd and give password as android.
keytool -exportcert -alias androiddebugkey -keystore [path-to-users-directory]\.android\debug.keystore" | openssl sha1 -binary | openssl base64
For Linux/ Mac : Open a terminal and run the following command and give password as android.
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
This command will generate a 28-character key hash unique to your development environment. Copy and paste it into the field below. You will need to provide a development key hash for the development environment of each person who works on your app.
Copy the Key hash to development Key hashes Field on the Facebook Developers Page.
If your app has already been published, you should also add a hash of your release key.
Adding Facebook Login to your android app.
Create a new java class and name it FacebookFragment.java
- You need to initialize Facebook SDK before you can use it. Add a call to
FacebookSdk.sdkInitialize
fromonCreate
method in the fragment:FacebookSdk.sdkInitialize(getApplicationContext());
- Add your Facebook App ID to your project’s strings file.
- Open your strings.xml file. Example path: /app/src/main/res/values/strings.xml.
- Add a new string with the name
facebook_app_id
and value as your Facebook App ID.<string name ="facebook_app_id">1657026007918322</string>
Replace the above app_id no with your own Facebook AppId. You can obtain your Facebook App Id by going to Facebook Developer’s Page and click on My Apps <your_app_name>
- Update your AndroidManifest.xml : Open AndroidManifest.xml
- Add a uses-permission element to the manifest:
<uses-permission android:name="android.permission.INTERNET"/>
- Add a meta-data element to the application element:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
- To use Facebook Login or Share, also add the
FacebookActivity
to the manifest:<activity android:name="com.facebook.FacebookActivity" android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:label="@string/app_name" />
- If you’re sharing links, images or video via the Facebook for Android app, you also need to declare the
FacebookContentProvider
in the manifest. Append your app id to the end of the authorities value. For example if your Facebook app id is 148851038810437, the declaration looks like:<provider android:authorities="com.facebook.app.FacebookContentProvider148851038810437" android:name="com.facebook.FacebookContentProvider" android:exported="true" />
- After completing all these steps your AndroidManifest.xml will be as shown below:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidtutorialpoint.flogin" > <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/> <activity android:name=".LoginActivity" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.facebook.FacebookActivity" android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:theme="@android:style/Theme.Translucent.NoTitleBar" android:label="@string/app_name" /> <provider android:authorities="com.facebook.app.FacebookContentProvider148851038810437" android:name="com.facebook.FacebookContentProvider" android:exported="true" /> </application> </manifest>
- Add a uses-permission element to the manifest:
- Now we have to implement the layout Create a new Layout Resource file, name it fragment_facebook.xml. Now open the layout file and add the following code.
fragment_facebook.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:facebook="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FFF" > <LinearLayout android:layout_width="300dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="30dp" android:gravity="center_horizontal" android:orientation="vertical" > <ImageView android:id="@+id/profilePicture" android:layout_height="100dp" android:layout_width="100dp" android:gravity="center_horizontal" android:layout_marginBottom="10dp" /> <TextView android:id="@+id/greeting" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_gravity="center" android:textColor="#333" android:textSize="18sp"/> <com.facebook.login.widget.LoginButton android:id="@+id/loginButton" android:layout_width="@dimen/button_width" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:layout_gravity="center_horizontal" facebook:com_facebook_confirm_logout="true" facebook:com_facebook_tooltip_mode="never_display" /> <Button android:id="@+id/postStatusUpdateButton" android:layout_width="@dimen/button_width" android:layout_height="wrap_content" android:visibility="gone" android:text="Post Status Update" /> <Button android:id="@+id/postPhotoButton" android:layout_width="@dimen/button_width" android:layout_height="wrap_content" android:visibility="gone" android:text="Post Photo" /> <Button android:id="@+id/getInterestsButton" android:layout_width="@dimen/button_width" android:layout_height="wrap_content" facebook:com_facebook_confirm_logout="true" android:text="Get Interests !!" /> </LinearLayout> </LinearLayout>
Inside the Linear Layout we have an ImageView to display the profile picture of the user, Next we have a TextView for showing our Greeting Message. Then we have
com.facebook.login.widget.LoginButton
, this is custom button widget provided by facebook SDK it has built-in support to handle login. We have usedfacebook:com_facebook_confirm_logout=”true”
to get a confirmation from the user before logging out.We have three more Buttons for Posting Status Update , Posting Photo and Getting User Interests respectively. Note that all the three buttons are initially hidden using
android:visibility=”gone”
and are enabled or disabled based upon whether user is logged in or out. - Declare a private LoginButton variable in FacebookFragment.
private LoginButton loginButton;
- Create a reference to loginButton in the
onCreateView()
method ofFacebookFragment
and also set the fragment for loginButton as this.loginButton = (LoginButton) v.findViewById(R.id.loginButton); // If using in a fragment loginButton.setFragment(this);
- We define a share call back which we will be using later on
private FacebookCallback<Sharer.Result> shareCallback = new FacebookCallback<Sharer.Result>() { @Override public void onCancel() { Log.d("FacebookFragment", "Canceled"); } @Override public void onError(FacebookException error) { Log.d("FacebookFragment", String.format("Error: %s", error.toString())); String title = getString(R.string.error); String alertMessage = error.getMessage(); showResult(title, alertMessage); } @Override public void onSuccess(Sharer.Result result) { Log.d("FacebookFragment", "Success!"); if (result.getPostId() != null) { String title = getString(R.string.success); String id = result.getPostId(); String alertMessage = getString(R.string.successfully_posted_post, id); showResult(title, alertMessage); } } private void showResult(String title, String alertMessage) { new AlertDialog.Builder(getActivity()) .setTitle(title) .setMessage(alertMessage) .setPositiveButton(R.string.ok, null) .show(); } };
- Next create a
callbackManager
and register a call back on the Facebook Login Button.callbackManager = CallbackManager.Factory.create(); // Callback registration loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Toast toast = Toast.makeText(getActivity(), "Logged In", Toast.LENGTH_SHORT); postingEnabled = true; postPhotoButton.setVisibility(View.VISIBLE); postStatusUpdateButton.setVisibility(View.VISIBLE); getUserInterests.setVisibility(View.VISIBLE); toast.show(); handlePendingAction(); updateUI(); } @Override public void onCancel() { // App code if (pendingAction != PendingAction.NONE) { showAlert(); pendingAction = PendingAction.NONE; } updateUI(); } @Override public void onError(FacebookException exception) { if (pendingAction != PendingAction.NONE && exception instanceof FacebookAuthorizationException) { showAlert(); pendingAction = PendingAction.NONE; } updateUI(); } private void showAlert() { new AlertDialog.Builder(getActivity()) .setTitle(R.string.cancelled) .setMessage(R.string.permission_not_granted) .setPositiveButton(R.string.ok, null) .show(); } });
This callback manages the result of Facebook Login and handles conditions such as onSuccess, onCancel and onError.
- Next We use the share call back we defined earlier on
shareDialog
used to share on facebook.shareDialog = new ShareDialog(this); shareDialog.registerCallback( callbackManager, shareCallback);
- We also define an Enum
PendingAction
to deal with pending actions, a constant string to define the permissions and a Bundle key to save pending actions in event of any activity lifecycle event.private enum PendingAction { NONE, POST_PHOTO, POST_STATUS_UPDATE } private static final String PERMISSION = "publish_actions"; private final String PENDING_ACTION_BUNDLE_KEY = "com.androidtutorialpoint.LoginActivity:PendingAction";
- Now we will define some utility functions which we will use later, These functions help in updating the UI on clicking Login , Post Status and Post Photo Buttons.
Paste the following code in the
LoginActivity
after closing brackets ofonCreate()
Methodprivate void updateUI() { boolean enableButtons = AccessToken.getCurrentAccessToken() != null; postStatusUpdateButton.setEnabled(enableButtons || canPresentShareDialog); postPhotoButton.setEnabled(enableButtons || canPresentShareDialogWithPhotos); Profile profile = Profile.getCurrentProfile(); if (enableButtons && profile != null) { new LoadProfileImage(profilePicImageView).execute(profile.getProfilePictureUri(200, 200).toString()); greeting.setText(getString(R.string.hello_user, profile.getFirstName())); postingEnabled = true; postPhotoButton.setVisibility(View.VISIBLE); postStatusUpdateButton.setVisibility(View.VISIBLE); getUserInterests.setVisibility(View.VISIBLE); } else { Bitmap icon = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.user_default); profilePicImageView.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(), icon, 200, 200, 200, false, false, false, false)); greeting.setText(null); postingEnabled = false; postPhotoButton.setVisibility(View.GONE); postStatusUpdateButton.setVisibility(View.GONE); getUserInterests.setVisibility(View.GONE); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(PENDING_ACTION_BUNDLE_KEY, pendingAction.name()); } private void handlePendingAction() { PendingAction previouslyPendingAction = pendingAction; // These actions may re-set pendingAction if they are still pending, but we assume they // will succeed. pendingAction = PendingAction.NONE; switch (previouslyPendingAction) { case NONE: break; case POST_PHOTO: postPhoto(); break; case POST_STATUS_UPDATE: postStatusUpdate(); break; } } private void onClickPostStatusUpdate() { performPublish(PendingAction.POST_STATUS_UPDATE, canPresentShareDialog); } private void postStatusUpdate() { Profile profile = Profile.getCurrentProfile(); ShareLinkContent linkContent = new ShareLinkContent.Builder() .setContentTitle("Integrate Facebook Login to your Android App") .setContentDescription( "This app shows how to integrate Facebook Login to your Android App") .setContentUrl(Uri.parse("http://www.androidtutorialpoint.com/material-design/adding-facebook-login-to-android-app/")) .build(); if (canPresentShareDialog) { shareDialog.show(linkContent); } else if (profile != null && hasPublishPermission()) { ShareApi.share(linkContent, shareCallback); } else { pendingAction = PendingAction.POST_STATUS_UPDATE; } } private void onClickPostPhoto() { performPublish(PendingAction.POST_PHOTO, canPresentShareDialogWithPhotos); } private void postPhoto() { Bitmap image = BitmapFactory.decodeResource(this.getResources(), R.drawable.androidlogo); SharePhoto sharePhoto = new SharePhoto.Builder().setBitmap(image).build(); ArrayList<SharePhoto> photos = new ArrayList<>(); photos.add(sharePhoto); SharePhotoContent sharePhotoContent = new SharePhotoContent.Builder().setPhotos(photos).build(); if (canPresentShareDialogWithPhotos) { shareDialog.show(sharePhotoContent); } else if (hasPublishPermission()) { ShareApi.share(sharePhotoContent, shareCallback); } else { pendingAction = PendingAction.POST_PHOTO; // We need to get new permissions, then complete the action when we get called back. LoginManager.getInstance().logInWithPublishPermissions( this, Arrays.asList(PERMISSION)); } } private boolean hasPublishPermission() { AccessToken accessToken = AccessToken.getCurrentAccessToken(); return accessToken != null && accessToken.getPermissions().contains("publish_actions"); } private void performPublish(PendingAction action, boolean allowNoToken) { AccessToken accessToken = AccessToken.getCurrentAccessToken(); if (accessToken != null || allowNoToken) { pendingAction = action; handlePendingAction(); } } /** * Background Async task to load user profile picture from url * */ private class LoadProfileImage extends AsyncTask<String, Void, Bitmap> { ImageView bmImage; public LoadProfileImage(ImageView bmImage) { this.bmImage = bmImage; } protected Bitmap doInBackground(String... uri) { String url = uri[0]; Bitmap mIcon11 = null; try { InputStream in = new java.net.URL(url).openStream(); mIcon11 = BitmapFactory.decodeStream(in); } catch (Exception e) { Log.e("Error", e.getMessage()); e.printStackTrace(); } return mIcon11; } protected void onPostExecute(Bitmap result) { if (result != null) { Bitmap resized = Bitmap.createScaledBitmap(result,200,200, true); bmImage.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),resized,250,200,200, false, false, false, false)); } } }
Let’s Discuss all the helper methods we have added.
updateUI()
: Used to manage the UI , checks for a validAccessToken
and enables thepostStatusUpdateButton
andpostPhotoButton
based upon it. If the profile is null it sets the default profile picture in the image view, but in case the profile is valid it will add the greeting text and set the profile picture of the user. To load the profile picture we have created a utility methodLoadProfileImage()
which we will be discussing shortly. We have to handle the visibilty of the buttons here since we will be calling this method in theonResume
lifecyle method of the fragment.onSaveInstanceState(Bundle outState)
: In case of any change activity lifecycle event like change in device configuration we need to use saved bundle information.handlePendingAction()
: It manages the pending actions if there is any. Based on the pending status it will callpostPhoto()
andpostStatusUpdate()
method which are discussed below.postStatusUpdate()
: It allows your app to update the status on behalf of the user, We have created aShareLinkContent
object using itsBuilder
method and based upon the permissions the app will show the dialog to share the content or pass it as pendingAction.postPhoto()
: It allows your app to post a photo on behalf of the user, We have created aSharePhoto
object using itsBuilder
method, again based upon the permissions the app will show the dialog to share the content or pass it as pendingAction.The above two functions uses methods
hasPublishPermission()
andperformPublish()
methodshasPublishPermission()
: As the name suggests this method gets the access token and checks whether the active token haspublish_actions
permissions.performPublish(PendingAction action, boolean allowNoToken)
: This method is a utility method to the access token and perform the action passed to the function.onClickPostStatusUpdate()
: this method just callsperformPublish()
and passes thePOST_STATUS_UPDATE
as an argument.onClickPostPhoto()
: this method just callsperformPublish()
and passes thePOST_PHOTO
as an argument.LoadProfileImage()
extends theAsyncTask
, It is used to download the profile picture of the user.
- Next Create a facebook Profile Tracker to track any changes to your facebook Profile
profileTracker = new ProfileTracker() { @Override protected void onCurrentProfileChanged(Profile oldProfile, Profile currentProfile) { updateUI(); // It's possible that we were waiting for Profile to be populated in order to // post a status update. handlePendingAction(); } };
- Create references for profile Picture view, Greeting Message, Status Update Button, Post Photo Button and Get User Interests Button in the
onCreateView()
method of the FacebookFragmentprofilePicImageView = (ImageView) v.findViewById(R.id.profilePicture); greeting = (TextView) v.findViewById(R.id.greeting); postStatusUpdateButton = (Button) v.findViewById(R.id.postStatusUpdateButton); postPhotoButton = (Button) v.findViewById(R.id.postPhotoButton); getUserInterests = (Button) v.findViewById(R.id.getInterestsButton);
- Next We define
OnClickListener
s for the Facebook Login Button, Status Update Button, Post Photo Button and Get User Interests Button in theonCreateView()
method of the FacebookFragmentloginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LoginManager.getInstance().logInWithReadPermissions(getActivity(), Arrays.asList("public_profile")); if(!postingEnabled) { postingEnabled = true; postPhotoButton.setVisibility(View.VISIBLE); postStatusUpdateButton.setVisibility(View.VISIBLE); getUserInterests.setVisibility(View.VISIBLE); }else{ postingEnabled = false; postPhotoButton.setVisibility(View.GONE); postStatusUpdateButton.setVisibility(View.GONE); getUserInterests.setVisibility(View.GONE); } }); postStatusUpdateButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { onClickPostStatusUpdate(); } }); postPhotoButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { onClickPostPhoto(); } }); getUserInterests.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GraphRequest request = GraphRequest.newMeRequest(AccessToken.getCurrentAccessToken(), new GraphRequest.GraphJSONObjectCallback() { @Override public void onCompleted( JSONObject object, GraphResponse response) { if (object != null) { Log.d("Flogin", object.toString()); String name = JSONParser.getName(object); String id = JSONParser.getId(object); ArrayList<String> favAthletes = JSONParser.getFavAthletes(object); ArrayList<String> favTeams = JSONParser.getFavTeams(object); String s ="Name : "+name+"\n"; s +="Id : "+id+"\n"; s +="Favourite Athletes : "+"\n"; for(int i = 0; i < favAthletes.size(); i++) { s += ((i+1)+". "+favAthletes.get(i)).toString()+"\n"; } s += "Favourite Teams : "+"\n"; for(int i = 0; i < favTeams.size(); i++) { s += ((i+1)+". "+favTeams.get(i)).toString()+"\n"; } Toast t = Toast.makeText(getActivity(),s, Toast.LENGTH_LONG); t.show(); } } }); Bundle parameters = new Bundle(); parameters.putString("fields", "id,name,link,favorite_athletes,favorite_teams"); request.setParameters(parameters); request.executeAsync(); } });
Let’s go through the code for each of the
onClickListener()
.- Login Button : The
onClickListener()
will set the visibilty of the Post Photo, Post Status and Get User Interests button based upon the value of boolean variable postingEnabled. - Post Status Button : It will simply call the
onClickPostStatusUpdate()
method described earlier. - Post Photo Button : It will call the
onClickPostPhoto()
method described earlier. - Get User Interests Button : This method shows the demonstrates the working of Facebook Graph API. We are creating a
newMeRequest
which takes in the activeAccessToken
. This request is like an AsyncTask request, we then create a bundle of parameters we need. Here we are getting the id,name,link,email,favorite_athletes,favorite_teams etc for the Logged In User. We will be printing these as a toast message. The response is in the JSON format. We are then using a JSONParser class to get a list of athletes and favourite team for the user. Implementation of the JSONParser class is given later in the tutorial.
- Login Button : The
- In the
onCreateView()
method add the following code to indicate that it is possible to show ShareDialog and Dialog with Photos to the user.// Can we present the share dialog for regular links? canPresentShareDialog = ShareDialog.canShow( ShareLinkContent.class); // Can we present the share dialog for photos? canPresentShareDialogWithPhotos = ShareDialog.canShow( SharePhotoContent.class);
- We define on Resume, on Pause and
onDestroy
lifecycle methods for our Fragment
In order to use Analytics support provided by facebook for advertising and reporting purpose. You can access these reports from the Facebook Developer’s page.@Override public void onResume() { super.onResume(); // Call the 'activateApp' method to log an app event for use in analytics and advertising reporting. AppEventsLogger.activateApp(getApplicationContext()); updateUI(); } @Override public void onPause() { super.onPause(); // Call the 'deactivateApp' method to log an app event for use in analytics and advertising reporting. AppEventsLogger.deactivateApp(getApplicationContext()); } @Override public void onDestroy() { super.onDestroy(); profileTracker.stopTracking(); }
- We have to create
onActivityResult()
method to forward the login results to thecallbackManager
created inonCreate()
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); callbackManager.onActivityResult(requestCode, resultCode, data); }
- The complete FacebookFragment.java code is shown below:
Faceboook Fragment
package com.androidtutorialpoint.flogin; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.facebook.AccessToken; import com.facebook.CallbackManager; import com.facebook.FacebookAuthorizationException; import com.facebook.FacebookCallback; import com.facebook.FacebookException; import com.facebook.FacebookSdk; import com.facebook.GraphRequest; import com.facebook.GraphResponse; import com.facebook.Profile; import com.facebook.ProfileTracker; import com.facebook.appevents.AppEventsLogger; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; import com.facebook.login.widget.LoginButton; import com.facebook.share.ShareApi; import com.facebook.share.Sharer; import com.facebook.share.model.ShareLinkContent; import com.facebook.share.model.SharePhoto; import com.facebook.share.model.SharePhotoContent; import com.facebook.share.widget.ShareDialog; import org.json.JSONObject; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; public class FacebookFragment extends Fragment{ private LoginButton loginButton; private Button getUserInterests; private boolean postingEnabled = false; private static final String PERMISSION = "publish_actions"; private final String PENDING_ACTION_BUNDLE_KEY = "com.example.hellofacebook:PendingAction"; private Button postStatusUpdateButton; private Button postPhotoButton; private ImageView profilePicImageView; private TextView greeting; private PendingAction pendingAction = PendingAction.NONE; private boolean canPresentShareDialog; private boolean canPresentShareDialogWithPhotos; private CallbackManager callbackManager; private ProfileTracker profileTracker; private ShareDialog shareDialog; private FacebookCallback<Sharer.Result> shareCallback = new FacebookCallback<Sharer.Result>() { @Override public void onCancel() { Log.d("FacebookFragment", "Canceled"); } @Override public void onError(FacebookException error) { Log.d("FacebookFragment", String.format("Error: %s", error.toString())); String title = getString(R.string.error); String alertMessage = error.getMessage(); showResult(title, alertMessage); } @Override public void onSuccess(Sharer.Result result) { Log.d("FacebookFragment", "Success!"); if (result.getPostId() != null) { String title = getString(R.string.success); String id = result.getPostId(); String alertMessage = getString(R.string.successfully_posted_post, id); showResult(title, alertMessage); } } private void showResult(String title, String alertMessage) { new AlertDialog.Builder(getActivity()) .setTitle(title) .setMessage(alertMessage) .setPositiveButton(R.string.ok, null) .show(); } }; private enum PendingAction { NONE, POST_PHOTO, POST_STATUS_UPDATE } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FacebookSdk.sdkInitialize(getActivity()); // Other app specific specialization } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); callbackManager.onActivityResult(requestCode, resultCode, data); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_facebook, parent, false); loginButton = (LoginButton) v.findViewById(R.id.loginButton); // If using in a fragment loginButton.setFragment(this); callbackManager = CallbackManager.Factory.create(); // Callback registration loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Toast toast = Toast.makeText(getActivity(), "Logged In", Toast.LENGTH_SHORT); postingEnabled = true; postPhotoButton.setVisibility(View.VISIBLE); postStatusUpdateButton.setVisibility(View.VISIBLE); getUserInterests.setVisibility(View.VISIBLE); toast.show(); handlePendingAction(); updateUI(); } @Override public void onCancel() { // App code if (pendingAction != PendingAction.NONE) { showAlert(); pendingAction = PendingAction.NONE; } updateUI(); } @Override public void onError(FacebookException exception) { if (pendingAction != PendingAction.NONE && exception instanceof FacebookAuthorizationException) { showAlert(); pendingAction = PendingAction.NONE; } updateUI(); } private void showAlert() { new AlertDialog.Builder(getActivity()) .setTitle(R.string.cancelled) .setMessage(R.string.permission_not_granted) .setPositiveButton(R.string.ok, null) .show(); } }); shareDialog = new ShareDialog(this); shareDialog.registerCallback( callbackManager, shareCallback); if (savedInstanceState != null) { String name = savedInstanceState.getString(PENDING_ACTION_BUNDLE_KEY); pendingAction = PendingAction.valueOf(name); } profileTracker = new ProfileTracker() { @Override protected void onCurrentProfileChanged(Profile oldProfile, Profile currentProfile) { updateUI(); handlePendingAction(); } }; profilePicImageView = (ImageView) v.findViewById(R.id.profilePicture); greeting = (TextView) v.findViewById(R.id.greeting); postStatusUpdateButton = (Button) v.findViewById(R.id.postStatusUpdateButton); postStatusUpdateButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { onClickPostStatusUpdate(); } }); postPhotoButton = (Button) v.findViewById(R.id.postPhotoButton); postPhotoButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { onClickPostPhoto(); } }); getUserInterests = (Button) v.findViewById(R.id.getInterestsButton); getUserInterests.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GraphRequest request = GraphRequest.newMeRequest(AccessToken.getCurrentAccessToken(), new GraphRequest.GraphJSONObjectCallback() { @Override public void onCompleted( JSONObject object, GraphResponse response) { if (object != null) { Log.d("Flogin", object.toString()); ArrayList<String> favAthletes = JSONParser.getFavAthletes(object); Log.d("Print",favAthletes.toString()); Toast t = Toast.makeText(getActivity(), object.toString(), Toast.LENGTH_LONG); t.show(); } } }); Bundle parameters = new Bundle(); parameters.putString("fields", "id,name,link,email,favorite_athletes,favorite_teams"); request.setParameters(parameters); request.executeAsync(); } }); // Can we present the share dialog for regular links? canPresentShareDialog = ShareDialog.canShow( ShareLinkContent.class); // Can we present the share dialog for photos? canPresentShareDialogWithPhotos = ShareDialog.canShow( SharePhotoContent.class); loginButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LoginManager.getInstance().logInWithReadPermissions(getActivity(), Arrays.asList("public_profile")); if(!postingEnabled) { postingEnabled = true; postPhotoButton.setVisibility(View.VISIBLE); postStatusUpdateButton.setVisibility(View.VISIBLE); getUserInterests.setVisibility(View.VISIBLE); }else{ postingEnabled = false; postPhotoButton.setVisibility(View.GONE); postStatusUpdateButton.setVisibility(View.GONE); getUserInterests.setVisibility(View.GONE); } // GraphRequest request = GraphRequest.newMeRequest(AccessToken.getCurrentAccessToken(), // new GraphRequest.GraphJSONObjectCallback() { // @Override // public void onCompleted( // JSONObject object, // GraphResponse response) { // if (object != null) { // Log.d("Me Request",object.toString()); // Toast t = Toast.makeText(getActivity(), object.toString(), Toast.LENGTH_SHORT); // t.show(); // } // // } // }); // Bundle parameters = new Bundle(); // parameters.putString("fields", "id,name,link,email"); // request.setParameters(parameters); // request.executeAsync(); } }); // loginButton.setOnClickListener(new View.OnClickListener() { // @Override // public void onClick(View v) { // // LoginManager.getInstance().logInWithReadPermissions(getActivity(), Arrays.asList("public_profile", "user_friends")); // // // // } // }); return v; } @Override public void onResume() { super.onResume(); // Call the 'activateApp' method to log an app event for use in analytics and advertising // reporting. Do so in the onResume methods of the primary Activities that an app may be // launched into. AppEventsLogger.activateApp(getActivity()); updateUI(); } @Override public void onPause() { super.onPause(); // Call the 'deactivateApp' method to log an app event for use in analytics and advertising // reporting. Do so in the onPause methods of the primary Activities that an app may be // launched into. AppEventsLogger.deactivateApp(getActivity()); } @Override public void onDestroy() { super.onDestroy(); profileTracker.stopTracking(); } private void updateUI() { boolean enableButtons = AccessToken.getCurrentAccessToken() != null; postStatusUpdateButton.setEnabled(enableButtons || canPresentShareDialog); postPhotoButton.setEnabled(enableButtons || canPresentShareDialogWithPhotos); Profile profile = Profile.getCurrentProfile(); if (enableButtons && profile != null) { new LoadProfileImage(profilePicImageView).execute(profile.getProfilePictureUri(200, 200).toString()); greeting.setText(getString(R.string.hello_user, profile.getFirstName())); } else { Bitmap icon = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.user_default); profilePicImageView.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(), icon, 200, 200, 200, false, false, false, false)); greeting.setText(null); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(PENDING_ACTION_BUNDLE_KEY, pendingAction.name()); } private void handlePendingAction() { PendingAction previouslyPendingAction = pendingAction; // These actions may re-set pendingAction if they are still pending, but we assume they // will succeed. pendingAction = PendingAction.NONE; switch (previouslyPendingAction) { case NONE: break; case POST_PHOTO: postPhoto(); break; case POST_STATUS_UPDATE: postStatusUpdate(); break; } } private void onClickPostStatusUpdate() { performPublish(PendingAction.POST_STATUS_UPDATE, canPresentShareDialog); } private void postStatusUpdate() { Profile profile = Profile.getCurrentProfile(); ShareLinkContent linkContent = new ShareLinkContent.Builder() .setContentTitle("Integrate Facebook Login to your Android App") .setContentDescription( "This app shows how to integrate Facebook Login to your Android App") .setContentUrl(Uri.parse("http://www.androidtutorialpoint.com/material-design/adding-facebook-login-to-android-app/")) .build(); if (canPresentShareDialog) { shareDialog.show(linkContent); } else if (profile != null && hasPublishPermission()) { ShareApi.share(linkContent, shareCallback); } else { pendingAction = PendingAction.POST_STATUS_UPDATE; } } private void onClickPostPhoto() { performPublish(PendingAction.POST_PHOTO, canPresentShareDialogWithPhotos); } private void postPhoto() { Bitmap image = BitmapFactory.decodeResource(this.getResources(), R.drawable.androidlogo); SharePhoto sharePhoto = new SharePhoto.Builder().setBitmap(image).build(); ArrayList<SharePhoto> photos = new ArrayList<>(); photos.add(sharePhoto); SharePhotoContent sharePhotoContent = new SharePhotoContent.Builder().setPhotos(photos).build(); if (canPresentShareDialogWithPhotos) { shareDialog.show(sharePhotoContent); } else if (hasPublishPermission()) { ShareApi.share(sharePhotoContent, shareCallback); } else { pendingAction = PendingAction.POST_PHOTO; // We need to get new permissions, then complete the action when we get called back. LoginManager.getInstance().logInWithPublishPermissions( this, Arrays.asList(PERMISSION)); } } private boolean hasPublishPermission() { AccessToken accessToken = AccessToken.getCurrentAccessToken(); return accessToken != null && accessToken.getPermissions().contains("publish_actions"); } private void performPublish(PendingAction action, boolean allowNoToken) { AccessToken accessToken = AccessToken.getCurrentAccessToken(); if (accessToken != null || allowNoToken) { pendingAction = action; handlePendingAction(); } } /** * Background Async task to load user profile picture from url * */ private class LoadProfileImage extends AsyncTask<String, Void, Bitmap> { ImageView bmImage; public LoadProfileImage(ImageView bmImage) { this.bmImage = bmImage; } protected Bitmap doInBackground(String... uri) { String url = uri[0]; Bitmap mIcon11 = null; try { InputStream in = new java.net.URL(url).openStream(); mIcon11 = BitmapFactory.decodeStream(in); } catch (Exception e) { Log.e("Error", e.getMessage()); e.printStackTrace(); } return mIcon11; } protected void onPostExecute(Bitmap result) { if (result != null) { Bitmap resized = Bitmap.createScaledBitmap(result,200,200, true); bmImage.setImageBitmap(ImageHelper.getRoundedCornerBitmap(getContext(),resized,250,200,200, false, false, false, false)); } } } }
FacebookFragment will be hosted in the
LoginActivity
. Open the layout file activity_login.xml and add the following code.activity_login.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".LoginActivity"> </RelativeLayout>
The layout will act as container for the FacebookFragment. Next add the FragmentManager to LoginActivity in order to start the fragment.
LoginActivity
package com.androidtutorialpoint.flogin; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class LoginActivity extends AppCompatActivity { private com.facebook.login.widget.LoginButton loginButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); FragmentManager fm = getSupportFragmentManager(); Fragment fragment = fm.findFragmentById(R.id.fragment_container); if (fragment == null) { fragment = new FacebookFragment(); fm.beginTransaction() .add(R.id.fragment_container, fragment) .commit(); } } }
We have used some utility classes like JSONParser
Create these two classes in the same package:
ImageHelper.java
package com.androidtutorialpoint.flogin; /** * Created by anonymous on 12/10/15. */ import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; public class ImageHelper { public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels , int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR ) { Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas canvas = new Canvas(output); final float densityMultiplier = context.getResources().getDisplayMetrics().density; final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, w, h); final RectF rectF = new RectF(rect); //make sure that our rounded corner is scaled appropriately final float roundPx = pixels*densityMultiplier; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); //draw rectangles over the corners we want to be square if (squareTL ){ canvas.drawRect(0, h/2, w/2, h, paint); } if (squareTR ){ canvas.drawRect(w/2, h/2, w, h, paint); } if (squareBL ){ canvas.drawRect(0, 0, w/2, h/2, paint); } if (squareBR ){ canvas.drawRect(w/2, 0, w, h/2, paint); } paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(input, 0,0, paint); return output; } public static Bitmap getRoundedCornerBitmap1(Bitmap bitmap, int pixels) { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); final float roundPx = pixels; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } }
JSONParser.java
package com.androidtutorialpoint.flogin; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; public class JSONParser { public static ArrayList<String> favAthletes = new ArrayList<>(); public static ArrayList<String> favTeams = new ArrayList<>(); public static ArrayList<String> getFavAthletes(JSONObject obj) { favAthletes.clear(); try { JSONArray arr = obj.getJSONArray("favorite_athletes"); String s; for (int i = 0; i < arr.length(); i++) { obj = arr.getJSONObject(i); s = obj.getString("name"); favAthletes.add(s); } } catch (JSONException e) { e.printStackTrace(); } return favAthletes; } public static ArrayList<String> getFavTeams(JSONObject obj) { favTeams.clear(); try { JSONArray arr = obj.getJSONArray("favorite_teams"); String s; for (int i = 0; i < arr.length(); i++) { obj = arr.getJSONObject(i); s = obj.getString("name"); favTeams.add(s); } } catch (JSONException e) { e.printStackTrace(); } return favTeams; } public static String getName(JSONObject obj) { String s1 = ""; try { s1 = obj.getString("name"); } catch (JSONException e) { e.printStackTrace(); } return s1; } public static String getId(JSONObject obj) { String s1 = ""; try { s1 = obj.getString("id"); } catch (JSONException e) { e.printStackTrace(); } return s1; } }
Additionally you can copy the strings.xml and dimens.xml files
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="button_width">250dp</dimen> </resources>
<resources> <string name="app_name">FLogin</string> <string name ="facebook_app_id">148851038810437</string><string name="facebook_app_name">HelloFBSample</string> <string name="cancelled">Cancelled</string> <string name="permission_not_granted">Unable to perform selected action because permissions were not granted.</string> <string name="ok">OK</string> <string name="hello_user">Hello %1$s!</string> <string name="success">Success</string> <string name="successfully_posted_post">Post ID: %1$s</string> <string name="error">Error</string> <string name="status_update">Updating status for %1$s at %2$s</string> <string name="photo_post">Photo Post</string> <string name="you_picked">You picked:</string> <string name="no_friends_selected"><No friends selected></string> <string name="no_place_selected"><No place selected></string> <string name="pick_seattle_place">Pick a Seattle Place</string> <string name="app_id">355198514515820</string> <string name="exception">Exception: %1$s</string> </resources>
You can add the image resources used in the project, by downloading the project from Download Now button at the top of the post and copying the images from the drawable’s folder.
Now, run the app on your phone or emulator where you are already using your Facebook account, and you should be able to sign in to the App using your existing Facebook account. Please note that while your app is in development stage you can login into the app using the facebook account which is registered as Developer or a Tester. Otherwise you will get the following error “App Not Setup: This app is still in development mode, and you don’t have access to it. Switch to a registered test user or ask an app admin for permissions.”
In case you face similar issue, then configure the roles in the Facebook Developers page in the app roles section.
What’s Next!!!
You can experiment with different user permissions and try to access the information from the user.