6.09.2013

Login, publish post and logout with Facebook API 3.0 for Android


In order to start using Facebook API in you application, you'll need to download and extract the SDK ZIP file. By enabling Facebook integrations, including through this SDK, you can share information with Facebook, including information about people’s use of your app.

To import the SDK library project and the samples, with the new SDK, go to Eclipse's File > Import menu, and select General' / 'Existing Projects into Workspace.


Browse to select the root of your SDK folder, facebook-android-sdk-master. The SDK should appear in the list as 'FacebookSDK' . For this tutorial we don't need the samples so deselect them.


Click 'Finish'. If the project is showing errors, simply use Project > Clean in Eclipse to refresh all the project's states. It is also possible that your Eclipse compiler level has not matched that required by Android. If you see errors like "Android requires compiler compliance level 5.0 or 6.0.", simply make sure the project (or Eclipse) properties mandate v1.6 in the Java Compiler section.

The next step is to create Facebook App. To do this go to App Dashboard, on the Facebook Developers site. Click 'Create New App', and enter basic information such as its name and a unique namespace.









Once created, note down the app ID shown at the top of the dashboard page. You'll need to add this to your project files. Next you'll need to create Android key hashes to associate with the app.The key hash is used by Facebook as a security check for authenticity. Every Android app you'll create will be signed, and you will need to register each app's key hash with Facebook as a security check for authenticity. To generate your key hash on your local computer, run Java's keytool utility (which should be on your console's path) against the Android debug keystore. This is, by default, in your home .android directory). On Windows, use:

       keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64

You will be prompted for a password. This should be 'android' without quotes. You'll then be given a key hash of 30 characters or so. (If you are not prompted for a password, something is wrong and you must check your paths above to ensure the debug.keystore is present.).

It you are not registered as a facebook developer, go to the Facebook Developer site. Make sure you are logged into Facebook and, using the dropdown menu in the top-right, go to your 'Settings'.Then, go to the 'Developer Settings' section on the left. If you haven't done so yet, you will be required to quickly register as a developer.











To obtain the release key hash, use the 'keytool' in the same way as in the step above except for the alias and path.

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

Make sure to use the password that you set when you first created the release key. Save this change. You will also need to return to this dashboard and add your app's package name and main activity class once you have created a new Android project itself.








Now everything is ready to start our project.
Go to File -> New -> Android Application Project to create new project. Lets call it MyFacebookProject. Define the other options of the project and click next.


Create blank activity click next and finish.MainActivity class and activity_main.xml will be automatically created. In activity_main.xml create two button - login and logout. when the user logs in the logout button will be shown.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/loginButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Login" />

    <Button
        android:id="@+id/logoutButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Logout"
        android:visibility="gone" />

</LinearLayout>

Before we start writing some code, we will have to include the FacebookSDK library to our project. To do this, select Project -> Properties. On the Library area, click add and select FacebookSDK. You'll see something similar like the image below.


Go to MainActivity.class and add this two lines:

private Session.StatusCallback sessionStatusCallback;
private Session currentSession;

The currentSession variable will contain the active session. Next lets create a method that will be used to login the user. Call the method connectToFB().

        /**
 * Connects the user to facebook
 */
 public void connectToFB() {
  
  List<String> permissions = new ArrayList<String>();
  permissions.add("publish_stream");
  
  currentSession = new Session.Builder(this).build();
  currentSession.addCallback(sessionStatusCallback);

  Session.OpenRequest openRequest = new Session.OpenRequest(this);
  openRequest.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
  openRequest.setRequestCode(Session.DEFAULT_AUTHORIZE_ACTIVITY_CODE);
  openRequest.setPermissions(permissions);
  currentSession.openForPublish(openRequest);
  
 }

Override the onActivityResult() method.

        /**
 * this method is used by the facebook API
 */
 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (currentSession != null) {
   currentSession.onActivityResult(this, requestCode, resultCode, data);
  }
 }

