¿Cómo utilizar correctamente Google Plus Iniciar sesión con múltiples actividades?

¿Cuál sería una buena o recomendable forma de enlazar el ciclo de vida del cliente api de Google+ con el flujo de una aplicación multiactividad? Hacer que las actividades dependan del método del cliente apC onConnected para activar su funcionalidad, utilizarlo como una cosa de "activación" de una sola vez, o quizás otra cosa completamente?

Actualmente estoy luchando por entender cómo usar correctamente el inicio de sesión de Google+ en mi aplicación de Android, que tiene más de una actividad.

La idea es, en una primera fase, usar el signo de G + solo para autenticar al usuario y poder recibir su correo electrónico, enviar notificaciones y cosas por el estilo. Eventualmente, planeo implementar otras funcionalidades de Google como quizás Maps u otros servicios de Google Play, así que creo que es útil implementarlo ya.

Sin embargo, mi aplicación no se comporta como se esperaba, y he reducido el problema al hecho de que todavía no he entendido el signo de G + en el ciclo de aplicación cuando hay más de una actividad presente.

¿Cuál es la forma correcta o recomendada para implementar este método de autenticación? ¿Hay quizá un patrón de las clases que podrían dirigirme en la dirección correcta?

Por ejemplo, he encontrado un diagrama muy simple del ciclo de vida del cliente api , pero ¿cómo se relaciona esto con el flujo de la aplicación?

Inicialmente tengo una actividad de inicio de sesión, donde puse el botón de inicio de sesión. Siguiendo la guía de Google , puedo iniciar sesión y cuando se llama al método onConnected, comienzo la actividad principal (como el panel o la pantalla principal de la aplicación).

Esto funciona algo. Por ejemplo, ¿cuál sería una buena manera de manejar el onStart y onStop para cada actividad? ¿Debo volver a conectar y volver a autenticar el cliente api cada vez para cada actividad? Así que tal vez es una buena idea tener una BaseActivity para implementar todo esto.

Otro problema es, ¿debo usar el mismo objeto de cliente api y pasarlo de alguna manera, o tal vez almacenarlo en la clase de actividad base? O debería estar creando e inicializando un nuevo objeto de cliente api cada vez?

¿Qué tal si solo utilizas la Actividad de inicio de sesión para autenticar con G + y luego simplemente recibir el correo electrónico y almacenarlo en una base de datos local, y marcar al usuario como "autenticado" o "activo" o algo así. Eso evitaría que tuviera que volver a autenticar cada vez que se cierra la aplicación o se suspende la conexión, incluso permitiendo algunos ahorros de la batería.

La aplicación no está realmente utilizando G + publicación o cualquier otra funcionalidad como esa. Lo ideal sería que funcionara bien fuera de línea y sólo necesitaría conexión para cosas como autenticación inicial u otras cosas únicas.

Cualquier sugerencia o puntero en la dirección correcta es muy apreciada.

Edit: He leído todas las guías y tutoriales que he encontrado, que utilizan Google+, y cada uno de ellos aborda esto desde una sola perspectiva de actividad. Yo creo que este es un problema bastante común que se beneficiaría de un patrón o por lo menos una pauta general.

Reconectar para cada actividad es absolutamente bien. Generalmente hay 3 maneras que he visto de la gente que aplica esto:

  1. Implementar principalmente en una base de actividad, y hacer que los demás ampliar. Esto es conectar / desconectar en cada actividad, pero con código en un solo lugar.
  2. Implementar conectar / desconectar en un fragmento, e incluirlo en actividades donde se necesita autenticación. Esto es útil si ya tiene una base que no puede extender (por ejemplo, algunos casos de juegos).
  3. Implementar un servicio para conectar / desconectar. Esto puede disparar un broadcastintent o similar si es necesario iniciar sesión.

