2012-07-11 14 views
16

Estoy creando una nueva aplicación de Android usando SyncAdapter para manejar la sincronización de db. Tengo todo en su lugar y la aplicación funciona bien, pero noté que estoy conectado dos veces.Inicie sesión dos veces al usar SyncAdapters

El primer inicio de sesión tiene lugar cuando la clase AuthenticatorActivity (amplía AccountAuthenticatorActivity) valida el usuario y la contraseña.

Si el usuario y la contraseña son correctos del AuthenticatorActivity luego hace:

  • Si el account no existía lo crea utilizando mAccountManager.addAccountExplicitly()
  • El authToken se guarda utilizando intent.putExtra(AccountManager.KEY_AUTHTOKEN, authToken);

Este fue básicamente copiado/pegado de las muestras de Android, así que supongo que está bien.

La cuestión es que cuando los SyncAdapter lanchas y utiliza

authtoken = mAccountManager.blockingGetAuthToken(account, 
      AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, true); 

El método getAuthToken() dentro de la clase Authenticator que se extiende AbstractAccountAuthenticator se llama. Y dentro de este método estoy golpeando el punto de inicio de sesión una vez más.

A partir de ese momento, el punto final de inicio de sesión no se vuelve a ejecutar hasta que caduque authToken.

Esto no es algo que me molesta mucho, pero me gustaría saber si hay una forma de evitar iniciar sesión dos veces.

+0

¿Qué hay de usar 'AccountManager.setAuthToken()' en lugar de volver a colocar el token en el paquete? – alexanderblom

+0

@alexanderblom: lo intenté también. Ninguna diferencia. – Macarse

+1

Creo que la razón detrás de dos inicios de sesión fue para asegurar que los tokens de autenticación estén actualizados, pero no pude encontrar la fuente que me respalde. Recuerdo haberlo leído en algún lado cuando intenté seguir el ejemplo de C2DM cuando apareció por primera vez el año pasado en Google I/O ... – Yenchi

Respuesta

14

Como hemos visto, sin embargo Authenticator.java en el SampleSyncAdapter dice

Lo interesante que demuestra esta clase es el uso de authTokens como parte del proceso de autenticación. ... Si ya tenemos un authToken almacenado en la cuenta, devolvemos ese authToken. Si no lo hacemos, pero tenemos un nombre de usuario y una contraseña, intentaremos hablar con el servicio de muestra para obtener un authToken.

eso es una mentira. Authenticator.getAuthToken no hace ninguna comprobación de caché, simplemente llega a la red para obtener un token.

La solución es añadir en la falta de verificación:

Authenticator.java: 
@Override 
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, 
     String authTokenType, Bundle loginOptions) throws NetworkErrorException { 

    // check that authToken type supported 
    ... 

    // Check if we already have a cached token to return 
    final AccountManager am = AccountManager.get(mContext); 
    String cachedAuthToken = am.peekAuthToken(account, authTokenType); 
    if (cachedAuthToken != null) { 
     final Bundle result = new Bundle(); 
     result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 
     result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE); 
     result.putString(AccountManager.KEY_AUTHTOKEN, cachedAuthToken); 
     return result; 
    } 

    // Get new authToken from server 
    ... 

    // If all else fails, prompt the user for credentials 
    ... 
} 

Tenga en cuenta que el resto de su proyecto necesita utilizar religiosamente AccountManager.invalidateAuthToken cuando fallan las llamadas o de lo que terminará con un bucle infinito de llamadas que fallan , tratando de obtener un nuevo token de autenticación y luego volviendo a fallar cuando se devuelve el mismo token de autenticación en caché.

+2

Si necesita un ejemplo completo de trabajo, utilicé la misma técnica en mi adaptador de sincronización de muestra para la publicación de mi blog sobre ese tema. Se puede ver el código de aplicación de ejemplo aquí: https://github.com/Udinic/SyncAdapter La entrada de blog acerca de los adaptadores de sincronización aquí: http://udinic.wordpress.com/2013/07/24/ write-your-own-android-sync-adapter/ Específicamente sobre Autenticadores, explicando este problema, puede leer aquí: http://udinic.wordpress.com/2013/04/24/write-your-own- android-authenticator/ – Udinic

+0

en la clase que extiende AccountAuthenticatorActivity, llamo am.setAuthToken (String) y am.setPassword (String). En la clase que extiende AbstractAccountAuthenticator, llamo am.peekAuthToken (account, authTokenType); Esto devuelve null la primera vez. A continuación, inicia sesión utilizando el nombre de usuario de la cuenta y la contraseña guardada en el administrador de cuenta (am.getPassword (cuenta)); Y luego se guarda el authtoken en el administrador de cuenta a través del paquete devuelto por getAuthToken. Alguien sabe por qué am.setPassword() establece con éxito la contraseña, pero am.setAuthToken (String) no? – Ethan

Cuestiones relacionadas