Facebook documentation focuses on the point that applications accessing user’s data from Facebook should not ask for any permission they are not going to make use of (especially publish_stream
and offline_access
). Here’s a quote from a Facebook document:
Depending on your application’s needs, you may need additional permissions from the user. A large number of calls do not require any additional permissions, so you should first make sure you need a permission. This is a good idea because this step potentially adds friction to the user’s process. Another point to remember is that this call can be made even after the user has first connected. So you may want to delay asking for permissions until as late as possible.
However, while working on an Android application that uses the Facebook SDK, I couldn’t find good documentation on how to do this. Here’s what I have been able to come up with by reading the code in sample Facebook applications in the SDK.
Let us first define what permissions we are going to need.
// List of additional write permissions being requested
private static final List<String> PERMISSIONS = Arrays.asList("publish_stream, publish_actions");
// Request code for reauthorization requests.
private static final int REAUTH_ACTIVITY_CODE = 100;
// Flag to represent if we are waiting for extended permissions
private boolean pendingAnnounce = false;
As you might have guessed from the permissions, we would be publishing some thing to user’s wall. Lets call this method that handles the sesison as publishAnnounce
. We add our activity as the session callback for Facebook session updates. You can pass objects of any class that implements StatusCallback
. We will see more about this later. Here’s what publishAnnounce
would look like.
private void handleAnnounce() {
pendingAnnounce = false;
Session session = Session.getActiveSession();
if (session == null || !session.isOpened()) {
return;
}
List<String> permissions = session.getPermissions();
if (!permissions.containsAll(PERMISSIONS)) {
pendingAnnounce = true; // Mark that we are currently waiting for confirmation of publish permissions
session.addCallback(this);
requestPublishPermissions(this, session, PERMISSIONS, REAUTH_ACTIVITY_CODE);
return;
}
// TODO: Publish the post. You would need to implement this method to actually post something
publishMessage();
}
void requestPublishPermissions(Activity activity, Session session, List<String> permissions,
int requestCode) {
if (session != null) {
Session.ReauthorizeRequest reauthRequest = new Session.ReauthorizeRequest(activity, permissions)
.setRequestCode(requestCode);
session.reauthorizeForPublish(reauthRequest);
}
}
We first checked if we had all the required permissions. If not, we create a new ReauthorizeRequest with the set of permissions that we are requesting. This guides user outside our app to either the Facebook app or browser to confirm the permissions. When the user confirms the requests, he is redirected back to our application and onActivityResult
for the Activity that invoked the reauthorization request is called. Let us see how it would look like:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REAUTH_ACTIVITY_CODE:
Session session = Session.getActiveSession();
if (session != null) {
session.onActivityResult(this, requestCode, resultCode, data);
}
break;
}
}
All we need to do here is to pass the result to the active Facebook session. This processes the result and calls the onSessionStateChanged
if the session state changes. We then check in that method if our token was successfully updated and try to publish the message again.
protected void onSessionStateChange(final Session session, SessionState state, Exception exception) {
if (session != null && session.isOpened()) {
if (state.equals(SessionState.OPENED_TOKEN_UPDATED)) {
// Session updated with new permissions
// so try publishing once more.
tokenUpdated();
}
}
}
/**
* Called when additional permission request is copmleted successfuly.
*/
private void tokenUpdated() {
// Check if a publish action is in progress
// awaiting a successful reauthorization
if (pendingAnnounce) {
// Publish the action
handleAnnounce();
}
}
EDIT: For the new SDK(3.0.1), I have the following:
public static void requestPublishPermissions(Activity activity, Session session, List<String> permissions,
int requestCode) {
if (session != null) {
Session.NewPermissionsRequest reauthRequest = new Session.NewPermissionsRequest(activity, permissions)
.setRequestCode(requestCode);
session.requestNewPublishPermissions(reauthRequest);
}
}
public static void requestReadPermissions(Activity activity, Session session, List<String> permissions,
int requestCode) {
if (session != null) {
Session.NewPermissionsRequest reauthRequest = new Session.NewPermissionsRequest(activity, permissions)
.setRequestCode(requestCode);
session.requestNewReadPermissions(reauthRequest);
}
}