Now lets create a method onSessionStateChange that will manage the session. In this method you can fetch user data and do other stuff when the session is open.

        /**
 * manages the session state change. This method is called after the
 * <code>connectToFB()</code> method.
 * 
 * @param session
 * @param state
 * @param exception
 */
 private void onSessionStateChange(Session session, SessionState state,
   Exception exception) {
  if (session != currentSession) {
   return;
  }

  if (state.isOpened()) {
   // Log in just happened.
   Toast.makeText(getApplicationContext(), "session opened",
     Toast.LENGTH_SHORT).show();
  } else if (state.isClosed()) {
   // Log out just happened. Update the UI.
   Toast.makeText(getApplicationContext(), "session closed",
     Toast.LENGTH_SHORT).show();
  }
 }

In the onCreate() method instanciate the sessionStatusCallback, so it will react on session changes.

// create instace for sessionStatusCallback
sessionStatusCallback = new Session.StatusCallback() {
   
 @Override
 public void call(Session session, SessionState state, Exception exception) {
  onSessionStateChange(session, state, exception);
 
 }
};

Also in the onCreate method lets program the buttons login, logout and new publish button. When the user clicks on login button, login dialog will open. when the user is logged in , the login button will be hidden and the logout and publish button will be shown. When user clicks on logout button the session will be closed and the login button will be shown. First add this three lines in your class:

private Button login;
private Button logout;
private Button publishButton;

So now in the onCreate() method add this code:

// login button
login = (Button) findViewById(R.id.loginButton);
login.setOnClickListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
  login.setVisibility(View.GONE);
  connectToFB();
  logout.setVisibility(View.VISIBLE);
  publishButton.setVisibility(View.VISIBLE);

 }
});

// logout button
logout = (Button) findViewById(R.id.logoutButton);
logout.setOnClickListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
  if (currentSession != null) {
   currentSession.closeAndClearTokenInformation();
   logout.setVisibility(View.GONE);
   publishButton.setVisibility(View.GONE);
   login.setVisibility(View.VISIBLE);
  }
 }
});

// publish button
publishButton = (Button) findViewById(R.id.publishButton);
publishButton.setOnClickListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
  publishStory();

 }
});

Don't worry if you have an error on the publishStory() method. We'll write it later.Now we'll update the activity_main.xml and add the publishButton to the layout.

<Button 
        android:id="@+id/publishButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Publish on my wall"
        android:visibility="gone"/>

Now we'll code the publishStory() method:

/**
* Publishes story on the logged user's wall
*/
public void publishStory() {
 Bundle params = new Bundle();
 params.putString("name", "test-name");
 params.putString("caption", "test-caption");
 params.putString("description", "test-description");
 params.putString("link", "http://somewebsite.com");
 params.putString("picture","http://yourimagelink/test.jpg");                                                

 WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(this,currentSession, params))
   .setOnCompleteListener(new OnCompleteListener() {

   @Override
   public void onComplete(Bundle values,FacebookException error) {
    if (error == null) {
     // When the story is posted, echo the success
     // and the post Id.
     final String postId = values.getString("post_id");
     if (postId != null) {
                                           // do some stuff
     } else {
     // User clicked the Cancel button
     Toast.makeText(getApplicationContext(),
       "Publish cancelled", Toast.LENGTH_SHORT).show();
     }
    } else if (error instanceof FacebookOperationCanceledException) {
     // User clicked the "x" button
     Toast.makeText(getApplicationContext(),
      "Publish cancelled", Toast.LENGTH_SHORT).show();
    } else {
     // Generic, ex: network error
     Toast.makeText(getApplicationContext(),
      "Error posting story", Toast.LENGTH_SHORT).show();
    }
   }

  }).setFrom("").build();
 feedDialog.show();

}

Finally add internet permission , your application id and the loginActivity to your AndroidManifest.xml file. the final version of the AndroidManifest.xml file should look like this:

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

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="17" />

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/app_id" />

        <activity
            android:name="com.mende.myfacebookproject.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.facebook.LoginActivity" />
    </application>

</manifest>

Your final MainActivity.class code should look like this:
package com.mende.myfacebookproject;

import java.util.ArrayList;
import java.util.List;

import com.facebook.FacebookException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.Session;
import com.facebook.SessionLoginBehavior;
import com.facebook.SessionState;
import com.facebook.widget.WebDialog;
import com.facebook.widget.WebDialog.OnCompleteListener;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;
import android.content.Intent;

