22

I am developing an Android App that integrates with Facebook. I would like to:

  1. Let the user login with Facebook
  2. Get the user's email address on Facebook (could be a proxied email address, which is fine)
  3. Post to the user's wall/timeline on his/her behalf

Technically, that would be to:

  1. Authenticate the user
  2. Request the email permission
  3. Request the publish_stream permission

1. Authenticate the user

I called Session.openActiveSession() with a Session.StatusCallback (I already checked that there is no active opened session beforehand):

final Session.StatusCallback sessionStatusCallback = new Session.StatusCallback() {
    public void call(final Session session, SessionState state, Exception exception) {
        // If there is an exception...
        if(exception != null)
        {
            // Handle fail case here.
            return;
        }

        // If session is just opened...
        if(state == SessionState.OPENED)
        {
            // Handle success case here.
            return;
        }
    };
};

// Start Facebook Login.
Session.openActiveSession(activity, true, sessionStatusCallback);

My callback is called after successful login. So far so good.

2. Request the email permission

This is my status callback:

new Session.StatusCallback() {
    public void call(final Session session, SessionState state, Exception exception) {
        // If there is an exception...
        if(exception != null)
        {
            // Handle fail case here.
            return;
        }
        
        // If token is just updated...
        if(state == SessionState.OPENED_TOKEN_UPDATED)
        {
            // Handle success case here.
            return;
        }
    };
};

I request the permission with Session.requestNewReadPermissions():

final Session session = Session.getActiveSession();
final static String[] PERMISSION_ARRAY_READ = {"email"};
final List<String> permissionList = Arrays.asList(PERMISSION_ARRAY_READ);

// If all required permissions are available...
if(session.getPermissions().containsAll(permissionList))
{
    // Handle success case here.
    return;
}

// Request permissions.
session.requestNewReadPermissions(new Session.NewPermissionsRequest(activity, permissionList));

My callback is called after permission is granted. So far so good.

3. Request the publish_stream permission

This is my status callback:

new Session.StatusCallback() {
    public void call(final Session session, SessionState state, Exception exception) {
        // If there is an exception...
        if(exception != null)
        {
            // Handle fail case here.
            return;
        }
        
        // If token is just updated...
        if(state == SessionState.OPENED_TOKEN_UPDATED)
        {
            // Handle success case here.
            return;
        }
    };
};

I request the permission with Session.requestNewPublishPermissions():

final Session session = Session.getActiveSession();
final static String[] PERMISSION_ARRAY_PUBLISH = {"publish_stream"};
final List<String> permissionList = Arrays.asList(PERMISSION_ARRAY_PUBLISH);

// If all required permissions are available...
if(session.getPermissions().containsAll(permissionList))
{
    // Handle success case here.
    return;
}

// Request permissions.
session.requestNewPublishPermissions(new Session.NewPermissionsRequest(activity, permissionList));

This time, my callback is not called after permission is granted.

Investigation

Upon further investigation, I found that my callback is triggered by com.facebook.Session#postStateChange(SessionState, SessionState, Exception):

void postStateChange(final SessionState oldState, final SessionState newState, final Exception exception) {
    if (oldState == newState && exception == null) {
        return;
    }

    /* ... */
}

Since oldState and newState are equal (both being SessionState.OPENED_TOKEN_UPDATED, my callback is not called.

Question

How can I receive any notification after permission is granted for the 2nd time? Am I supposed to close() the session and re-open it from cache?

Additional info

My Facebook Android SDK 3.0 is download from here, which is stated in Facebook's Getting Started with the Facebook SDK for Android.

Community
  • 1
  • 1
Pang
  • 9,564
  • 146
  • 81
  • 122

3 Answers3

10

This is a bug.

[edit: As Guy points out in comments, this was fixed in 3.0.1, so this workaround is no longer necessary]

The workaround you mention is basically correct, though you do not need to call close. If you are using the single active session, before calling requestNewPublishPermissions() just call:

Session.openActiveSessionFromCache(myContext);

If you are using multiple sessions, you need to initialize a new Session with the TokenCachingStrategy, verify it is in the CREATED_TOKEN_LOADED state, and call openForRead(null);

After doing one of these, requestNewPublishPermissions() should call your notification once it completes.

rightparen
  • 1,693
  • 10
  • 15
  • 2
    I've put together a couple of articles ([here](http://adilatwork.blogspot.co.uk/2013/02/facebook-android-sdk-30-opening-session.html) and [here](http://adilatwork.blogspot.co.uk/2013/02/facebook-android-sdk-30-requesting.html)) which take @rightparen's workaround intro consideration and fully explain getting started opening a Facebook session and requesting additional permissions. – Adil Hussain Feb 28 '13 at 21:57
  • In the latest FB SDK 3.0.1 this does not happen anymore, and there is no longer a need to call `openActiveSessionFromCache` – Guy Apr 17 '13 at 09:39
  • I have the latest 3.0.1 and I even tried adding this line, and nothing. I don't get the call back, but If I check the permission afterwards it works.Drives me insane – Kirill Kulakov Aug 08 '13 at 16:24
  • Hey, I am getting similar issue. Can you please tell me where can i exactly put the line of code ? There is no method `requestNewPublishPermissions()` used in my code. So i am bit confused. Please guide me. – GrIsHu Feb 21 '14 at 07:08
2

Working code based on rightparen's answer

Before requesting permission for the 2nd time (i.e. before Session.requestNewPublishPermissions()), do this:

// Re-initialize Facebook session.
session.removeCallback(sessionStatusCallback);          // Remove callback from old session.
session = Session.openActiveSessionFromCache(context);  // Create new session by re-opening from cache.
session.addCallback(sessionStatusCallback);             // Add callback to new session.

Code is still based on Facebook Android SDK 3.0, as in the question.

Community
  • 1
  • 1
Pang
  • 9,564
  • 146
  • 81
  • 122
0

Another thing I ran into was that my requestCode for the NewPermissionRequest was not being set to the same requestCode that I used to open my Session for Read with, thereby my Session.StatusCallback was never being invoked when the new permissions have been granted.

For instance, in my onActivityResult I have a check for the requestCode and delegate the call accordingly because I have other stuff coming in to this method.

public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
    if (requestCode == FACEBOOK_AUTH_RESULT_CODE) {
        Session session = Session.getActiveSession();
        if(session != null) {
            session.onActivityResult(activity, requestCode, resultCode, data);
        }
    }       
}

I then opened my Session with the following code :

        Session.getActiveSession().openForRead(
            new Session.OpenRequest(activity).
                setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK).
                setRequestCode(FACEBOOK_AUTH_RESULT_CODE).
                setPermissions(MY_READ_PERMISSIONS));

I then forgot to use the same requestCode when constructing my NewPermissionRequest.

This is what the correct NewPermissionRequest needs to look like :

        Session.getActiveSession().requestNewPublishPermissions(
            new NewPermissionsRequest(activity, MY_PUBLISH_PERMISSIONS)
                .setRequestCode(FACEBOOK_AUTH_RESULT_CODE));
Akos Cz
  • 12,711
  • 1
  • 37
  • 32