一文搞懂Android賬戶系統(tǒng)的使用方式

一文搞懂Android賬戶系統(tǒng)的使用方式簡(jiǎn)介概述實(shí)戰(zhàn)環(huán)境布置基本使用(注冊(cè)、登錄和退出)注冊(cè)登錄退出附錄

一文搞懂Android賬戶系統(tǒng)的使用方式

簡(jiǎn)介

Android賬戶系統(tǒng)是利用Android系統(tǒng)為應(yīng)用對(duì)其賬戶信息進(jìn)行管理,同時(shí)避免每次進(jìn)入應(yīng)用都需用戶手動(dòng)輸入用戶名密碼進(jìn)行驗(yàn)證的繁瑣操作。

概述

Android賬戶系統(tǒng)是利用AccountManager家族的系統(tǒng)接口,將應(yīng)用的賬戶信息交給系統(tǒng)管理,并與后臺(tái)服務(wù)端自認(rèn)證處理。

我們可以在設(shè)置界面中看到Android系統(tǒng)管理的賬戶相關(guān)信息:

設(shè)置界面賬戶.png

Account家族均在系統(tǒng)的android/accounts文件目錄中,主要有如下幾個(gè)類成員:

  • AbstractAccountAuthenticator

  • Account

  • AccountAuthenticatorActivity

  • AccountAutheticatorResponse

  • AccountManager

  • AuthenticatorDescription

當(dāng)然應(yīng)用是通過(guò)AccountManager去和系統(tǒng)服務(wù)AccountManagerService進(jìn)行交互,具體的功能實(shí)現(xiàn)還是在service中。

實(shí)戰(zhàn)

應(yīng)用想實(shí)現(xiàn)通過(guò)Android系統(tǒng)管理自己的賬戶信息,大致需要進(jìn)行如下幾個(gè)步驟:

  • 環(huán)境布置;

  • 實(shí)現(xiàn)添加賬戶、登錄及退出登錄操作;

環(huán)境布置

首先是環(huán)境布置,這里的環(huán)境布置是應(yīng)用實(shí)現(xiàn)該功能的基本配置。

1、首先是權(quán)限配置,若要使用系統(tǒng)的該功能,需要獲取一些相關(guān)的權(quán)限:

<!--AccountManager所需權(quán)限-->
 <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
 <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
 <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>

2、在AndroidManifest.xml文件中添加系統(tǒng)服務(wù)AccountService,為了告訴系統(tǒng)當(dāng)前應(yīng)用需要使用Account服務(wù)

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

3、在2中,我們注意到注釋1處配置了一份資源文件,該文件是定義當(dāng)前應(yīng)用的賬戶類型(通常就是包名)

在res目錄下,和values同級(jí)的目錄xml(若沒(méi)有則新建)下定義authenticator.xml文件(名字自定義)

 <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
  android:accountType="com.welthy.demo"  //1
  android:icon="@mipmap/ic_launcher_round"
  android:smallIcon="@mipmap/ic_launcher"
  android:label="@string/app_name"/>

主要的就是注釋1的accountType,我們?cè)O(shè)為包名。

4、新建2中定義的AccountService

 public class AccountService extends Service {
      @Nullable
      @Override
      public IBinder onBind(Intent intent) {
           MyAuthenticator myAuthenticator = new MyAuthenticator(this); //1
           return myAuthenticator.getIBinder();
      }
 }

在這個(gè)服務(wù)中,我們只實(shí)現(xiàn)其onBind方法,目的就是為了返回告訴系統(tǒng)當(dāng)前應(yīng)用的Authenticator的binder引用。以便系統(tǒng)可以調(diào)用我們自定義的Authenticator中的相關(guān)操作,以便實(shí)現(xiàn)賬戶功能。

5、新建4中提到的MyAuthenticator,該類是繼承自AbstractAccountAuthenticator

public class MyAuthenticator extends AbstractAccountAuthenticator {
 ?
      private Context mContext;
      public MyAuthenticator(Context context) {
          super(context);
          this.mContext = context;
      }
  ......
  @Override
  public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
      Intent intent = new Intent(mContext, AccountActivity.class);
      intent.putExtra(AccountActivity.ARG_ACCOUNT_TYPE, accountType);
      intent.putExtra(AccountActivity.ARG_AUTH_TYPE, authTokenType);
 intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
       final Bundle bundle = new Bundle();
       bundle.putParcelable(AccountManager.KEY_INTENT, intent); //1
       return bundle; //2
  }

  String authToken;
  @Override
  public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
       final AccountManager am = AccountManager.get(mContext);  //3
       authToken = am.peekAuthToken(account, authTokenType);  //4
       if (TextUtils.isEmpty(authToken)) {  //5
            final String password = am.getPassword(account);
            if (password != null) {
            //向服務(wù)器再次請(qǐng)求
       }

        //  authToken = sServerAuthenticate.userSignIn(account.name, password, authTokenType);   //調(diào)用服務(wù)端認(rèn)證登錄,獲取其authToken
  
        //認(rèn)證成功
       if (!TextUtils.isEmpty(authToken)) {  //6
           Log.d("wx","authentication success");
           final Bundle result = new Bundle();
           result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
           result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
           result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
           return result;
      }
 ?
      //未注冊(cè)過(guò)
      Log.d("wx","never registered.");  //7
      final Intent intent = new Intent(mContext, AccountActivity.class);
   intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONS E, response);
      intent.putExtra(AccountActivity.ARG_ACCOUNT_TYPE, account.type);
      intent.putExtra(AccountActivity.ARG_AUTH_TYPE, authTokenType);
      final Bundle bundle = new Bundle();
      bundle.putParcelable(AccountManager.KEY_INTENT, intent);
      return bundle;
  }
  ......
 }

