在android emulator上检索OAuth 2.0访问令牌失败

在android emulator上检索OAuth 2.0访问令牌失败,android,authentication,oauth-2.0,google-api,android-emulator,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 = mGoogl

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

mGoogleAccountCredential = GoogleAccountCredential.usingOAuth2(context, Arrays.asList(Scopes.EMAIL, Scopes.PLUS_LOGIN));
mGoogleAccountCredential.setSelectedAccountName(accountName);
String token = mGoogleAccountCredential.getToken();
它在真正的设备上运行正常,但在android emulator上,
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)
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()
在模拟器上返回空数组。但是,在实际设备上,它会返回一个正确的列表。

也许模拟器运行的是旧版本的Google服务。最新版本似乎会抛出GoogleAuthException,而不是IllegalArgumentException


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


我看不出另一个原因,但这里你有一个使用GoogleAccountCredential的例子,因为事情总是比看起来容易。
感谢post和to指出正确答案

我检查过的所有真实设备都运行Android 5.1棒棒糖。
我检查过的所有模拟器都运行安卓6.0棉花糖

在棉花糖上,即在我的模拟器上,仅在清单中指定
GET_ACCOUNTS
权限是不够的。必须在运行时请求此权限,具体如下:

请求权限:

// 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.
    }
}
注意:在棉花糖
获取账户
中,
写入联系人
读取联系人
权限在同一权限组中,因此一旦授予
读取联系人
,也将授予
获取账户


注2:在Android Nougat
GET\u ACCOUNTS
中是,因此使用
READ\u CONTACTS
而不是
GET\u ACCOUNT
是有意义的,即使在棉花糖中也是如此。

你使用谷歌API系统映像吗?当然,我在问题中明确指出了这一点(因为我在这个话题上没有深入的经验),你使用了“Google API Item x86 System Image”来构建您的虚拟设备,而不仅仅是“Item x86 System Image”?我没有看到您在哪里指定了这个(可能是间接的)是的,我使用了Google API映像。否则
GoogleAppAvailability.isGooglePlayServicesAvailable(上下文)太长了,读不下去了。0,@ b/y>不会返回。@宾尼亚签出。TL;DR,您需要在清单中有<代码> GETYActudio权限,并在运行时请求它。ILLCOLALGARMUMTENExtExchange是运行时异常,而不是选中的异常。因此,它在函数签名中没有指定。我使用的图像是具有谷歌播放SE的图像。安装了服务(“谷歌API系统映像”)。事实上,我可以在模拟器上登录我的gmail。
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
// 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.
    }
}