在尝试实现示例同步适配器应用程序时,我遇到了上述异常。我看到了许多与此问题相关的帖子,但没有令人满意的回复。
因此,我会在这里记录我的解决方案,以防其他人遇到相同的问题。
还有一些有用的提示可以帮助调试此类问题。
首先,对于某些标签启用详细日志记录:
$ adb shell setprop log.tag.AccountManagerService VERBOSE
$ adb shell setprop log.tag.Accounts VERBOSE
$ adb shell setprop log.tag.Account VERBOSE
$ adb shell setprop log.tag.PackageManager VERBOSE
您将看到如下日志:
V/AccountManagerService: initiating bind to authenticator type com.example.account
V/Accounts: there is no service connection for com.example.account
V/Accounts: there is no authenticator for com.example.account, bailing out
D/AccountManagerService: bind attempt failed for Session: expectLaunch true, connected false, stats (0/0/0), lifetime 0.002, addAccount, accountType com.example.account, requiredFeatures null
这意味着该帐户类型未注册验证器。安装软件包时,请观察日志以查看已注册的验证器。D/PackageManager: encountered new type: ServiceInfo: AuthenticatorDescription {type=com.example.account}, ComponentInfo{com.example/com.example.android.AuthenticatorService}, uid 10028
D/PackageManager: notifyListener: AuthenticatorDescription {type=com.example.account} is added
我遇到的问题是,身份验证器 XML 描述符引用了一个字符串资源,在安装过程中没有得到正确解析:
android:accountType="@string/account_type"
日志显示
encountered new type: ServiceInfo: AuthenticatorDescription {type=@2131231194}, ...
将其替换为普通字符串(而不是资源)可以解决问题。这似乎只出现在Android 2.1中。
android:accountType="com.example.account"
首先,检查在这篇文章中解释的条件:
[...] 如果你看到一个来自AccountManagerService
的错误信息,形式为caller uid XXXX is different than the authenticator's uid
,那么这可能会有点误导。在该消息中,“认证器”不是指你的认证器类,而是Android理解为账户类型注册的认证器。 在AccountManagerService
内部发生的检查如下:
private void checkCallingUidAgainstAuthenticator(Account account) {
final int uid = Binder.getCallingUid();
if (account == null || !hasAuthenticatorUid(account.type, uid)) {
String msg = "caller uid " + uid + " is different than the authenticator's uid";
Log.w(TAG, msg);
throw new SecurityException(msg);
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
}
}
请注意hasAuthenticatorUid()
需要使用account.type
参数。我的问题在于这里出了差错。我创建了一个带有常量指定类型的Account
:
class LoginTask {
Account account = new Account(userId, AuthenticatorService.ACCOUNT_TYPE);
...
}
class AuthenticatorService extends Service {
public static final String ACCOUNT_TYPE = "com.joelapenna.foursquared";
...
}
但是这个常量与我的认证器的XML定义不匹配:
<account-authenticator xmlns:android="/web/20150729061818/http://schemas.android.com/apk/res/android"
android:accountType="com.joelapenna.foursquared.account" ... />
其次,如果你跟我一样想将示例嵌入到现有应用中进行测试,那么请确保使用此示例中的Constants
类而不是android.provider.SyncStateContract
包下的类。因为这两个类都使用了相同的属性名称ACCOUNT_TYPE
,该属性名称在创建Account
对象时被使用。
在我的情况下,问题非常简单,就是在res/xml/authenticator.xml
中声明的android:accountType="com.foo"
与创建帐户时错误地引用为"foo.com"
造成了不匹配。
Account newAccount = new Account("dummyaccount", "foo.com");
糟糕!
有几个部分需要实现自定义账户...
要在您的Activity中调用AccountManager,类似于您已经实现的方式...
Account account = new Account(username, ACCESS_TYPE);
AccountManager am = AccountManager.get(this);
Bundle userdata = new Bundle();
userdata.putString("SERVER", "extra");
if (am.addAccountExplicitly(account, password, userdata)) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, username);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCESS_TYPE);
setAccountAuthenticatorResult(result);
}
在res/xml/authenticator.xml文件中,您需要定义您的AccountAuthenticator数据(负责您的Authenticator UID)。ACCESS_TYPE必须与此xml中定义的accountType字符串相同!
在res/xml/authenticator.xml文件中,您需要定义您的AccountAuthenticator数据(负责您的Authenticator UID)。ACCESS_TYPE必须与此xml中定义的accountType字符串相同!
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="de.buecherkiste"
android:icon="@drawable/buecher"
android:label="@string/app_name"
android:smallIcon="@drawable/buecher" >
</account-authenticator>
最后,您需要在清单文件中定义您的服务。请不要忘记相关权限以管理您的账户(AUTHENTICATE_ACCOUNTS / USE_CREDENTIALS / GET_ACCOUNTS / MANAGE_ACCOUNTS)。
<service android:name=".AuthenticationService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
我的错误在于假设AccountManager的getAccounts()方法只返回与我的应用程序上下文相关联的帐户。 我更改为
AccountManager accountManager = AccountManager.get(context);
Account[] accounts = accountManager.getAccounts();
为了
AccountManager accountManager = AccountManager.get(context);
Account[] accounts = accountManager.getAccountsByType(Constants.ACCOUNT_TYPE);
<uses-permission android:name="ANDROID.PERMISSION.GET_ACCOUNTS"/>
当我把它改成小写字母时,原来的所有字母都变成了小写字母。
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
请确保您的服务XML指向正确的位置。
例如,如果您的模块名称是
com.example.module.auth
您的服务android:name应该为
<service android:name=".module.auth.name-of-authenticator-service-class"...
在 AndriodManifest.xml 中
对我来说,这是一个非常愚蠢的错误,而且很难找到。
在 authenticator.xml 文件中,我写了:
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.myapp"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:label="@string/app_name"
/>
替代
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="com.myapp"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:label="@string/app_name"
/>
导致这个错误的原因。希望能对某些人有所帮助!
accountManager.getAccounts()
搜索此电子邮件并找到一个具有相同电子邮件但具有另一种帐户类型的帐户时,当尝试使用该(google.com)帐户时,我会遇到此错误。public Account findAccount(String accountName) {
for (Account account : accountManager.getAccounts())
if (TextUtils.equals(account.name, accountName) && TextUtils.equals(account.type, "myservice.com"))
return account;
return null;
}
accountManager.getAccountsByType("myservice.com")
。 - nickgrim