Android NDK开发详解连接性之创建存根身份验证程序

使用同步适配器传输数据

注意:对于大多数后台处理用例,我们建议使用 WorkManager 作为解决方案。请参考后台处理指南,了解哪一种解决方案最适合您。

在 Android 设备和网络服务器之间同步数据,可以显著提高您的应用对于用户的实用性和吸引力。例如,将数据上传到网络服务器可以创建有用的备份,而从服务器下载数据则可让用户在设备离线时仍可使用数据。在某些情况下,用户可能会发现在网页界面中输入和修改数据,然后在设备上使用这些数据会更加轻松;或者,他们可能会希望随着时间推移慢慢收集数据,然后将其上传到中央存储区。

虽然您可以设计自己的系统用于在应用中执行数据传输,但您也可以考虑使用 Android 的同步适配器框架。此框架可以帮助您管理数据传输和实现数据传输的自动化,还可以协调不同应用之间的同步操作。如果使用此框架,您可以利用一些您自己设计的数据传输方案所不具备的功能:

插件架构
允许您将数据传输代码作为可调用组件添加到系统中。
自动执行
允许您设置根据各种条件(包括数据更改、在一定时间后或一天中的具体时刻)自动执行数据传输。此外,系统还会将无法运行的传输添加到队列中,并在可能的情况下运行它们。
自动检查网络
系统仅在设备具有网络连接时才运行数据传输。
提高电池使用效率
可让您将应用的所有数据传输任务集中到一个地方,以便于它们同时运行。您的数据传输还会和其他应用的数据传输一起安排。这些因素可减少系统需要开启网络的次数,从而减少对电池电量的消耗。
帐号管理和身份验证
如果您的应用要求提供用户凭据或服务器登录信息,您可以选择性地将帐号管理和身份验证集成到数据传输中。

本课程向您介绍了以下内容:如何创建同步适配器及封装它的绑定 Service,如何提供可帮助您将同步适配器插入框架的其他组件,以及如何以各种方式运行同步适配器。

注意:同步适配器是异步运行的,因此您应该期望它们能够定期、高效地传输数据,但不是即时地传输数据。如果您需要实时传输数据,应通过 AsyncTask 或 IntentService 来实现。
课程

创建存根身份验证程序
了解如何添加同步适配器框架要求您的应用具备的帐号处理组件。为简单起见,本课程介绍了如何创建存根身份验证组件。
创建存根内容提供器
了解如何添加同步适配器框架要求您的应用具备的内容提供器组件。本课程假定您的应用不使用内容提供器,因此介绍了如何添加存根组件。如果您的应用中已经有内容提供器,您可以跳过这一课。
创建同步适配器
了解如何将数据传输代码封装在同步适配器框架能够自动运行的组件中。
运行同步适配器
了解如何使用同步适配器框架触发和调度数据传输。

创建桩身份验证器

同步适配器框架假定您的同步适配器在与帐号相关联的设备存储和要求登录访问权限的服务器存储之间传输数据。为此,框架需要您在同步适配器中提供身份验证器组件。此组件可插入到 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();
        }
    }

将身份验证器绑定到框架

为了使同步适配器框架能够访问您的身份验证器,您必须为其创建绑定 Service。此 Service 提供一个 Android binder 对象,以支持框架调用身份验证器并在身份验证器和框架之间传递数据。

由于框架会在首次需要访问身份验证器时启动此 Service,因此您也可以利用该 Service 来实例化身份验证器,方法是在该 Service 的 Service.onCreate() 方法中调用身份验证器构造函数。

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

        /*
         * 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(this);
        }
        /*
         * 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 文件包含一个元素 ,该元素具有以下属性:

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,请将以下 元素作为 的子元素添加到应用清单中,以此声明该 Service:

        <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 操作 android.accounts.AccountAuthenticator 触发的过滤器,系统发送此操作以运行身份验证器。触发过滤器后,系统会启动 AuthenticatorService,这是您提供的用于封装身份验证器的绑定 Service。

元素用于声明身份验证器的元数据。android:name 属性用于将元数据关联到身份验证框架。android:resource 元素用于指定您之前创建的身份验证器元数据文件的名称。

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

本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。

最后更新时间 (UTC):2020-06-10。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值