Todos estos trabajos, y he visto todos ellos utilizados en aplicaciones del mundo real. Lo más importante a recordar es separar la lógica del 99% (el usuario está firmado o firmado y se le está informando) del relativamente raro caso de "inicio de sesión en este momento". Por ejemplo, es posible que onConnected / onConnection no haya disparado mucho, pero la mayoría de las veces está ignorando o simplemente volteando un poco el estado de la aplicación. Sólo en una pantalla con un botón de inicio de sesión necesita la resolución del resultado de la conexión y el elemento onActivityResult. Piense en la conexión de servicios de Google Play como la mayoría de las preguntas sobre el estado del usuario, en lugar de firmarlas, y debería estar bien.

Estoy de acuerdo con la respuesta de Ian Barber, pero para explicar un poco más, su Activity debe considerarse en dos tipos – Activity s que resuelven el inicio de sesión, y Activity que requieren la firma.

La mayoría de las Activity no se preocupan por autenticar al usuario y tendrán la misma lógica en su aplicación. Se creará un GoogleApiClient , que se conecta al proceso de servicios de Google Play que se ejecuta en el dispositivo y lee el estado de inicio de sesión en caché del usuario – devolver onConnected() si el usuario está onConnectionFailed() y onConnectionFailed() si no. La mayoría de sus Activity s desea restablecer el estado de la aplicación e iniciar su LoginActivity si el usuario no ha LoginActivity . Cada Activity debe mantener su propia instancia de GoogleApiClient ya que es un objeto ligero que se utiliza para acceder al estado compartido de Google Play Servicios. Este comportamiento podría, por ejemplo, estar encapsulado en una clase BaseActivity compartida o una clase SignInFragment compartida, pero cada instancia debería tener su propia instancia de GoogleApiClient .

Sin LoginActivity su LoginActivity debe implementarse de manera diferente. También debe crear un GoogleApiClient , pero cuando recibe onConnected() indicando que el usuario está onConnected() , debe iniciar una Activity adecuada para el usuario y finish() . Cuando su LoginActivity recibe onConnectionFailed() indicando que el usuario no ha LoginActivity onConnectionFailed() , debe intentar resolver los problemas de inicio de sesión con startResolutionForResult() .

0. TL; DR

Para el codificador impaciente, una versión de trabajo de la siguiente aplicación se puede encontrar en GitHub .

Después de volver a escribir el código de actividad de inicio de sesión varias veces en muchas aplicaciones diferentes, la solución fácil (y no tan elegante) fue crear el cliente de API de Google como un objeto de clase de aplicación. Pero, dado que el estado de la conexión afecta el flujo de UX, nunca fui feliz con este acercamiento.

Reduciendo nuestro problema sólo al concepto de conexión , podemos considerar que:

  1. Oculta el cliente de la API de Google.
  2. Tiene estados finitos.
  3. Es un (más bien) único.
  4. El estado actual afecta el comportamiento de la aplicación.

1. Patrón de Proxy

Puesto que la Connection encapsula GoogleApiClient , implementará ConnectionCallbacks y OnConnectionFailedListener :

 @Override public void onConnected(Bundle hint) { changeState(State.OPENED); } @Override public void onConnectionSuspended(int cause) { changeState(State.CLOSED); connect(); } @Override public void onConnectionFailed(ConnectionResult result) { if (currentState.equals(State.CLOSED) && result.hasResolution()) { changeState(State.CREATED); connectionResult = result; } else { connect(); } } 

Las actividades pueden comunicarse con la clase Connection a través de los métodos connect , disconnect y revoke , pero sus comportamientos son decididos por el estado actual. La máquina de estado requiere los siguientes métodos:

 protected void onSignIn() { if (!googleApiClient.isConnected() && !googleApiClient.isConnecting()) { googleApiClient.connect(); } } protected void onSignOut() { if (googleApiClient.isConnected()) { Plus.AccountApi.clearDefaultAccount(googleApiClient); googleApiClient.disconnect(); googleApiClient.connect(); changeState(State.CLOSED); } } protected void onSignUp() { Activity activity = activityWeakReference.get(); try { changeState(State.OPENING); connectionResult.startResolutionForResult(activity, REQUEST_CODE); } catch (IntentSender.SendIntentException e) { changeState(State.CREATED); googleApiClient.connect(); } } protected void onRevoke() { Plus.AccountApi.clearDefaultAccount(googleApiClient); Plus.AccountApi.revokeAccessAndDisconnect(googleApiClient); googleApiClient = googleApiClientBuilder.build(); googleApiClient.connect(); changeState(State.CLOSED); } 

