Android AccountManager帐号管理(一)

AccountManager简介

AccountManager帐号管理器,集中管理apps注册的不同类型的帐号。
不同类型的帐号服务会使用不同的帐号登录和鉴权方式,所以AccountManager为不同类型的帐号提供一个插件式authenticator模块,authenticators自己处理帐号登录/认证的具体细节,也可以自己存储帐号信息

简言之,AccountManager是一个面向应用程序开发的组件,它提供了一套对应于IAccountManager协议的应用程序接口;这组接口通过Binder机制与系统服务AccountManagerService进行通信,协作完成帐号相关的操作。同时,AccountManager接收authenticators提供的回调,以便在帐号操作完成之后向调用此帐号服务的业务返回对应的接口,同时触发这个业务对结果的处理。
- authenticators 即注册帐号服务的app;
- 业务调用方 即使用authenticators提供的帐号服务的第三方,也可以是authenticator自己

使用AccountManager注册帐号服务

如果应用想要注册一个新的帐号服务,必须实现AbstractAccountAuthenticator类,这是创建一个account authenticator的抽象基础类;然后新建一个authenticator service,注册action必须为”android.accounts.AccountAuthenticator”,且该service要实现onBinder(android.content.Intent)方法,返回AbstractAccountAuthenticator实现类的实例

说下必须要注册一个action为”android.accounts.AccountAuthenticator”的authenticator service
首先,AbstractAccountAuthenticator是创建一个account authenticator必须实现的抽象基础类,接口协议定义在IAccountAuthenticator中,是一个authenticator自定义自己登录/认证等的接口协议;
那如何将authenticator的实现回调给AccountManagerService,供其调起authenticator的具体实现呢?
就是通过action注册为”android.accounts.AccountAuthenticator”的authenticator service了:
这个action即为AccountManager#ACTION_AUTHENTICATOR_INTENT的常量值,系统服务AccountManagerService是通过bind到action为AccountManager#ACTION_AUTHENTICATOR_INTENT的intent service上来调起某个账号类型的authenticator service,然后通过调用这个service的getBinder()方法来获取AbstractAccountAuthenticator的实现实例,进而调用authenticator对帐号登录认证等服务的具体实现
至于每个帐号服务都定义一个action为”android.accounts.AccountAuthenticator”的service,那AccountManagerService是如何区分的呢?
当然是通过账号类型了,每个accountType只能对应一个authenticator
那系统是如何知道每个authenticator service对应的账号类型?
在AndroidManifest.xml中注册authenticator service时声明帐号属性的meta-data配置,声明的meta-data是一个name为 “android.accounts.AccountAuthenticator”的xml 资源(AccountManager#AUTHENTICATOR_META_DATA_NAME),该XML资源文件定义了account-authenticator用到的一些属性:如accountType;系统解析authenticator service info之后,loadXmlMetaData获取authenticator 的xml属性,然后利用 Xml.asAttributeSet即

final PackageManager pm = mContext.getPackageManager();
final  List resolveInfos =  pm.queryIntentServicesAsUser(new Intent("android.accounts.AccountAuthenticator", PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ResolveInfo resolveInfo : resolveInfos) {
     android.content.pm.ServiceInfo si = service.serviceInfo;
     ComponentName componentName = new ComponentName(si.packageName, si.name);
     PackageManager pm = mContext.getPackageManager();
     XmlResourceParser parser = null;
     try {
         parser = si.loadXmlMetaData(pm, "android.accounts.AccountAuthenticator")
         if (parser == null) {
             throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
         }
          AttributeSet attrs = Xml.asAttributeSet(parser);
          ...//解析authenticator xml的帐号属性
     }
     ...
}

注册一个测试帐号

创建一个继承自AbstractAccountAuthenticator的类TestAccountAuthenticator

public class TestAccountAuthenticator extends AbstractAccountAuthenticator {
    private Context mContext;
    public TestAccountAuthenticator(Context context) {
        super(context);
        mContext = context;
    }
    @Override
    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
        return null;
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {//登录界面的定制化实现
        Intent addAccountIntent = new Intent(mContext, LoginActivity.class);
        addAccountIntent.putExtra("authTokenType", authTokenType);
        if (options != null) {
            addAccountIntent.putExtras(options);
        }
        addAccountIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);//一定要把response传入intent的extra中,便于将登录操作的结果回调给AccountManager

        Bundle bundle = new Bundle();
        bundle.putParcelable(AccountManager.KEY_INTENT, addAccountIntent);
        return bundle;
    }
    @Override
    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {//是否允许删除你的账号,这里是不允许删除,可自定义什么时候可以被删除,默认是true
        Bundle bundle = new Bundle();
        bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
        return bundle;
    }
    @Override
    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options)
            throws NetworkErrorException {//自己实现:验证用户的密码
        return null;
    }
    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
            throws NetworkErrorException {//自己完成获取鉴权token的流程
        return null;
    }
    @Override
    public String getAuthTokenLabel(String authTokenType) {
        return null;
    }
    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
            throws NetworkErrorException {
        return null;
    }
    @Override
    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
        return null;
    }
}

创建一个authenticator service—TestAuthenticatiorService,实现onBinder()方法,在onBinder方法里返回TestAccountAuthentcator的实例

public class TestAuthenticatiorService extends Service {
    private static final String TAG = "XmAuthenticationService";

    private TestAccountAuthenticator mAuthenticator;
    @Override
    public void onCreate() {
        super.onCreate();
        mAuthenticator = new TestAccountAuthenticator(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mAuthenticator.getIBinder();
    }
}

在AndroidManifest.xml文件中注册该TestAuthenticatorService

<service
    android:name=".TestAuthenticatiorService"
    android:exported="true">
    <intent-filter>
        <action android:name="android.accounts.AccountAuthenticator" />
    intent-filter>
    <meta-data
        android:name="android.accounts.AccountAuthenticator"
        android:resource="@xml/authenticator" />
service>

其中,authenticator是一个xml的资源文件,定义了account的一些属性

 
 <account-authenticator
 xmlns:android="http://schemas.android.com/apk/res/android"
     android:accountType="com.test"//账号类型
     android:icon="@drawable/icon"//设置-同步-添加 账号类型的icon
     android:smallIcon="@drawable/miniIcon"//小icon
     android:label="@string/label"//设置-同步-添加 账号类型的名称
     android:accountPreferences="@xml/account_preferences"//在设置中展示的一些偏好
     android:customTokens="false"//authenticator是否要自己处理auth token的存储和获取权限
/>

ps:说下customTokens属性
如设置为true,就需要在TestAccountAuthenticator类的getAuthToken方法的实现中自己进行caller app的权限检查和token存储问题
如不设置(默认为false)或设置为false,则是使用AccountManager的权限检查和存储机制,默认只有签名相同的app才可调用getAuthToken()方法,存储在系统数据库中,但要app判断是否有效,失效要调用invalidate才可清除系统的存储

到这里,你就成功注册了一个新的帐号类型了

你可能感兴趣的:(android)