创建桩身份验证器

同步适配器框架假定您的同步适配器在设备存储空间之间传输数据 与需要登录访问权限的账号和服务器存储空间相关联。因此, 框架要求您在同步过程中提供一个名为身份验证器的组件 适配器。该组件可插入到 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 binder 对象,允许框架 来调用身份验证器并在身份验证器和框架之间传递数据。

以下代码段展示了如何定义绑定 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();
    }
}

添加身份验证器元数据文件

要将身份验证器组件插入到同步适配器框架和账号框架中,您需要: 为这些框架提供描述组件的元数据。此元数据声明了 您为同步适配器创建的账号类型,并声明了界面元素 。声明 XML 文件中的元数据,该文件存储在应用项目的 /res/xml/ 目录中。 您可以为该文件指定任何名称,但通常将它命名为 authenticator.xml

此 XML 文件包含一个 <account-authenticator> 元素, 具有以下属性:

android:accountType
同步适配器框架要求每个同步适配器都具有账号类型,形式为 域名。该框架将账号类型用作同步适配器的一部分。 内部标识。对于要求登录的服务器,账号类型以及 系统会将用户账号作为登录凭据的一部分发送到服务器。

即使服务器不要求提供登录信息,您仍然需要提供账号类型。对于 值,请使用由您控制的域名。虽然框架使用它来管理 同步适配器,则该值不会发送到您的服务器。

android:icon
指向可绘制对象的指针 包含图标的资源。如果您通过指定 res/xml/syncadapter.xml 中的 android:userVisible="true" 属性, 那么您必须提供此图标资源。该 ID 会显示在 系统应用的“设置”应用。
android:smallIcon
指向可绘制对象的指针 资源,其中包含小版图标。该资源可用于代替 android:icon(位于系统“设置”应用的账号部分), 具体取决于屏幕大小
android:label
用于向用户标识账号类型的可本地化字符串。如果您将同步适配器 指定属性 android:userVisible="true" res/xml/syncadapter.xml,则应提供此字符串。它出现在 系统“设置”应用的账号部分(位于您为 身份验证器。

以下代码段显示了您之前创建的身份验证器的 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> 元素设置由 intent 操作触发的过滤器 android.accounts.AccountAuthenticator,由系统发送,用于运行 身份验证器。当过滤器被触发时,系统会启动 AuthenticatorService, 您提供的用于封装身份验证器的绑定 Service

通过 <meta-data> 元素声明身份验证器的元数据。通过 android:name 属性将元数据链接到身份验证框架。通过 android:resource 元素指定您之前创建的身份验证器元数据文件的名称。

除身份验证器之外,同步适配器还需要内容提供器。如果您的应用 已在使用 content provider,请继续学习下一课,了解如何创建桩内容 提供商;否则,请转到创建同步适配器一课。