Android帐号同步机制详解

本文详细介绍了Android账号同步机制,包括整体理解、账号、账号同步的实现步骤,如添加身份验证器、同步适配器、内容提供者,并探讨了如何运行账号同步以及实现数据同步。同时,文章讨论了在实现过程中遇到的问题,如更改同步项名称、添加多个同步项以及设置默认选中状态的解决方案。
部署运行你感兴趣的模型镜像

整体理解

Android帐号同步是一个系统的机制,是由系统调度的,可以配置运行策略的同步机制,实际上通常是配合同步适配器工作的https://developer.android.google.cn/training/sync-adapters/index.html
从文档的描述及实际的使用方式来看,帐号同步机制应该是同步适配器的延伸,就是需要同步的数据是需要验证身份和用户凭据的

帐号

这里的帐号和不是我们通常理解的App的帐号,App的帐号相关信息是由App的服务器存储的,这里帐号是由Android系统提供的服务存储的,可以理解为帐号的服务端是系统,系统负责存储这些帐号的相关信息,并且,文档提到,不应该在这里存储敏感的用户信息,因为root后这里的数据将可以被读取

帐号同步的实现

下边实现一个完整的帐号同步的例子,以pixel 2手机为例,其他手机的界面可能不太一样,但功能应该是一致的

如果实现了帐号同步并添加了帐号,在系统的设置-帐号界面是能看到我们添加的帐号的,在添加帐号界面,则会显示我们App的帐号类型
系统设置-帐号页面
添加帐号页面

添加身份验证器

public class AccountAuthenticator extends AbstractAccountAuthenticator {

    private Context mContext;

    public AccountAuthenticator(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
        Intent intent = new Intent(mContext, AddAccountActivity.class);
        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
        Bundle bundle = new Bundle();
        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
        return bundle;
    }

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
        return null;
    }

    //...其他方法空实现即可

}

添加身份验证器服务

这个服务是系统与应用交互的入口,注册了这个服务,系统就能找到应用中帐号身份验证器并与应用交互,这里只需要简单实例化AccountAuthenticator并返回一个IBinder对象即可,系统已经把主要的逻辑已经在AccountAuthenticator的父类AbstractAccountAuthenticator里封装好了

class AuthenticatorService : Service() {

    private var accountAuthenticator: AccountAuthenticator? = null

    override fun onCreate() {
        super.onCreate()
        accountAuthenticator = AccountAuthenticator(this)
    }

    override fun onBind(intent: Intent): IBinder {
        return accountAuthenticator!!.iBinder
    }

}

在AndroidManifest.xml文件注册

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

authenticator.xml文件内容如下,这里accountType声明了App可以添加的帐号的类型(为了保证唯一性,一般和包名相同),其他配置是系统的设置页面会使用到

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="com.axl.accountmanagertest"
    android:icon="@mipmap/ic_launcher_round"
    android:label="@string/authenticator_name"
    android:smallIcon="@mipmap/ic_launcher_round" />

这样,在添加帐号页面,就能看到我们的App的帐号类型了

这样就可以通过系统的界面添加帐号了(也可以不使用系统的界面,直接用代码添加),在系统界面点击添加帐号,选择我们的App的时候,会回调到AccountAuthenticatoraddAccount()方法,在这里可以直接添加帐号或者提供一个UI进行帐号的添加,上述代码是提供了一个添加帐号的UI,所以在系统界面点击添加帐号的的时候会启动App的界面
在这里插入图片描述
添加帐号只需要调用addAccountExplicitly()方法

val manager = AccountManager.get(this)
val account = Account(accountName, Constants.ACCOUNT_TYPE)
manager.addAccountExplicitly(account, null, null)

添加同步适配器

class AccountSyncAdapter extends AbstractThreadedSyncAdapter {

    public AccountSyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
    }
}

添加同步适配器服务

这里和身份验证器类似,系统通过这个服务找到App里的同步适配器

public class AccountSyncService extends Service {

    private static final Object sSyncAdapterLock = new Object();

    private static AccountSyncAdapter sAccountSyncAdapter = null;

