5

Sto cercando di accedere al mio applicazione utilizzando GoogleAccountCredential per l'autenticazione:Non riuscendo a recuperare l'accesso OAuth 2.0 gettone emulatore di Android

mGoogleAccountCredential = GoogleAccountCredential.usingOAuth2(context, Arrays.asList(Scopes.EMAIL, Scopes.PLUS_LOGIN)); 
mGoogleAccountCredential.setSelectedAccountName(accountName); 
String token = mGoogleAccountCredential.getToken(); 

Funziona bene su dispositivi reali, ma l'emulatore Android mGoogleAccountCredential.getToken() fallisce con la seguente eccezione:

java.lang.IllegalArgumentException: the name must not be empty: null 
03-01 19:41:31.604 3203-3361/com.myapp W/System.err:  at android.accounts.Account.<init>(Account.java:48) 
03-01 19:41:31.604 3203-3361/com.myapp W/System.err:  at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source) 
03-01 19:41:31.604 3203-3361/com.myapp W/System.err:  at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:255) 
  • Google Play Services presenti sull'emulatore (GoogleApiAvailability.isGooglePlayServicesAvailable(context) restituisce 0)
  • 012.351.641,061 mila
  • accountName è impostato e corretto quando passarono ai setSelectedAccountName (insieme a "[email protected]")
  • tutte le autorizzazioni, dependecies ed esistono configurazioni nel progetto (come un dato di fatto, funziona su tutti i dispositivi reali)

Qualsiasi indizio perché non funziona sull'emulatore?

UPD:
Dopo aver scavato un po 'nel codice di Google: il problema si verifica in setSelectedAccountName(accountName) metodo. Questo metodo richiede a GoogleAccountManager di assegnargli un account associato al nome dell'account specificato. Se non c'è un conto ad esempio, il nome dell'account viene impostato null:

public final GoogleAccountCredential setSelectedAccountName(String accountName) { 
    selectedAccount = accountManager.getAccountByName(accountName); 
    // check if account has been deleted 
    this.accountName = selectedAccount == null ? null : accountName; 
    return this; 
    } 

AccountManager, a sua volta, va oltre tutto l'account esistente e confronta i loro nomi per il nome dato conto. Se c'è una corrispondenza, l'account appropriato viene restituito:

public Account getAccountByName(String accountName) { 
    if (accountName != null) { 
     for (Account account : getAccounts()) { 
     if (accountName.equals(account.name)) { 
      return account; 
     } 
     } 
    } 
    return null; 
    } 

    public Account[] getAccounts() { 
    return manager.getAccountsByType("com.google"); 
    } 

Il fatto è che i rendimenti getAccounts() array vuoto sull'emulatore. Su un dispositivo reale, tuttavia, restituisce una lista corretta.

+0

Utilizzi l'immagine del sistema API di Google? – Anthony

+0

Sì, certo, l'ho specificato nella mia domanda – meltedspark

+0

Solo per essere sicuro (dato che non ho una profonda esperienza in questo argomento), hai usato la "Immagine del sistema x86 Elemento API di Google" per costruire il tuo Dispositivo Virtuale, e non solo "Immagine del sistema x86 elemento"? Non ho visto dove hai specificato questo (forse indirettamente) – Anthony

risposta

2

Bene, come sempre le cose sono più facili di quello che sembrano.
Grazie al post this ea b1izzar per indicare la risposta corretta.

Tutti i dispositivi reali controllati sono in esecuzione Android 5.1 Lollipop.
Tutti gli emulatori che ho controllato sono in esecuzione Android 6.0 Marshmallow.

Su Marshmallow, vale a dire sul mio emulatore, non è sufficiente specificare l'autorizzazione GET_ACCOUNTS in manifest. E 'obbligatoria per richiedere questo permesso a runtime con uno specifico code:

permessi Richiesta:

// Here, thisActivity is the current activity 
if (ContextCompat.checkSelfPermission(thisActivity, 
       Manifest.permission.READ_CONTACTS) 
     != PackageManager.PERMISSION_GRANTED) { 

    // Should we show an explanation? 
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, 
      Manifest.permission.READ_CONTACTS)) { 

     // Show an expanation to the user *asynchronously* -- don't block 
     // this thread waiting for the user's response! After the user 
     // sees the explanation, try again to request the permission. 

    } else { 

     // No explanation needed, we can request the permission. 

     ActivityCompat.requestPermissions(thisActivity, 
       new String[]{Manifest.permission.READ_CONTACTS}, 
       MY_PERMISSIONS_REQUEST_READ_CONTACTS); 

     // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an 
     // app-defined int constant. The callback method gets the 
     // result of the request. 
    } 
} 

Nota: in MarshmallowGET_ACCOUNTS, WRITE_CONTACTS e READ_CONTACTS permessi si trovano nello stesso gruppo di autorizzazioni, quindi una volta READ_CONTACTS concesso, GET_ACCOUNTS è concesso anche.

Nota 2: inAndroid TorroneGET_ACCOUNTS è deprecated, quindi ha senso usare READ_CONTACTS invece di GET_ACCOUNT anche in Marshmallow.

1

Forse l'emulatore sta eseguendo una versione precedente di Servizi Google. Sembra che l'ultima versione genererebbe GoogleAuthException in contrasto con IllegalArgumentException.

API Doc

public String getToken() 
       throws IOException, 
         com.google.android.gms.auth.GoogleAuthException 
Returns an OAuth 2.0 access token. 
Must be run from a background thread, not the main UI thread. 

Throws: 
IOException 
com.google.android.gms.auth.GoogleAuthException 
+0

IllegalArgumentException è un'eccezione di runtime, non una controllata. Pertanto non è specificato nella firma della funzione. – meltedspark

+0

Hai ragione, derp. –

1

Penso che il problema è che è necessario utilizzare un dispositivo fisico per lo sviluppo e la sperimentazione perché i servizi non può essere installato su un emulatore Google Play.

non vedo un altro motivo, ma qui si ha una code snippet tratto da tasks-android-sample che utilizzano anche GoogleAccountCredential.

+0

Uso l'immagine su cui sono installati i servizi di Google Play ("Immagine del sistema API di Google"). In effetti, sono in grado di accedere al mio gmail sull'emulatore. – meltedspark