无法在Android模拟器

时间:2016-03-01 19:56:32

标签: android authentication oauth-2.0 google-api android-emulator

我正在尝试使用GoogleAccountCredential登录我的应用程序进行身份验证:

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

它在真实设备上工作正常,但在android模拟器mGoogleAccountCredential.getToken()上失败,但有以下异常:

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服务(GoogleApiAvailability.isGooglePlayServicesAvailable(context)返回0)
  • 传递给accountName(设置为setSelectedAccountName)时,
  • "myuser@gmail.com"已设置且正确
  • 项目中存在所有权限,依赖项和配置(事实上,它适用于所有真实设备)

任何线索为什么它不能在模拟器上运行?

UPD:
在Google代码中挖掘了一下之后:问题出现在setSelectedAccountName(accountName)方法中。此方法要求GoogleAccountManager为其提供与指定帐户名相关联的帐户。如果没有此类帐户,则帐户名称将设置为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会覆盖所有现有帐户,并将其名称与给定的帐户名称进行比较。如果匹配,则返回相应的帐户:

  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");
  }

问题是getAccounts()在模拟器上返回空数组。但是,在真实设备上,它会返回一个正确的列表。

3 个答案:

答案 0 :(得分:2)

嗯,一如既往,事情比他们看起来容易 感谢this发帖和b1izzar指向正确答案。

我检查过的所有真实设备都在运行 Android 5.1 Lollipop 我检查过的所有模拟器都在运行 Android 6.0 Marshmallow

Marshmallow 上,即在我的模拟器上,仅在清单中指定GET_ACCOUNTS权限是不够的。 必须在特定code

请求此权限在运行时
  

请求权限:

// 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.
    }
}

注意 Marshmallow GET_ACCOUNTSWRITE_CONTACTSREAD_CONTACTS权限属于同一权限组,因此{{} 1}}被授予,READ_CONTACTS也被授予。

Android Nougat GET_ACCOUNTS中的

注意事项2 deprecated,因此使用GET_ACCOUNTS代替{{{}}是有意义的1}}甚至在 Marshmallow

答案 1 :(得分:1)

也许模拟器正在运行旧版Google服务。似乎最新版本会抛出GoogleAuthException,而不是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

答案 2 :(得分:1)

我认为问题在于您必须使用物理设备进行开发和测试,因为无法在模拟器上安装 Google Play服务

我没有看到其他原因,但是您从code snippet获取tasks-android-sample,并使用 GoogleAccountCredential