新建的Authenticator繼承系統(tǒng)的AbstractAccountAuthenticator后,我們需要實(shí)現(xiàn)其中的抽象方法,我們主要需要實(shí)現(xiàn)其中的addAccount()和getAuthenToken()方法,其他的默認(rèn)實(shí)現(xiàn)即可。

首先看到addAccount()方法,我們就是新建Intent意圖,并將該Intent封裝到Bundle中。目的是告訴系統(tǒng)我們的登錄界面,以及當(dāng)前應(yīng)用的賬戶類型(包名),系統(tǒng)會(huì)去提取該Bundle中意圖,然后去啟動(dòng)我們指定的登錄界面進(jìn)行登錄操作。通過(guò)指定AccountManager.KEY_INTENT告訴系統(tǒng)我們的intent信息。

然后是getAuthToken()方法。首先在注釋1,獲得其AccountManager引用。然后通過(guò)它調(diào)用peekAuthToken獲取當(dāng)前賬戶信息的authToken。若該authToken為空的話,則會(huì)進(jìn)入注釋5,將該賬戶信息向服務(wù)端發(fā)起認(rèn)證請(qǐng)求。若認(rèn)證成功的話,則會(huì)進(jìn)入注釋6,我們直接返回該bundle即可。最后若沒(méi)認(rèn)證則進(jìn)入注釋7,代表該賬戶從未進(jìn)行過(guò)注冊(cè),需要跳轉(zhuǎn)到登錄界面進(jìn)行注冊(cè)登錄。

賬戶系統(tǒng)的基本布置就是如此,當(dāng)然還有Authenticator中其他的抽象方法進(jìn)行相關(guān)的操作。

基本使用(注冊(cè)、登錄和退出)

注冊(cè)

當(dāng)環(huán)境配置完后,我們只需通過(guò)AccountManager,調(diào)用其addAccount()方法就可完成一個(gè)賬戶信息的注冊(cè)

Account account = new Account(username,ARG_ACCOUNT_TYPE);  //1
AccountManager am = AccountManager.get(AccountActivity.this);  //2
am.addAccountExplicitly(account,pwd,null);  //3

注釋1,創(chuàng)建當(dāng)前用戶對(duì)應(yīng)的Account封裝;注釋2,獲取AccountManager引用;注釋3,調(diào)用addAccountExplicitly()方法進(jìn)行賬戶添加(內(nèi)部有幾個(gè)addAccountXXX方法,將在源碼分析中再進(jìn)行說(shuō)明)。

登錄

登錄時(shí)我們通過(guò)調(diào)用getAuthToken()方法進(jìn)行登錄操作,關(guān)于驗(yàn)證及驗(yàn)證結(jié)果的操作在getAuthToken的講解中已進(jìn)行過(guò)說(shuō)明。

Account account = new Account(username,ARG_ACCOUNT_TYPE);  //1
AccountManager am = AccountManager.get(AccountActivity.this);  //2
AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { //3
  @Override
  public void run(AccountManagerFuture<Bundle> future) {
      try {
           Log.d("wx","ok run");
           Intent it = new Intent(AccountActivity.this, MainActivity.class);
           startActivity(it);
      }catch (Exception e){}
  }
 };
 am.getAuthToken(account,ARG_ACCOUNT_TYPE,null,AccountActivity.this,callback,null); //4

注釋1,獲取當(dāng)前需登錄的賬戶封裝,注釋2,獲取AccountManager引用,注釋3,我們定義了一個(gè)AccountManagerCallback,為了接收驗(yàn)證成功的結(jié)果回調(diào)。注釋4,調(diào)用AccountManager的getAuthToken()進(jìn)行登錄操作。

退出

對(duì)于Android賬戶系統(tǒng)來(lái)說(shuō),要退出代表移除當(dāng)前賬戶,及時(shí)再輸入其用戶名和密碼也沒(méi)有,就像從未注冊(cè)過(guò)一樣,因此該操作若需要的話建議在系統(tǒng)設(shè)置中操作。我們通過(guò)AccountManager.invalidateAuthToken ()方法將該賬戶的authToken置為無(wú)效。

以上是賬戶相關(guān)的基本操作,更詳細(xì)可參考附錄1中的信息。

附錄

1、http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容