无法在Android模拟器上检索OAuth 2.0访问令牌 [英] Failing to retrieve OAuth 2.0 access token on android emulator

查看:110
本文介绍了无法在Android模拟器上检索OAuth 2.0访问令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to login into my application using GoogleAccountCredential for the authentication:

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

它在真实设备上可以正常工作,但是在android仿真器上mGoogleAccountCredential.getToken()失败,但出现以下异常:

It works just fine on real devices, but on the android emulator mGoogleAccountCredential.getToken() fails with the following exception:

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")
  • 项目中存在所有权限,依赖关系和配置(事实上,它在所有实际设备上均有效)
    • Google Play Services present on the emulator (GoogleApiAvailability.isGooglePlayServicesAvailable(context) returns 0)
    • accountName is set and correct when passed to the setSelectedAccountName (set to "myuser@gmail.com")
    • All the permissions, dependecies and configurations exist in the project (as a matter of fact, it works on all the real devices)
    • 有什么线索为什么它不能在模拟器上工作?

      Any clue why isn't it working on the emulator?

      UPD:
      深入研究Google的代码后:问题出现在setSelectedAccountName(accountName)方法中.此方法要求GoogleAccountManager给他一个与给定帐户名关联的帐户.如果没有这样的帐户,则将帐户名设置为null:

      UPD:
      After digging a bit in Google's code: the issue occurs in setSelectedAccountName(accountName) method. This method asks GoogleAccountManager to give him an account associated with the given account name. If there is no such an account, the account name is being set to 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依次遍历所有现有帐户,并将其名称与给定的帐户名称进行比较.如果存在匹配项,则返回相应的帐户:

      AccountManager, in turn, goes over all the existing account and compares their names to the given account name. If there is a match, the appropriate account is returned:

        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()返回模拟器上的空数组.但是,在实际设备上,它会返回正确的列表.

      The thing is that getAccounts() returns empty array on the emulator. On a real device, however, it returns a proper list.

      推荐答案

      一如既往,事情比看起来容易.
      感谢帖子,并发送至 b1izzar 指向正确的答案.

      Well, as always things are easier than they seem.
      Thanks to this post and to b1izzar for pointing to the right answer.

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

      All the real devices I checked on are running Android 5.1 Lollipop.
      All the emulators I checked on are running Android 6.0 Marshmallow.

      棉花糖上,即在我的模拟器上,在清单中指定GET_ACCOUNTS权限是不够的.这是的强制以请求此权限的在运行时与特定代码:

      On Marshmallow, i.e. on my emulator, it's not enough to specify GET_ACCOUNTS permission in manifest. It is mandatory to request this permission at runtime with a specific code:

      请求权限:

      Request permissions:

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

      注意:棉花糖 GET_ACCOUNTS中,WRITE_CONTACTSREAD_CONTACTS权限位于同一权限组中,因此,一旦授予READ_CONTACTS,则也被授予.

      Note: in Marshmallow GET_ACCOUNTS, WRITE_CONTACTS and READ_CONTACTS permissions are in the same permission group, so once READ_CONTACTS is granted, GET_ACCOUNTS is granted as well.

      注意2: Android牛轧糖 GET_ACCOUNTS中是已过时,因此即使在棉花糖中使用READ_CONTACTS代替GET_ACCOUNT也很有意义.

      Note 2: in Android Nougat GET_ACCOUNTS is deprecated, so it makes sense to use READ_CONTACTS instead of GET_ACCOUNT even in Marshmallow.

      这篇关于无法在Android模拟器上检索OAuth 2.0访问令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