public class MainActivity extends Activity {
 private Session.StatusCallback sessionStatusCallback;
 private Session currentSession;

 private Button login;
 private Button logout;
 private Button publishButton;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // create instace for sessionStatusCallback
  sessionStatusCallback = new Session.StatusCallback() {

   @Override
   public void call(Session session, SessionState state,
     Exception exception) {
    onSessionStateChange(session, state, exception);

   }
  };

  // login button
  login = (Button) findViewById(R.id.loginButton);
  login.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    login.setVisibility(View.GONE);
    connectToFB();
    logout.setVisibility(View.VISIBLE);
    publishButton.setVisibility(View.VISIBLE);

   }
  });

  // logout button
  logout = (Button) findViewById(R.id.logoutButton);
  logout.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    if (currentSession != null) {
     currentSession.closeAndClearTokenInformation();
     logout.setVisibility(View.GONE);
     publishButton.setVisibility(View.GONE);
     login.setVisibility(View.VISIBLE);
    }
   }
  });

  // publish button
  publishButton = (Button) findViewById(R.id.publishButton);
  publishButton.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    publishStory();

   }
  });

 }

 /**
  * Connects the user to facebook
  */
 public void connectToFB() {

  List<String> permissions = new ArrayList<String>();
  permissions.add("publish_stream");

  currentSession = new Session.Builder(this).build();
  currentSession.addCallback(sessionStatusCallback);

  Session.OpenRequest openRequest = new Session.OpenRequest(
    MainActivity.this);
  openRequest.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
  openRequest.setRequestCode(Session.DEFAULT_AUTHORIZE_ACTIVITY_CODE);
  openRequest.setPermissions(permissions);
  currentSession.openForPublish(openRequest);

 }

 /**
  * this method is used by the facebook API
  */
 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (currentSession != null) {
   currentSession
     .onActivityResult(this, requestCode, resultCode, data);
  }
 }

 /**
  * manages the session state change. This method is called after the
  * <code>connectToFB</code> method.
  * 
  * @param session
  * @param state
  * @param exception
  */
 private void onSessionStateChange(Session session, SessionState state,
   Exception exception) {
  if (session != currentSession) {
   return;
  }

  if (state.isOpened()) {
   // Log in just happened.
   Toast.makeText(getApplicationContext(), "session opened",
     Toast.LENGTH_SHORT).show();
  } else if (state.isClosed()) {
   // Log out just happened. Update the UI.
   Toast.makeText(getApplicationContext(), "session closed",
     Toast.LENGTH_SHORT).show();
  }
 }

 /**
  * Publishes story on the logged user's wall
  */
 public void publishStory() {
  Bundle params = new Bundle();
  params.putString("name", "test-name");
  params.putString("caption", "test-caption");
  params.putString("description", "test-description");
  params.putString("link", "http://curious-blog.blogspot.com");
  params.putString("picture",
    "http://somewebsite/test.jpg");

  WebDialog feedDialog = (new WebDialog.FeedDialogBuilder(this,
    currentSession, params))
    .setOnCompleteListener(new OnCompleteListener() {

     @Override
     public void onComplete(Bundle values,
       FacebookException error) {
      if (error == null) {
       // When the story is posted, echo the success
       // and the post Id.
       final String postId = values.getString("post_id");
       if (postId != null) {
        // do some stuff
       } else {
        // User clicked the Cancel button
        Toast.makeText(getApplicationContext(),
          "Publish cancelled", Toast.LENGTH_SHORT)
          .show();
       }
      } else if (error instanceof FacebookOperationCanceledException) {
       // User clicked the "x" button
       Toast.makeText(getApplicationContext(),
         "Publish cancelled", Toast.LENGTH_SHORT)
         .show();
      } else {
       // Generic, ex: network error
       Toast.makeText(getApplicationContext(),
         "Error posting story", Toast.LENGTH_SHORT)
         .show();
      }
     }

    }).setFrom("").build();
  feedDialog.show();

 }
 

}

