Android: inicio de sesión de Google con pantalla de inicio de sesión en lugar de inicio de sesión automático

He añadido un inicio de sesión de Google a mi aplicación para Android (los pasos se pueden encontrar en la edición 3 de esta publicación). Todo funciona como debería, pero me gustaría hacer algunos pequeños ajustes. Con el código actual encontrado en la edición 3, se inicia sesión automáticamente cada vez que inicia la aplicación, sin la pantalla de inicio de sesión. Quiero desactivar esto, ya que la aplicación se utilizará en una tableta en el trabajo, donde un empleado diferente debe iniciar sesión en la aplicación todos los días.

Empecé por eliminar el mGoogleApiClient.connect(); Desde el método onStart() , y ahora tengo el botón de inicio de sesión de Google de nuevo. Cuando agrego mGoogleApiClient.connect(); A signInWithGoogle() puedo signInWithGoogle() sesión con el usuario recordado.

Lo que quiero ahora es la pantalla predeterminada de inicio de sesión de Google en la que puede rellenar su correo electrónico de Google y su contraseña, cada vez que haga clic en el botón de inicio de sesión, en lugar de simplemente iniciar sesión en el usuario recordado. (PS: Tenga en cuenta que en mi dispositivo Android actualmente sólo tengo un usuario en Settings -> Google Accounts , tal vez por eso se inicia sesión automáticamente en lugar de dar la opción de elegir qué cuenta debe conectarse.)

Voy a probar si hace una diferencia cuando tengo varias cuentas de Google en mi dispositivo Android. Aceptar, he añadido una segunda cuenta de Google a mi dispositivo Android, pero mi aplicación todavía se registra automáticamente en el usuario recordado cuando hago clic en Iniciar sesión ..


EDIT 2:

Todavía no he podido encontrar una solución para mi problema.

Encontré algunos tutoriales AccountManager con diferentes formas de iniciar sesión en Google, como usar el AccountManager para que un usuario pueda seleccionar una de las cuentas de Google existentes en el dispositivo. (Sólo he leído sobre este método hoy, así que no tengo ejemplos de código para esto, pero esto tampoco es lo que estoy buscando de todos modos.)

Probablemente ya lo dejé en claro en el post anterior, pero esto es lo que quiero explicar en imágenes:

  1. Un usuario inicia la aplicación en su Dispositivo Android.
  2. Un usuario introduce su nombre de usuario de cuenta de Google (correo electrónico utilizado) y su contraseña Producto en la lista
  3. Después de que un usuario ha iniciado sesión correctamente, podemos hacer otras cosas con la aplicación

PS: Sólo para asegurarse de que esta pantalla de inicio de sesión es la de Google. Así que no es una pantalla de inicio de sesión creada por mí mismo. Esto en teoría me haría capaz de guardar la contraseña introducida, que está en contra del protocolo de Google OAuth.


EDIT 3 (El Código):

Los pasos que hice para que los servicios de Google funcionaran hasta ahora son los siguientes. Ahora sólo tengo que averiguar cómo forzar la pantalla de inicio de sesión o completamente cerrar la sesión, lo que resulta en la pantalla de inicio de sesión cada vez.

He seguido el siguiente tutorial: http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/

Con información adicional utilizada en los siguientes tutoriales / sitios:

  • Https://developers.google.com/+/mobile/android/getting-started
  • Https://developers.google.com/+/mobile/android/sign-in
  • Http://developer.android.com/google/play-services/setup.html#Setup

Esto generó el código siguiente:

AndroidManifest.xml:

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.testproject_gmaillogin" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <activity android:name="com.example.testproject_gmaillogin.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 

Strings.xml:

 <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">TestProject_GmailLogin</string> <string name="action_settings">Settings</string> <string name="profile_pic_description">Google Profile Picture</string> <string name="btn_logout_from_google">Logout from Google</string> <string name="btn_revoke_access">Revoke Access</string> </resources> 

Activity_main.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp" tools:context=".MainActivity" > <LinearLayout android:id="@+id/profile_layout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:orientation="horizontal" android:weightSum="3" android:visibility="gone"> <ImageView android:id="@+id/img_profile_pic" android:contentDescription="@string/profile_pic_description" android:layout_width="80dp" android:layout_height="wrap_content" android:layout_weight="1"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:orientation="vertical" android:layout_weight="2" > <TextView android:id="@+id/txt_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textSize="20sp" /> <TextView android:id="@+id/txt_email" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:textSize="18sp" /> </LinearLayout> </LinearLayout> <com.google.android.gms.common.SignInButton android:id="@+id/btn_sign_in" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp"/> <Button android:id="@+id/btn_sign_out" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_logout_from_google" android:visibility="gone" android:layout_marginBottom="10dp"/> <Button android:id="@+id/btn_revoke_access" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_revoke_access" android:visibility="gone" /> </LinearLayout> 

