Facebook SDK pour Android – bug du SSO



Mettre du social dans ses applications Android c’est bien, et c’est encore mieux quand c’est ergonomique. C’est la promesse du sdk Facebook pour Android et sa fonctionnalité SSO (Single Sign On, ie ne montrez patte blanche qu’une fois).
Si l’utilisateur a installé l’application Facebook sur son terminal et y a configuré son compte Facebook, alors il pourra se connecter à Facebook dans notre super application sans avoir à répéter son identifiant et mot de passe Facebook.

C’est super, mais parfois, la connexion ne se fait pas. Et pour peu que votre smartphone Android soit un peu âgé, c’est systématique. Il est alors impossible de se connecter à Facebook dans notre super appli !

 

Debuggage

Long et ardu, et donc encore plus a expliquer. On passe tout de suite à l’EXPLICATION !

L’explication

Les variables d’instance mAuthActivityCode, mAuthDialogListener, mAuthActivity,   mAuthPermissions ne sont pas initialisées lorsqu’elles sont utilisées dans la méthode authorizeCallback.
Pourtant toutes ces variables ont été initialisées lors de l’appel à la méthode authorize, juste avant de démarrer l’activity de l’application officielle Facebook !

Oui, mais ce n’était pas le même instance de la classe Facebook !
En effet, notre activity passée alors en arrière plan a été décrétée trop encombrante par Android, il l’a tuée ; et l’objet Facebook bien initialisé a fini dans le GC
(cf Android developers – tasks and back stack Note: Multiple tasks can be held in the background at once. However, if the user is running many background tasks at the same time, the system might begin destroying background activities in order to recover memory, causing the activity states to be lost. See the following section about Activity state.).
Ainsi, au retour, notre activity a été recrée, et avec elle, une nouvelle instance de la classe Facebook, toute neuve : non initialisée.

Rustine

Un moyen simple de résoudre ce problème est d’initialiser mAuthActivityCode, mAuthDialogListener, mAuthActivity,  mAuthPermissions au moment de la création de l’instance Facebook, plutôt que lors de l’appel à authorize. Comme c’est fait là :

import android.app.Activity;
import android.content.Intent;

import com.facebook.android.Facebook;

/*
 Turn around the Facebook authorizeCallBack bug.
*
* @author HoodBrains
*
/
public class HBFacebook extends Facebook {

//TODO: change visibility to protected in mother class
//      com.facebook.android.Facebook for members:
//
//    protected Activity mAuthActivity;
//    protected String[] mAuthPermissions;
//    protected int mAuthActivityCode;
//    protected DialogListener mAuthDialogListener;

   //HB
   private boolean isReadyForAuth = false;

   /*
    * Constructor for Facebook object.
    * Set all required callbacks for SSO.
    *
    * @param appId
    *          Your Facebook application ID. Found at
    *          www.facebook.com/developers/apps.php .
    * @param activity
    *            The Android activity in which we want to display the
    *            authorization dialog.
    * @param permissions
    *            A list of permissions required for this application: e.g.
    *            "read_stream", "publish_stream", "offline_access", etc. see
    *            http://developers.facebook.com/docs/authentication/permissions
    *            This parameter should not be null -- if you do not require any
    *            permissions, then pass in an empty String array.
    * @param activityCode
    *            Single sign-on requires an activity result to be called back
    *            to the client application -- if you are waiting on other
    *            activities to return data, pass a custom activity code here to
    *            avoid collisions. If you would like to force the use of legacy
    *            dialog-based authorization, pass FORCE_DIALOG_AUTH for this
    *            parameter. Otherwise just omit this parameter and Facebook
    *            will use a suitable default. See
    *            http://developer.android.com/reference/android/
    *              app/Activity.html for more information.
    * @param listener
    *            Callback interface for notifying the calling application when
    *            the authentication dialog has completed, failed, or been
    *            canceled.
    *            
    * @author HoodBrains
    /
   public HBFacebook(String appId,
              Activity activity,
              String[] permissions,
              int activityCode,
              DialogListener listener) {
       super(appId);
       mAuthActivity = activity;
       mAuthPermissions = permissions;
       mAuthActivityCode = activityCode;
       mAuthDialogListener = listener; 

       isReadyForAuth = true;
   }

   /*
    * Constructor with default activity code.
    * See HBFacebook above for full help.
    *  
    /
   public HBFacebook(String appId,
              Activity activity,
              String[] permissions,
              DialogListener listener) {
       this(appId, activity, permissions, DEFAULT_AUTH_ACTIVITY_CODE, listener);
   }

   /*
    * Authorize method. All required informations
    * have been set in the constructor.
    /
   public void authorize() {

       if (!isReadyForAuth) {
           throw new  RuntimeException("Not correctly initialized for authorize process.");
       }
       super.authorize(mAuthActivity,
               mAuthPermissions,
               mAuthActivityCode,
               mAuthDialogListener);
   }

   /*
    * Check that this where correctly initialized.
    */
   public void authorizeCallback(int requestCode, int resultCode, Intent data) {
       if (!isReadyForAuth) {
           throw new  RuntimeException("Not correctly initialized for " +
                   "authorize process.");
       }
       super.authorizeCallback(requestCode, resultCode, data);
   }

}

It Wöks

Même sur les vieux smartphones Android. Et même quand on a pas de chance.

Il ne reste plus qu’à trouver un cas ou l’intent share ne suffit pas !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>