建立虛設常式驗證器

同步轉換介面架構會假設您的同步轉接器在與帳戶和伺服器儲存空間相關聯,且需要登入存取權的裝置儲存空間之間傳輸資料。因此,架構會預期您提供名為驗證器的元件做為同步轉換器的一部分。這個元件可以插入 Android 帳戶和驗證架構,並提供標準介面,用於處理登入資訊等使用者憑證。

即使您的應用程式不使用帳戶,您還是需要提供驗證器元件。如未使用帳戶或伺服器登入資訊,系統會忽略驗證器處理的資訊,因此您可以提供含有虛設常式方法實作的驗證器元件。您還需要提供繫結的 Service,讓同步轉接程式架構呼叫驗證器的方法。

本課程將說明如何定義每個虛設常式驗證器的全部部分,滿足同步轉接介面架構的需求。如果您需要提供處理使用者帳戶的實際驗證器,請參閱 AbstractAccountAuthenticator 的參考說明文件。

新增虛設常式驗證器元件

如要在應用程式中新增虛設常式驗證器元件,請建立擴充 AbstractAccountAuthenticator 的類別,然後傳回 null 或擲回例外狀況,藉此破解必要方法。

以下程式碼片段是虛設常式驗證器類別的範例:

Kotlin

/*
 * Implement AbstractAccountAuthenticator and stub out all
 * of its methods
 */
class Authenticator(context: Context) // Simple constructor
    : AbstractAccountAuthenticator(context) {

    // Editing properties is not supported
    override fun editProperties(r: AccountAuthenticatorResponse, s: String): Bundle {
        throw UnsupportedOperationException()
    }

    // Don't add additional accounts
    @Throws(NetworkErrorException::class)
    override fun addAccount(
            r: AccountAuthenticatorResponse,
            s: String,
            s2: String,
            strings: Array<String>,
            bundle: Bundle
    ): Bundle?  = null

    // Ignore attempts to confirm credentials
    @Throws(NetworkErrorException::class)
    override fun confirmCredentials(
            r: AccountAuthenticatorResponse,
            account: Account,
            bundle: Bundle
    ): Bundle?  = null

    // Getting an authentication token is not supported
    @Throws(NetworkErrorException::class)
    override fun getAuthToken(
            r: AccountAuthenticatorResponse,
            account: Account,
            s: String,
            bundle: Bundle
    ): Bundle {
        throw UnsupportedOperationException()
    }

    // Getting a label for the auth token is not supported
    override fun getAuthTokenLabel(s: String): String {
        throw UnsupportedOperationException()
    }

    // Updating user credentials is not supported
    @Throws(NetworkErrorException::class)
    override fun updateCredentials(
            r: AccountAuthenticatorResponse,
            account: Account,
            s: String,
            bundle: Bundle
    ): Bundle {
        throw UnsupportedOperationException()
    }

    // Checking features for the account is not supported
    @Throws(NetworkErrorException::class)
    override fun hasFeatures(
            r: AccountAuthenticatorResponse,
            account: Account,
            strings: Array<String>
    ): Bundle {
        throw UnsupportedOperationException()
    }
}

Java

/*
 * Implement AbstractAccountAuthenticator and stub out all
 * of its methods
 */
public class Authenticator extends AbstractAccountAuthenticator {
    // Simple constructor
    public Authenticator(Context context) {
        super(context);
    }
    // Editing properties is not supported
    @Override
    public Bundle editProperties(
            AccountAuthenticatorResponse r, String s) {
        throw new UnsupportedOperationException();
    }
    // Don't add additional accounts
    @Override
    public Bundle addAccount(
            AccountAuthenticatorResponse r,
            String s,
            String s2,
            String[] strings,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }
    // Ignore attempts to confirm credentials
    @Override
    public Bundle confirmCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            Bundle bundle) throws NetworkErrorException {
        return null;
    }
    // Getting an authentication token is not supported
    @Override
    public Bundle getAuthToken(
            AccountAuthenticatorResponse r,
            Account account,
            String s,
            Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
    // Getting a label for the auth token is not supported
    @Override
    public String getAuthTokenLabel(String s) {
        throw new UnsupportedOperationException();
    }
    // Updating user credentials is not supported
    @Override
    public Bundle updateCredentials(
            AccountAuthenticatorResponse r,
            Account account,
            String s, Bundle bundle) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
    // Checking features for the account is not supported
    @Override
    public Bundle hasFeatures(
        AccountAuthenticatorResponse r,
        Account account, String[] strings) throws NetworkErrorException {
        throw new UnsupportedOperationException();
    }
}