MainActivity.java:

 package com.example.testproject_gmaillogin; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.common.SignInButton; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; import com.google.android.gms.plus.Plus; import com.google.android.gms.plus.model.people.Person; import android.support.v7.app.ActionBarActivity; import android.content.Intent; import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, OnClickListener { // Logcat tag private static final String TAG = "MainActivity"; // Profile pix image size in pixels private static final int PROFILE_PIC_SIZE = 400; // Request code used to invoke sign in user interactions private static final int RC_SIGN_IN = 0; // Client used to interact with Google APIs private GoogleApiClient mGoogleApiClient; // A flag indicating that a PendingIntent is in progress and prevents // us from starting further intents private boolean mIntentInProgress; // Track whether the sign-in button has been clicked so that we know to resolve // all issues preventing sign-in without waiting private boolean mSignInClicked; // Store the connection result from onConnectionFailed callbacks so that we can // resolve them when the user clicks sign-in private ConnectionResult mConnectionResult; // The used UI-elements private SignInButton btnSignIn; private Button btnSignOut, btnRevokeAccess; private ImageView imgProfilePic; private TextView txtName, txtEmail; private LinearLayout profileLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the UI-elements btnSignIn = (SignInButton) findViewById(R.id.btn_sign_in); btnSignOut = (Button) findViewById(R.id.btn_sign_out); btnRevokeAccess = (Button) findViewById(R.id.btn_revoke_access); imgProfilePic = (ImageView) findViewById(R.id.img_profile_pic); txtName = (TextView) findViewById(R.id.txt_name); txtEmail = (TextView) findViewById(R.id.txt_email); profileLayout = (LinearLayout) findViewById(R.id.profile_layout); // Set the Button onClick-listeners btnSignIn.setOnClickListener(this); btnSignOut.setOnClickListener(this); btnRevokeAccess.setOnClickListener(this); mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(Plus.API, null) .addScope(Plus.SCOPE_PLUS_LOGIN) .build(); } @Override protected void onStart(){ super.onStart(); mGoogleApiClient.connect(); // <- REMOVED (EDIT 4: Added again) } @Override protected void onStop(){ super.onStop(); if(mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect(); } @Override public void onClick(View view){ switch(view.getId()){ case R.id.btn_sign_in: signInWithGPlus(); break; case R.id.btn_sign_out: signOutFromGPlus(); break; case R.id.btn_revoke_access: revokeGPlusAccess(); break; } } @Override public void onConnectionFailed(ConnectionResult result) { if(!result.hasResolution()){ GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show(); return; } if(!mIntentInProgress){ // Store the ConnectionResult so that we can use it later when the user clicks 'sign-in' mConnectionResult = result; if(mSignInClicked) // The user has already clicked 'sign-in' so we attempt to resolve all // errors until the user is signed in, or they cancel resolveSignInErrors(); } } @Override protected void onActivityResult(int requestCode, int responseCode, Intent intent){ if(requestCode == RC_SIGN_IN && responseCode == RESULT_OK) SignInClicked = true; mIntentInProgress = false; if(!mGoogleApiClient.isConnecting()) mGoogleApiClient.connect(); } } @Override public void onConnected(Bundle connectionHint) { mSignInClicked = false; Toast.makeText(this, "User is connected!", Toast.LENGTH_LONG).show(); // Get all the user's information getProfileInformation(); // Update the UI after sign-in updateUI(true); } @Override public void onConnectionSuspended(int cause){ mGoogleApiClient.connect(); updateUI(false); } // Updating the UI, showing/hiding buttons and profile layout private void updateUI(boolean isSignedIn){ if(isSignedIn){ btnSignIn.setVisibility(View.GONE); btnSignOut.setVisibility(View.VISIBLE); btnRevokeAccess.setVisibility(View.VISIBLE); profileLayout.setVisibility(View.VISIBLE); } else{ btnSignIn.setVisibility(View.VISIBLE); btnSignOut.setVisibility(View.GONE); btnRevokeAccess.setVisibility(View.GONE); profileLayout.setVisibility(View.GONE); } } // Sign-in into Google private void signInWithGPlus(){ //if(!mGoogleApiClient.isConnecting()) // <- ADDED (EDIT 4: Removed again) //mGoogleApiClient.connect(); // <- ADDED (EDIT 4: Removed again) if(!mGoogleApiClient.isConnecting()){ mSignInClicked = true; resolveSignInErrors(); } } // Method to resolve any sign-in errors private void resolveSignInErrors(){ if(mConnectionResult.hasResolution()){ try{ mIntentInProgress = true; //Toast.makeText(this, "Resolving Sign-in Errors", Toast.LENGTH_SHORT).show(); mConnectionResult.startResolutionForResult(this, RC_SIGN_IN); } catch(SendIntentException e){ // The intent was cancelled before it was sent. Return to the default // state and attempt to connect to get an updated ConnectionResult mIntentInProgress = false; mGoogleApiClient.connect(); } } } // Fetching the user's infromation name, email, profile pic private void getProfileInformation(){ try{ if(Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null){ Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient); String personName = currentPerson.getDisplayName(); String personPhotoUrl = currentPerson.getImage().getUrl(); String personGooglePlusProfile = currentPerson.getUrl(); String personEmail = Plus.AccountApi.getAccountName(mGoogleApiClient); Log.e(TAG, "Name: " + personName + ", " + "plusProfile: " + personGooglePlusProfile + ", " + "email: " + personEmail + ", " + "image: " + personPhotoUrl); txtName.setText(personName); txtEmail.setText(personEmail); // by default the profile url gives 50x50 px image, // but we can replace the value with whatever dimension we // want by replacing sz=X personPhotoUrl = personPhotoUrl.substring(0, personPhotoUrl.length() - 2) + PROFILE_PIC_SIZE; new LoadProfileImage(imgProfilePic).execute(personPhotoUrl); } else{ Toast.makeText(getApplicationContext(), "Person information is null", Toast.LENGTH_LONG).show(); } } catch(Exception ex){ ex.printStackTrace(); } } // Sign-out from Google private void signOutFromGPlus(){ if(mGoogleApiClient.isConnected()){ Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); mGoogleApiClient.disconnect(); mGoogleApiClient.connect(); updateUI(false); } } // Revoking access from Google private void revokeGPlusAccess(){ if(mGoogleApiClient.isConnected()){ Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient) .setResultCallback(new ResultCallback<Status>(){ @Override public void onResult(Status s){ Log.e(TAG, "User access revoked!"); mGoogleApiClient.connect(); updateUI(false); } }); } } @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 public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) return true; return super.onOptionsItemSelected(item); } } 

LoadProfileImage.java:

 package com.example.testproject_gmaillogin; import java.io.InputStream; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.util.Log; import android.widget.ImageView; /** * Background async task to load user profile picture from url **/ public class LoadProfileImage extends AsyncTask<String, Void, Bitmap> { private ImageView bmImage; public LoadProfileImage(ImageView bmImage){ this.bmImage = bmImage; } @Override protected Bitmap doInBackground(String... urls){ String urlDisplay = urls[0]; Bitmap mIcon11 = null; try{ InputStream in = new java.net.URL(urlDisplay).openStream(); mIcon11 = BitmapFactory.decodeStream(in); } catch(Exception ex){ Log.e("Error", ex.getMessage()); ex.printStackTrace(); } return mIcon11; } @Override protected void onPostExecute(Bitmap result){ bmImage.setImageBitmap(result); } } 

Los otros pasos que hice fueron:

En https://console.developers.google.com/project He creado un proyecto con:

API de Google+ en:

API de Google+ en

Y un ID de cliente creado con el SHA1 correcto y el mismo espacio de nombres que el proyecto:

Y un ID de cliente creado con el SHA1 correcto

En Eclipse:

He instalado la biblioteca google-play-services:

Servicios Google Play instalados

Y lo agregó al proyecto:

Se agregó la biblioteca de servicios de Google Play (2)Se agregó la biblioteca de servicios de Google Play (2)

También he creado un emulador con la versión de Google 4.4.2 (por lo que no Android 4.4.2) y también cambió el proyecto a Google 4.4.2 en lugar de Android 4.4.2:

Error de la soluciónEmulador de error de solución


EDIT 4:

Ok, tengo una solución temporal para mi propio caso. En mi caso, la aplicación que estoy haciendo debe ejecutarse en un Tablet que se utiliza explícitamente para mi aplicación. Como este es el caso, puedo eliminar todas las cuentas de Google de la configuración del dispositivo en el momento en que alguien revoca el acceso (como función de cierre de sesión).

Comencé por quitar los cambios anteriores (re-added the .connect(); al onStart() y lo quitó del signInWithGPlus() )

Luego agregué una línea al método revokeGPlusAccess :

 // Revoking access from Google private void revokeGPlusAccess(){ if(mGoogleApiClient.isConnected()){ Plus.AccountApi.clearDefaultAccount(mGoogleApiClient); Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient) .setResultCallback(new ResultCallback<Status>(){ @Override public void onResult(Status s){ Log.e(TAG, "User access revoked!"); removeAllGoogleAccountsFromDevice(); // <- Added mGoogleApiClient.connect(); updateUI(false); } }); } } 

Con el siguiente método:

 // Method to remove ALL Google Accounts from the Android Device private void removeAllGoogleAccountsFromDevice(){ // Ask if this really is what you want new AlertDialog.Builder(MainActivity.mActivity) .setMessage("Are you sure you want to delete all Google Accounts from this Android Device?\r\n\r\n" + "WARNING: If you run this app on the Work Tablet, click YES. If you run this on your own device, it's recommended to click NO.") .setCancelable(false) .setPositiveButton("Yes, continue", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // AccountManager is final because we use it in the separate Thread below final AccountManager accountManager = AccountManager.get(MainActivity.this); Account[] googleAccounts = accountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE); // Account is final because we use it in the separate Thread below for(final Account a : googleAccounts){ // Separate Thread because AccountManager #removeAccount is an async operation Thread worker = new Thread(new Runnable() { @Override public void run() { accountManager.removeAccount(a, null, null); } }); worker.start(); } } }) .setNegativeButton("No", null) .show(); } 

Sin embargo, esto sólo funciona en mi caso. Esto no funcionará en un dispositivo personal en el que obviamente no desea eliminar todas las cuentas de Google del dispositivo. Todavía me gustaría saber una solución si no quieres eliminar las cuentas de Google de ningún dispositivo.

3 Solutions collect form web for “Android: inicio de sesión de Google con pantalla de inicio de sesión en lugar de inicio de sesión automático”

La respuesta correcta está aquí .

Se necesita llamar a mClient.clearDefaultAccountAndReconnect() para borrar la cuenta previamente almacenada en caché.
Es una buena práctica hacer esto cada vez que un usuario hace clic en el botón de inicio de sesión, de modo que el usuario se muestre todas sus cuentas cada vez.

Intente firmar al usuario y luego volver a firmar al usuario. Si desea forzar al usuario a iniciar sesión cada vez, puede firmarlos cuando salgan de la aplicación. No te recomiendo que cambies el comportamiento de salida de la aplicación porque podría sorprender al usuario.

Asegúrese de que el entorno de desarrollo está configurado correctamente ejecutando el ejemplo de Google+ Android Quickstart . Si el comportamiento de inicio de sesión en la aplicación de ejemplo es el mismo que aparece, existe un problema con el entorno de desarrollo (por ejemplo, la versión de GMS o la versión de la API de Android) o el comportamiento del botón de inicio de sesión no es lo que espera que sea .

Por último, es posible que pueda beneficiarse de este artículo que cubre algunos puntos problemáticos comunes con Android Sign-In . Cubre una vista de alto nivel de los distintos pasos de autorización y resolución en el flujo de inicio de sesión de Android.

Salir no le ayudará a resolver su problema. Tienes que revocar el acceso cada vez que sales de la aplicación o cuando quieres salir de la aplicación e iniciar sesión nuevamente. Por lo tanto, basta con llamar revocar el método de acceso en el método de retroceso en la aplicación de salida como a continuación:

  @Override public void onBackPressed() { Log.d("CDA", "onBackPressed Called"); revokeGplusAccess(); super.onBackPressed(); } 

Esto definitivamente resolverá su problema.

  • If (session.isOpen ()), inicio de sesión de facebook en android siempre devuelve false
  • Hacer un login con facebook usando Facebook SDK 3.0
  • Los eventos de registro de ráfagas no siempre
  • ¿Cómo proporcionar credenciales de inicio de sesión a una prueba de Android automatizada?
  • La cookie de sesión no expira Cuando Chrome Browser está cerrado en teléfonos inteligentes
  • Mantenimiento de la sesión en android (la aplicación permanece autenticada en el lado del servidor)
  • Estrategia de la aplicación de Android para realizar un seguimiento de una sesión de inicio de sesión
  • Facebook Android SDK 3.0 siempre devuelve ABRIR al iniciar sesión
  • ¿Cómo puedo salir con AndroidAccountManager?
  • ¿Qué es una buena manera de realizar un seguimiento de los eventos de fondo en Android sin inflar los números de sesión?
  • Sesión de manejo en android mientras se registra en el lado del servidor en php
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.