2. Patrón de estado

Este es un patrón de comportamiento que permite a un objeto alterar su comportamiento cuando cambia su estado interno. El libro de patrones de diseño de GoF describe cómo una conexión TCP puede ser representada por este patrón (que también es nuestro caso).

Un estado de una máquina de estado debe ser un singleton , y el más fácil de hacerlo en Java fue crear Enum denominado State siguiente manera:

 public enum State { CREATED { @Override void connect(Connection connection) { connection.onSignUp(); } @Override void disconnect(Connection connection) { connection.onSignOut(); } }, OPENING {}, OPENED { @Override void disconnect(Connection connection) { connection.onSignOut(); } @Override void revoke(Connection connection) { connection.onRevoke(); } }, CLOSED { @Override void connect(Connection connection) { connection.onSignIn(); } }; void connect(Connection connection) {} void disconnect(Connection connection) {} void revoke(Connection connection) {} 

La clase Connection contiene el contexto, es decir, el estado actual, que define cómo se connect , disconnect y revoke los métodos de Connection , se comportarán:

 public void connect() { currentState.connect(this); } public void disconnect() { currentState.disconnect(this); } public void revoke() { currentState.revoke(this); } private void changeState(State state) { currentState = state; setChanged(); notifyObservers(state); } 

3. Patrón Singleton

Puesto que no hay necesidad de recrear esta clase repetidamente, lo proveemos como un singleton:

 public static Connection getInstance(Activity activity) { if (null == sConnection) { sConnection = new Connection(activity); } return sConnection; } public void onActivityResult(int result) { if (result == Activity.RESULT_OK) { changeState(State.CREATED); } else { changeState(State.CLOSED); } onSignIn(); } private Connection(Activity activity) { activityWeakReference = new WeakReference<>(activity); googleApiClientBuilder = new GoogleApiClient .Builder(activity) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(Plus.API, Plus.PlusOptions.builder().build()) .addScope(new Scope("email")); googleApiClient = googleApiClientBuilder.build(); currentState = State.CLOSED; } 

4. Patrón observable

La clase Connection extiende Java Observable , por lo que una o más actividades pueden observar los cambios de estado:

 @Override protected void onCreate(Bundle bundle) { connection = Connection.getInstance(this); connection.addObserver(this); } @Override protected void onStart() { connection.connect(); } @Override protected void onDestroy() { connection.deleteObserver(this); connection.disconnect(); } @Override protected void onActivityResult(int request, int result, Intent data) { if (Connection.REQUEST_CODE == request) { connection.onActivityResult(result); } } @Override public void update(Observable observable, Object data) { if (observable != connection) { return; } // Your presentation logic goes here... } 
  • ¿Cómo puedo evitar el Administrador de Cuentas de Chrome de Android para OAuth?
  • GoogleAuthException: Desconocido (android)
  • Error al recrear un ID de cliente para una aplicación de Android en la Consola de API
  • Google OAuth2 - token de acceso y token de actualización -> invalid_grant / Code ya se redimió
  • GoogleAuthException Fuente desconocida
  • ¿Cómo puedo verificar los símbolos generados por Android en mi servidor mediante PHP?
  • No se puede obtener el código de autorización con el inicio de sesión de Google+ para Android: INVALID_SCOPE
  • Google oauth cómo utilizar el token de actualización
  • La mejor forma de permitir a los usuarios acceder a la aplicación mediante sus credenciales de Google
  • Token de actualización de accountmanager (acceso sin conexión)
  • GoogleAuthException al obtener un token de acceso con ClientID
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.