无法在 android 模拟器上检索 OAuth 2.0 访问令牌
Failing to retrieve OAuth 2.0 access token on 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 模拟器上存在播放服务 (
GoogleApiAvailability.isGooglePlayServicesAvailable(context)
returns 0)
accountName
在传递给 setSelectedAccountName
时设置正确(设置为 "myuser@gmail.com"
)
- 项目中存在所有权限、依赖和配置(事实上,它适用于所有真实设备)
知道为什么它不能在模拟器上运行吗?
更新:
深入研究 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()
returns 模拟器上的空数组。但是,在真实设备上,它 returns 是一个合适的列表。
也许模拟器是 运行 旧版本的 Google 服务。最新版本似乎会抛出 GoogleAuthException 而不是 IllegalArgumentException。
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
我认为问题是您必须使用物理设备进行开发和测试,因为 Google Play 服务 无法安装在模拟器上。
我看不出其他原因,但这里有一个 code snippet taken from tasks-android-sample 也使用 GoogleAccountCredential.
好吧,事情总是比看起来容易。
感谢 post and to b1izzar 指出正确答案。
我查看的所有真实设备都是运行 Android 5.1 Lollipop.
我检查的所有模拟器都是 运行 Android 6.0 Marshmallow。
在 Marshmallow 上,即在我的模拟器上,在清单中指定 GET_ACCOUNTS
权限是不够的。 强制 在运行时请求此权限 具有特定 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.
}
}
注意: in Marshmallow GET_ACCOUNTS
, WRITE_CONTACTS
and READ_CONTACTS
权限在相同的权限组,因此一旦授予 READ_CONTACTS
,也会授予 GET_ACCOUNTS
。
注2:在Android牛轧糖GET_ACCOUNTS
是deprecated,所以使得即使在 Marshmallow.
中也应该使用 READ_CONTACTS
而不是 GET_ACCOUNT
我正在尝试使用 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 模拟器上存在播放服务 (
GoogleApiAvailability.isGooglePlayServicesAvailable(context)
returns 0) accountName
在传递给setSelectedAccountName
时设置正确(设置为"myuser@gmail.com"
)- 项目中存在所有权限、依赖和配置(事实上,它适用于所有真实设备)
知道为什么它不能在模拟器上运行吗?
更新:
深入研究 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()
returns 模拟器上的空数组。但是,在真实设备上,它 returns 是一个合适的列表。
也许模拟器是 运行 旧版本的 Google 服务。最新版本似乎会抛出 GoogleAuthException 而不是 IllegalArgumentException。
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
我认为问题是您必须使用物理设备进行开发和测试,因为 Google Play 服务 无法安装在模拟器上。
我看不出其他原因,但这里有一个 code snippet taken from tasks-android-sample 也使用 GoogleAccountCredential.
好吧,事情总是比看起来容易。
感谢
我查看的所有真实设备都是运行 Android 5.1 Lollipop.
我检查的所有模拟器都是 运行 Android 6.0 Marshmallow。
在 Marshmallow 上,即在我的模拟器上,在清单中指定 GET_ACCOUNTS
权限是不够的。 强制 在运行时请求此权限 具有特定 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. } }
注意: in Marshmallow GET_ACCOUNTS
, WRITE_CONTACTS
and READ_CONTACTS
权限在相同的权限组,因此一旦授予 READ_CONTACTS
,也会授予 GET_ACCOUNTS
。
注2:在Android牛轧糖GET_ACCOUNTS
是deprecated,所以使得即使在 Marshmallow.
READ_CONTACTS
而不是 GET_ACCOUNT