Android AccountManager帐号管理(一)

来源:互联网 发布:双色球选号过滤软件 编辑:程序博客网 时间:2024/06/08 06:22

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<ResolveInfo> 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的一些属性

 <?xml version="1.0" encoding="utf-8"?> <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才可清除系统的存储

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

原创粉丝点击