Cómo sincronizar Facebook Login entre Android y nuestro servidor


Hace unas semanas hicimos una introducción a la nueva API de Facebook para Android. Vimos los pasos necesarios para empezar a trabajar con ella y esta semana aprovecharemos lo ya visto para realizar algún ejemplo un poco más complicado.

 
Lo que vamos a implementar es un login con Facebook y vamos a sincronizarlo con nuestro propio servidor, comprobando si nuestro usuario está en nuestro sistema y si no lo está lo damos de alta con los datos que nos dé Facebook. Antes de continuar, si no visteis el anterior artículo de Facebook, es necesario que lo completéis para poder añadir esta librería a vuestro proyecto. La única parte que no es necesaria es la del código de la Activity.

En una pantalla de login como la que ya hemos hecho en el artículo Creando nuestro sistema de registro y login, vamos a añadir un botón que nos permita hacer login con nuestra cuenta de Facebook. Si nuestro email no está registrado en nuestra plataforma, entonces le pediremos a Facebook que nos dé los datos necesarios para poder hacer el registro.

En el artículo Creando nuestro sistema de registro y login(III) aún no habíamos utilizado librerías para crear conexiones HTTP como la que utilizamos en Peticiones HTTP ahora más fáciles, así que os aconsejo que si vais a utilizar el código del login que enlacé antes, hagáis un ejercicio de sustitución por esta librería.

En nuestra App Android


Empezamos incluyendo en la pantalla de login el siguiente código. Simplemente es un fragment que enlaza a la clase ButtonLoginFragment. Debéis sustituir en android:name por el package donde ubiquéis esta clase.


<fragment android:name="aqui.va.el.nombre.de.vuestro.package.ButtonLoginFragment"
          android:id="@+id/LoginFragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />


El siguiente paso es crear la clase ButtonLoginFragment que aparece en el fragment anterior. La clase ButtonLoginFragment es muy simple. Hereda de Fragment y nos devuelve la vista de el siguiente layout que explicaremos, facebook_button.xml. Además instanciamos el botón de login específico de Facebook y le indicamos que pida permiso al usuario para acceder a su email.

Si necesitáis añadir más permisos a vuestra app podéis encontrar aquí más información, https://developers.facebook.com/docs/reference/login/#permissions. Pero tened en cuenta que cuantos más permisos pidáis más reacio será el usuario a dar permisos, así que estad seguros de que necesitáis cada uno de los permisos que incluyáis.


public class ButtonLoginFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle       savedInstanceState) {
     View view = inflater.inflate(R.layout.facebook_button, container, false);
     LoginButton authButton = (LoginButton) view.findViewById(R.id.login_button);
     authButton.setReadPermissions(Arrays.asList("email"));
      
     return view;
   }
}

Después de esto vamos a crear el layout con el botón de login de Facebook, facebook_button.xml.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:orientation="vertical"
              android:gravity="center" android:layout_gravity="center">
    <com.facebook.widget.LoginButton
            android:id="@+id/login_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal|center_vertical"
            android:layout_marginTop="0dp"
            android:layout_marginBottom="0dp" />

</LinearLayout>


Como veis no tiene mayor complicación. Un LinearLayout para meter dentro el widget del LoginButton que nos proporciona el SDK de Facebook. Ahora veamos como queda la activity que gestiona la pantalla de login. Veremos únicamente la parte que gestiona el login de Facebook para no complicarlo demasiado. Debéis cambiar además la herencia de vuestra Activity a FragmentActivity quedando extends FragmentActivity.


private boolean try_login_facebook = true;
private UiLifecycleHelper uiHelper;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login);
       
    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);

}


Empezamos definiendo un booleano y una interface que nos ayudará en el ciclo de vida del login de Facebook. Y en el onCreate a parte de llamar al layout login, inicializamos la interface.


private Session.StatusCallback callback =  new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        if (state.isOpened()) {                    
        } else if (state.isClosed()) {
       
        }
   }
};
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
     super.onActivityResult(requestCode, resultCode, data);
     uiHelper.onActivityResult(requestCode, resultCode, data);
 }



El siguiente paso es definir callback que si os fijáis se le pasó a uiHelper en el onCreate. Esto nos permitirá actuar cuando el estado de la sesión de Facebook cambie. Y además en el onActivityResult lanzamos el método del mismo nombre de uiHelper para que realice las operaciones necesarias.