Your final activity_main.xml should look like this:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/loginButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Login" />

    <Button
        android:id="@+id/logoutButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Logout"
        android:visibility="gone" />
    
    <Button 
        android:id="@+id/publishButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Publish on my wall"
        android:visibility="gone"/>

</LinearLayout>


19 comments:

  1. Nice Post Easy to understand

    ReplyDelete
  2. About logout. In my case, when I go out (logout) and come in soon after it retrieves the previous session. it not redirects me to the login screen. what you think about this?

    (I'm using closeAndClearTokenInformation() for logout)

    ReplyDelete
    Replies
    1. Maybe you should check if you are using single sign on, on facebook. Check the connectToFb() method from the code above, and see if you have added the login behaviour:

      openRequest.setLoginBehaviour(SessionLoginBehavior.SUPPRESS_SSO);

      Also if the above is not the problem, make sure that you are calling closeAndClearTokenInformation() on the active session object.

      If this is not the case, post some code so we can look in to it.

      Delete
  3. My logout and publish button overlap and I am getting Api 100 error when I press on this overlapped button. Err: picture url is not formatted properly

    ReplyDelete
  4. how can I logout in other class?

    ReplyDelete
    Replies
    1. In the activity where you want to logout the user just write the code below:
      Session session = Session.getActiveSession;
      session.closeAndClearTokenInformation();

      Delete
  5. Excellent code ^^
    but how to get user info from this example?
    THANK YOU~

    ReplyDelete
    Replies
    1. Let's assume we have two views in our activity TextView for the name of the user and ProfilePictureView for the profile picture of the user. Yout can define the ProfilePictureView in to your layout like this:

      OPENTAG
      //com.facebook.widget.ProfilePictureView
      // android:id="@+id/selection_profile_pic"
      // android:layout_width="58dp"
      // android:layout_height="58dp"
      // android:layout_marginLeft="24dp"
      // android:layout_marginTop="24dp"
      CLOSETAG

      You can call this from the activity as:

      ProfilePictureView profilePictureView = (ProfilePictureView) findViewById(R.id.selection_profile_pic);

      Ok, that was for the picture.Next you will have to create a method makeMeRequest(final Session session), that will recive the current session:

      private void makeMeRequest(final Session session) {
      // Make an API call to get user data and define a
      // new callback to handle the response.
      Request request = Request.newMeRequest(session,
      new Request.GraphUserCallback() {
      @Override
      public void onCompleted(GraphUser user, Response response) {
      // If the response is successful
      if (session == currentSession) {
      if (user != null) {
      Session.setActiveSession(currentSession);

      // Set the id for the ProfilePictureView
      // view that in turn displays the profile
      // picture.
      profilePictureView.setProfileId(user.getId());
      // Set the Textview's text to the user's name.
      userNameView.setText(user.getName());
      }
      }
      if (response.getError() != null) {
      // Handle errors, will do so later.
      }
      }
      });
      request.executeAsync();
      }

      Here in the method above you can see the "user" object right.If you want additional info from your user, you can call something like user.getBirthday(), user.getFirstName() etc.

      So now that we have the makeMeRequest() method, you will have to call it from onSessionStateChange() method , where you check if the session is open, after
      state.isOpen :

      if(state.IsOpen(){
      makeMeRequest(currentSession);
      }

      Hope this helps

      Delete
  6. On login my app crashes and I get this error. Any idea why this might be happening.
    (server)' ~ Channel is unrecoverably broken and will be disposed!

    ReplyDelete
    Replies
    1. Are you testing the app on the emulator or on a device. Also if you can provide some more info, so we can see when this error occurs.

      Delete
  7. nice work ..thanks a lot dude..

    ReplyDelete
  8. Thanks a lot dude..
    You save my day :3

    ReplyDelete
  9. Thanks a lot for this tutoriel

    ReplyDelete
  10. Hello, this is John. working in a custom facebook application developing company. Your post is very interesting

    ReplyDelete
  11. i am already login with facebook ,so after opening this app , the session has to check i am logged in or not and if yes then i should not get login page

    ReplyDelete
  12. hey how can I use this session in anothert activity? In my logibactivity I logging him yo my system, but in the mainactvity I need to send post status, But I cant do this, dou you know any way for this?

    ReplyDelete