將驗證器繫結至架構

為了讓同步轉接程式架構存取驗證器,您必須為其建立繫結服務。這項服務提供 Android 繫結器物件,可讓架構呼叫驗證器,並在驗證器和架構之間傳遞資料。

下列程式碼片段說明如何定義繫結的 Service

Kotlin

/**
* A bound Service that instantiates the authenticator
* when started.
*/
class AuthenticatorService : Service() {

    // Instance field that stores the authenticator object
    private lateinit var mAuthenticator: Authenticator

    override fun onCreate() {
        // Create a new authenticator object
        mAuthenticator = Authenticator(getApplicationContext())
    }

    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    override fun onBind(intent: Intent?): IBinder = mAuthenticator.iBinder
}

Java

/**
 * A bound Service that instantiates the authenticator
 * when started.
 */
public class AuthenticatorService extends Service {
    ...
    // Instance field that stores the authenticator object
    private Authenticator mAuthenticator;
    @Override
    public void onCreate() {
        // Create a new authenticator object
        mAuthenticator = new Authenticator(getApplicationContext());
    }
    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mAuthenticator.getIBinder();
    }
}

新增驗證器中繼資料檔案

如要將驗證器元件插入同步轉接器和帳戶架構,您必須為這些架構提供描述元件的中繼資料。這個中繼資料會宣告您為同步轉換介面建立的帳戶類型,並宣告系統顯示的使用者介面元素,以讓使用者看見您的帳戶類型。請在應用程式專案中的 /res/xml/ 目錄中,以 XML 檔案宣告這些中繼資料。您可以命名檔案名稱,但名稱通常為 authenticator.xml

這個 XML 檔案包含單一元素 <account-authenticator>,具有下列屬性:

android:accountType
同步轉換介面架構要求每個同步轉接器都有以網域名稱的形式擁有帳戶類型。這個架構會使用帳戶類型做為同步轉接程式的內部識別的一部分。對於需要登入的伺服器,系統會將帳戶類型以及使用者帳戶,做為登入憑證的一部分傳送至伺服器。

如果您的伺服器不需要登入,您仍然需要提供帳戶類型。針對值,請使用由您控管的網域名稱。雖然架構會使用這個架構管理同步轉接器,但系統不會將這個值傳送至您的伺服器。

android:icon
指標指向包含圖示的可繪項目資源。如果您在 res/xml/syncadapter.xml 中指定 android:userVisible="true" 屬性,讓系統顯示同步轉換介面,則必須提供這個圖示資源。它會顯示在系統「設定」應用程式的「帳戶」部分。
android:smallIcon
指向包含小圖示版本的可繪項目資源。視螢幕大小而定,系統可能會在系統「設定」應用程式「帳戶」部分中使用這項資源,而非 android:icon
android:label
可為使用者提供帳戶類型的本地化字串,如果您在 res/xml/syncadapter.xml 中指定 android:userVisible="true" 屬性,讓系統顯示同步轉換介面,則應提供這個字串。這個名稱會顯示在系統「設定」應用程式的「帳戶」部分,在您為驗證器定義的圖示旁邊。

下列程式碼片段顯示了您先前所建立驗證器的 XML 檔案:

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:accountType="example.com"
        android:icon="@drawable/ic_launcher"
        android:smallIcon="@drawable/ic_launcher"
        android:label="@string/app_name"/>

在資訊清單中宣告驗證器

在上一個步驟中,您建立了繫結 Service,將驗證器連結至同步轉接器架構。為了向系統識別這項服務,請新增下列 <service> 元素做為 <application> 的子項元素,在應用程式的資訊清單中進行宣告:

    <service
            android:name="com.example.android.syncadapter.AuthenticatorService">
        <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator"/>
        </intent-filter>
        <meta-data
            android:name="android.accounts.AccountAuthenticator"
            android:resource="@xml/authenticator" />
    </service>

<intent-filter> 元素會設定由意圖動作 android.accounts.AccountAuthenticator 觸發的篩選器,並由系統傳送來執行驗證器。觸發篩選器時,系統會啟動 AuthenticatorService,也就是您提供的繫結 Service 來包裝驗證器。

<meta-data> 元素會宣告驗證器的中繼資料。android:name 屬性會將中繼資料連結至驗證架構。android:resource 元素會指定您先前建立的驗證器中繼資料檔案名稱。

除了驗證器之外,同步轉換介面也需要內容供應器。如果應用程式並未使用內容供應器,請前往下一堂課程,瞭解如何建立虛設常式內容供應器;否則,請參閱「建立同步處理轉接器」課程。