Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android FacebookSDK login with native Facebook app installed asks for permissions even after the user have already given them

Condition: Android device with native Facebook apk installed but logged out.

Every time this condition is met and the user tries to login using either Facebook's LoginButton or doing it manually (see below), after logged in, the Facebook SDK always asks for permission to access the user data, even if the user has already given permission.

Here is the code I'm implementing on my application:

Version 1 - Login Button:

XML:

<com.facebook.widget.LoginButton
    android:id="@+id/login_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Java:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");
private UiLifecycleHelper uiHelper;

@Override
protected void onCreate(Bundle savedInstanceState){
    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);
    loginButton = (LoginButton) findViewById(R.id.login_button);
    loginButton.setReadPermissions(PERMISSIONS);
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

Version 2 - Manually

XML:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/button"
    android:onClick="buttonOnClick"
    android:text="Login" />

Java:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");

public void buttonOnClick(View v) {
    System.out.println("botaoOnClick");
    Session session = Session.getActiveSession();
    if (!session.isOpened() && !session.isClosed()) {
        System.out.println("session: " + session);
        session.openForRead(new Session.OpenRequest(this).setPermissions(PERMISSIONS).setCallback(callback));
    }
    else {
        Session.openActiveSession(this, true, callback);
    }
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

Even the sample apps that come with sdk works this way, but I have already seen some other apps (eg. Foursquare) working the way I think is the natural behavior (only asks for permissions if the user hasn't already given them).

So, does anyone know a way to achieve the desired result? Preferably without editing the Facebook SDK itself.

Thanks in advance!

Edit 1: Additional information: upon checking the session variable on the callback method, the permissions always come empty when the condition above is met. If the user refuses to give permission (not for the first time), and tries to login again, the session comes with the permissions the user already gave some time in the past, as expected.

Edit 2 (on 2013-06-28): I've decided to upload a video reproducing the issue, since I am not so sure everyone understood what I've meant in my explanation.

Link here: http://www.youtube.com/watch?v=w4qJfoiVSsU

like image 410
Claudio Freitas Avatar asked Jun 07 '13 15:06

Claudio Freitas


People also ask

Why does Facebook need phone permission?

These permissions allow you to import your phone's contacts to Facebook and sync your Facebook contacts to your phone. This allows you to see your Facebook events in your phone's calendar. This allows the app to show your calendar availability (based on your phone's calendar) when you're viewing an event on Facebook.

How do I allow app permissions on Facebook?

Tap in the top right of Facebook. Scroll down and tap Settings. Go to the Permissions section and tap Apps and Websites. Go to Apps, Websites and Games and tap Edit.

Where do I find my Facebook permissions?

Access PermissionsLog in to your account and click the drop-down arrow at the far right of the screen at the top. Click “Privacy Settings.” Click “Edit Settings” next to Apps and Websites to view management options for the apps you currently use or have used.


1 Answers

Thats probably because you got a signature mismatch between your app (which I assume is in debug mode) and your facebook app associated to your appID.

Basically you should make sure that:

  1. The signature of your android app that use the facebook sdk is added to the facebook app dashboard Facebook App Dashboard you can easily get your app signature by using keytool or by adding this code in your activity's onCreate method :

    @Override
    protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    
    try {
        PackageInfo info = getPackageManager().getPackageInfo(
                getPackageName(), 
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.d("TAG", "Hash to copy ==> "+ Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
    } catch (NameNotFoundException e) {
    
    } 
    catch (NoSuchAlgorithmException e) {
    
    }
    }
    
  2. Facebook Login checkbox is Enabled

  3. If your not enabling sandbox mode you need to choose a category from the app detail page

  4. By default the loginbutton use the SingleSignOn loginbehavior, which will basically log you in as the owner of the facebook app, I suggest you to use the one that allow any user to log on in behalf of your facebook app. To do so, just add this line after you set the permission to the login button:

    loginButton.setReadPermissions(PERMISSIONS);
    loginButton.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
    

If you still having troubles, I suggest you to read this doc troubleshooting facebook login

PS: And FYI, If you use UiLifecycleHelper, don't forget to override the main activity/fragment lifecycle methods, and forward the calls to the UiLifecycleHelper as stated in the javadoc.

When using this class, clients MUST call all the public methods from the * respective methods in either an Activity or Fragment. Failure to call all the * methods can result in improperly initialized or uninitialized Sessions.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onResume() {
    super.onResume();
    uiHelper.onResume();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

@Override
protected void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    uiHelper.onActivityResult(requestCode, resultCode, data);
}
like image 158
Gomino Avatar answered Sep 21 '22 05:09

Gomino