    @Override
    public void onCreate() {
        synchronized (sSyncAdapterLock) {
            if (sAccountSyncAdapter == null) {
                sAccountSyncAdapter = new AccountSyncAdapter(getApplicationContext(), true);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return sAccountSyncAdapter.getSyncAdapterBinder();
    }
}

在AndroidManifest.xml文件注册

<service
    android:name=".AccountSyncService"
    android:exported="true">
    <intent-filter>
        <action android:name="android.content.SyncAdapter" />
    </intent-filter>

    <meta-data
        android:name="android.content.SyncAdapter"
        android:resource="@xml/syncadapter" />

</service>

同样,这里需要一个配置的资源文件,syncadapter.xml内容如下

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
    // 帐号类型,必须与在创建身份验证器元数据文件提供的帐号类型值相同,即添加的帐号类型
    android:accountType="com.axl.accountmanagertest"
    // 允许同步适配器组件的多个实例同时运行
    android:allowParallelSyncs="false"
    // ContentProvider的URI访问权限,同步适配器机制必须提供一个ContentProvider
android:contentAuthority="com.axl.accountmanagertest.AccountSyncProvider"
    // 告知同步适配器框架它可以在指定的任何时间运行同步适配器,如果希望通过编程方式控制同步适配器的运行时间,将此标记设置为false,然后调用requestSync()来运行同步适配器
    android:isAlwaysSyncable="true"
    // 允许将数据上传到云端,如果应用仅下载数据,将该属性设为false
    android:supportsUploading="false"
    // 设置同步适配器帐号类型的可见性,默认情况下,与帐号类型关联的帐号图标和标签会显示在系统“设置”应用的帐号部分中
    android:userVisible="true" />

添加权限

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>   

添加内容提供者

还需要为同步适配器提供一个ContentProvider,此provider的authorities就是syncadapter.xml文件contentAuthority的值

public class AccountSyncProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }
}

在AndroidManifest.xml文件注册

<provider
    android:name=".AccountSyncProvider"
    android:authorities="com.axl.accountmanagertest.AccountSyncProvider"
    android:exported="false"
    // 设置指示该提供器可同步的标记,如果将此标记设置为true,则无需在代码中调用setIsSyncable(),该标记允许同步适配器框架与内容提供器进行数据传输,但只有当明确执行时才会进行传输
    android:syncable="true" />

这样,在系统设置界面点进添加的帐号详情页,就有这个帐号下可以同步的条目,条目的名字默认是App的名字,可以与Google帐号对比一下
在这里插入图片描述

在这里插入图片描述
看到Google帐号的同步内容选项,对比我们的实现,会有3个问题

  1. 条目的名字怎么改变
  2. 怎么添加更多的条目
  3. 条目的状态怎么设置默认选中

问题1和2没有在官方的文档里找到答案,尝试了一下,同步项的名字可以在AndroidManifest.xml文件注册provider时,通过指定label来修改,添加多个同步项则可以是提供多个适配器服务和内容提供者(是否有更好的方式?)
在这里插入图片描述

对于问题3,官方文档对于provider标签syncable项的解释,看上去像是设置为true则可以同步,同步项应该是选中的,但是实际运行发现,并没有效果,还是需要在代码中调用

运行帐号同步

  1. 进入系统设置页面,选择同步项后手动点击立即同步
  2. 通过代码开启同步
val accounts: Array<Account> = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE)
accounts.forEach {
    ContentResolver.setIsSyncable(it, Constants.AUTHORITY_1, 1)
    ContentResolver.setSyncAutomatically(it, Constants.AUTHORITY_1, true)
    ContentResolver.addPeriodicSync(it, Constants.AUTHORITY_1, Bundle(), 15 * 60)
}

更多用法可以参考官方文档
https://developer.android.google.cn/training/sync-adapters/running-sync-adapter

实现数据的同步

每次系统调度进行同步的时候,同步适配器的onPerformSync()方法会被回调,应用可以在这里进行数据的同步操作,具体怎么进行服务器认证、拉取或上传数据等由应用控制

帐号维度数据存储

AccountManager提供了API,可以以帐号为维度,实现对String类型数据的存储

manager.setUserData(account, key, value)
manager.getUserData(account, key)

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值