La parte importante viene ahora, en el onResumeFragments. Aquí se obtiene el objeto Session de Facebook y se comprueba si no es nula y está activa. Además utilizo una bandera, try_login_facebook, porque se puede estar ejecutando múltiples veces este método y así evitamos que haga peticiones innecesarias.


El método facebookLogin simplemente va a obtener el token que nos da Facebook y lo vamos a enviar a nuestro servidor web para hacer su parte del proceso de autenticación. Fijaros que si da un fallo la conexión con el servidor ejecuto el método closeAndClearTokenInformation. Además se está utilizando la librería que ya se explicó en Peticiones HTTP ahora más fáciles para hacer la conexión.


@Override
protected void onResumeFragments() {
   super.onResumeFragments();  
 
   final Session session = Session.getActiveSession();
   if (session != null && session.isOpened()) {
       if(try_login_facebook){    
           try_login_facebook = false;
           facebookLogin(session);
       }    
   } 
}

public void facebookLogin(final Session session){
  
  
  AsyncHttpClient client = new AsyncHttpClient();
  RequestParams rp = new RequestParams();
  
  rp.put("token", session.getAccessToken());
  rp.put("tag", "login.facebook");                
  
  client.post("url de nuestro servicio web", rp, new AsyncHttpResponseHandler(){
   @Override
   public void onSuccess(String response){             
    //Aquí ha vuelto del proceso de login, hay que verificar en la respuesta si tuvo éxito o no
     
         
   }
   @Override
   public void onFailure(Throwable throwable){ 
    session.closeAndClearTokenInformation();
   }
  });
}


Si quisierais obtener información del usuario debéis hacer una petición de este estilo en el lugar donde estamos llamando al método facebookLogin. Simplemente se hace una petición a Facebook para que nos dé los datos requeridos. Acordaros que este es un proceso asíncrono y debemos tratar estos datos en el onCompleted. Algo muy parecido lo vimos cuando integramos el SDK de Facebook en Android.


Request request = Request.newMeRequest(session, new Request.GraphUserCallback() {

    @Override
    public void onCompleted(GraphUser user, Response response) {
          
        if (session == Session.getActiveSession()) {
            if (user != null) {
             //Aquí con el objeto user podemos obtener datos del usuario logado
            }
        }
        if (response.getError() != null) { session.closeAndClearTokenInformation(    ); }}});
request.executeAsync();


EN NUESTRO SERVIDOR WEB



La última parte la debemos hacer en un servidor web y como siempre la hago en PHP. Ya hemos visto otras veces como realizar estos procesos y no es muy complejo. Simplemente le hemos enviado desde la aplicación Android un tag para decirle que vamos a hacer un login con Facebook y le pasamos también el token.


public function facebookLogin($token){
    $url = "https://graph.facebook.com/me?access_token=". $token;
    $json = @file_get_contents($url);

    if($json != false){
        $e = json_decode($json, true);

        $email = $e["email"];
        $name = $e["name"];
        $username = $e["username"];
        if($this->isUserExisted($email) == false){
            $this->registerUser($username, $name, $email );
        }
        $response = array("success" => "1");
    } else {
        $response = array("success" => "0");
    }
    return json_encode($response);
}


El método que finalmente se debe llamar en nuestro servicio web será facebookLogin y simplemente va a hacer una petición a Facebook con el token para que le devuelva la info del usuario. Esto nos tiene que devolver un json si se ha encontrado al usuario. Podéis probar a llamarlo desde un navegador para que veáis que aspecto tiene y que datos trae. Después obtenemos los datos que nos ha dado Facebook, en nuestro caso necesitamos el email, nombre y nombre de usuario.


Buscamos en nuestro servidor el usuario por email con isUserExisted y si no existe lo registramos con registerUser. Podéis revisar el artículo Creando nuestro sistema de registro y login en Android (II), encontrareis el método isUserExisted y la parte que registra un usuario la podéis meter en el método registerUser para que os sea más fácil utilizar en ambos sitios.


Por último, se envía una respuesta indicando si el proceso ha tenido éxito o no. Esta la debemos evaluar en nuestra app Android. En este punto según queráis enfocar vuestra aplicación podéis navegar a otra pantalla, guardar en el terminal una determinada información o lo que vosotros necesitéis. Lo importante es que hemos conseguido hacer login en nuestro terminal con las credenciales de Facebook y además hemos sincronizado estos datos con nuestro servidor.

Comments are closed.