再次理解Android账号管理体系

目录

✅ 0. 需求

📂 1. 前言

🔱 2. 使用

2.1 账户体系前提

2.2 创建账户服务

2.3 操作账户-增删改查

💠 3. 源码流程


✅ 0. 需求

        试想,自己去实现一个账号管理体系,该如何做呢?

        ——————————

        最近有遇到这样一个需求:AR眼镜只支持同时与一个手机绑定,即:AR眼镜已与手机绑定过的话,不再支持与其他手机绑定;如要绑定其他手机,需要先解绑当前手机才能重新绑定。

        理解一下需求,即是:眼镜端需要账号管理体系,主要用来存储已绑定过手机的token。

        AR眼镜绑定手机时序图,如下所示:


 

📂 1. 前言

        我们知道,Android的账号管理体系是用来管理用户在Android设备上的身份验证和授权的系统,包括了对账号的创建、授权、修改和删除等操作的管理。

        那么,我们为什么要使用Android的账号管理体系?

        ——————————

        尽管,我们可以自己使用SP、MMKV、文件或数据库等方式来存储、更新、删除账户、密码或AuthToken;但其实涉及到跨进程通信,实现起来其实是稍显麻烦的;并且对于数据安全,信息加密这块的可靠性也有待商榷。

        另外,从本文第一张图可见,我们在架构设计中规划的账号体系服务,是寄生于Android启动时system_server开启的服务,然后通过binder方式,提供给其他进程使用。

        然而,在技术预研时发现,强大的Android早已想到了这点,在Android 2.0开始就加入了新包android.accounts,为我们准备好了这样一个服务ACCOUNT_SERVICE。

        而且,该包功能已十分强大,我们可以直接拿来使用,功能主要包括:

  1. 集中式的账户管理API,可以安全地存储和访问认证的令牌和密码;
  2. 可以在同一个设备中管理同一应用的多个不同账号,能够自动批量的同步服务器更新账户,甚至可以和不同服务器进行数据同步和安全认证;
  3. 把账户的验证过程、AuthToken的获取过程分离出来,降低程序的耦合性;
  4. 并且会在”设置”应用中添加一个账户入口;
  5. 方便应用间账号共享。

🔱 2. 使用

2.1 账户体系前提

        1)账号体系共享前提:使用相同的签名

        2)权限申明:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

2.2 创建账户服务

        步骤一:定义一个action为android.accounts.AccountAuthenticator的Intent的Service,并在meta-data的resource属性指定该Account基本显示信息的xml文件authenticator,模版代码如下:

<serviceandroid:name=".portal.feature.account.service.AccountService"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.accounts.AccountAuthenticator" /></intent-filter><meta-dataandroid:name="android.accounts.AccountAuthenticator"android:resource="@xml/authenticator" />
</service>

        步骤二:在res下的xml文件夹中新建authenticator.xml文件:

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

        :android:accountType表示的是Account类型,它必须是唯一的,一般是包名。

        步骤三:创建继承自AbstractAccountAuthenticator的Authenticator文件,如下:

class Authenticator(context: Context) : AbstractAccountAuthenticator(context) {override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?): Bundle? {return null}override fun addAccount(response: AccountAuthenticatorResponse?,accountType: String?,authTokenType: String?,requiredFeatures: Array<out String>?,options: Bundle?): Bundle? {return null}override fun getAuthToken(response: AccountAuthenticatorResponse?,account: Account,authTokenType: String?,options: Bundle?): Bundle? {return null}override fun confirmCredentials(response: AccountAuthenticatorResponse?, account: Account?, options: Bundle?): Bundle? {return null}override fun getAuthTokenLabel(authTokenType: String?): String {return ""}override fun updateCredentials(response: AccountAuthenticatorResponse?,account: Account?,authTokenType: String?,options: Bundle?): Bundle? {return null}override fun hasFeatures(response: AccountAuthenticatorResponse?, account: Account?, features: Array<out String>?): Bundle? {return null}}

        步骤四:创建帐户Service,并在Service的onBind中调AbstractAccountAuthenticator的getIBinder()返回其用于远程调用的IBinder,如下所示:

class AccountService : Service() {private var authenticator: Authenticator? = nulloverride fun onCreate() {super.onCreate()authenticator = Authenticator(this)}override fun onBind(intent: Intent?): IBinder? {return authenticator?.iBinder}}

        :运行起来程序后,在“设置”应用-“帐户”-“添加帐户”列表中就已可以发现自己的app了。

2.3 操作账户-增删改查

        1)获取所有账号

    /*** 获取所有账号*/fun getAllAccount(context: Context) {val accountManager = context.getSystemService(Context.ACCOUNT_SERVICE) as AccountManagerLog.e(TAG, "getAllAccount: size = ${accountManager.accounts.size}")for (account in accountManager.accounts) {Log.e(TAG, "getAllAccount: $account")}}

         2)添加账号

    /*** 添加账号*/fun addAccount(context: Context, account: Account, password: String, authToken: String) {val bundle = Bundle()bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name)bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)bundle.putString(AccountManager.KEY_AUTHTOKEN, authToken)bundle.putString(AccountManager.KEY_PASSWORD, password)AccountManager.get(context).addAccountExplicitly(account, password, bundle)}

         3)更新某个账号

    /*** 更新某个账号*/fun updateAccount(context: Context, account: Account, password: String = "", authToken: String = "") {var updatePassword = passwordvar updateAuthToken = authTokenAccountManager.get(context).apply {if (updatePassword.isEmpty()) {updatePassword = getUserData(account, AccountManager.KEY_PASSWORD)}if (updateAuthToken.isEmpty()) {updateAuthToken = getUserData(account, AccountManager.KEY_AUTHTOKEN)}removeAccountExplicitly(account)}addAccount(context, account, updatePassword, updateAuthToken)}

         4)删除某个账号

    /*** 删除某个账号*/fun delAccount(context: Context, account: Account) {val isRemoveSuccess = AccountManager.get(context).removeAccountExplicitly(account)Log.e(TAG, "delAllAccount: isRemoveSuccess = $isRemoveSuccess, $account")}

          5)删除所有账号

    /*** 删除所有账号*/fun delAllAccount(context: Context) {val accountManager = AccountManager.get(context)for (account in accountManager.accounts) {val isRemoveSuccess = accountManager.removeAccountExplicitly(account)Log.e(TAG, "delAllAccount: isRemoveSuccess = $isRemoveSuccess, $account")}}

💠 3. 源码流程

  • 从系统启动system_server进程,进而启动ACCOUNT_SERVICE服务开始;
  • AccountManager是一个面向应用程序开发的组件,它提供了一套对应于IAccountManager协议的应用程序接口;
  • 这组接口通过Binder机制与系统服务AccountManagerService进行通信,协作完成帐号相关的操作;
  • 同时AccountManager接收authenticators提供的回调,以便在帐号操作完成之后向调用此帐号服务的业务返回对应的接口,同时触发这个业务对结果的处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/135172.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 学习笔记(基础)

首先解释数据库DataBase&#xff08;DB&#xff09;&#xff1a;即存储数据的仓库&#xff0c;数据经过有组织的存储 数据库管理系统DataBase Management System&#xff08;DBMS&#xff09;&#xff1a;管理数据库的软件 SQL&#xff08;Structured Query Language&#xf…

3D视觉到三维视觉之结构光

3D视觉是计算机视觉的终极体现形式 2D视觉技术主要在二维空间下完成工作&#xff0c;三维信息基本上没有得到任何利用&#xff0c;而三维信息才真正能够反映物体和环境的状态&#xff0c;也更接近人类的感知模式。近年来&#xff0c;学术界和工业界推出了一系列优秀的算法和产…

redis 哨兵(sentinel)机制

1. 前言 sentinel&#xff08;哨兵&#xff09;是Redis 的高可用性解决方案之一。通过哨兵可以创建一个当主服务器出现故障时自动将从服务器升级为主服务器的分布式系统&#xff0c;解决了主从复制出现故障时需要人为干预的问题。 redis 的主从复制的作用有数据预热、负载均衡…

【初阶数据结构】树(tree)的基本概念——C语言

目录 一、树&#xff08;tree&#xff09; 1.1树的概念及结构 1.2树的相关概念 1.3树的表示 1.4树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二、二叉树的概念及结构 2.1二叉树的概念 2.2现实中真正的二叉树 2.3特殊的二叉树 2.4二叉树的性质…

使用 Feature Flags 实现数据库灰度迁移的监控与可观测性

作者&#xff1a;观测云与胡博 场景描述 很多企业会遇到数据库升级、或数据库迁移的情况&#xff0c;尤其是在自建数据库服务向云数据库服务、自建机房向云机房、旧数据库向新数据库迁移等场景。 然而&#xff0c;我们需要在整个移植过程中保证其稳定性、避免数据遗失、服务宕…

获取spring容器中的bean实例

在开发过程中&#xff0c;我们可能需要动态获取spring容器中的某个bean的实例&#xff0c;此时我们就会用到ApplicationContext spring应用上下文&#xff0c;这里做一下记录&#xff0c;网上很多类似的的工具类。 先写好工具类再测试一下是否好用 工具类&#xff1a; packag…

【pytest】生成测试报告

0. 脚本&#xff1a; fixture/test_fixtures_02.py # 功能函数 import pytestdef multiply(a, b):return a * bclass TestMultiply:# fixturesclassmethoddef setup_class(cls):print("setup_class>")classmethoddef teardown_class(cls):print("teardown_c…

最小二乘法

Least Square Method 1、相关的矩阵公式2、线性回归3、最小二乘法3.1、损失函数&#xff08;Loss Function&#xff09;3.2、多维空间的损失函数3.3、解析法求解3.4、梯度下降法求解 1、相关的矩阵公式 P r e c o n d i t i o n : ξ ∈ R n , A ∈ R n ∗ n i : σ A ξ σ ξ…

Linux驱动之INPUT设备驱动

目录 一、开发环境 二、编写按键input设备的注册与事件上报 2.1 修改设备树文件 1 添加 pinctrl 节点 2、添加 KEY 设备节点 3、检查 PIN 是否被其他外设使用 2.2 驱动程序编写 2.3 测试APP编写 2.4 运行测试 三、Linux内核自带按键input设备驱动 3.1 自带按键驱动程序源码简…

C#实现钉钉自定义机器人发送群消息帮助类

一、自定义机器人发送群消息使用场景 在企业中,针对一些关键指标内容(如每天的生产产量、每天的设备报警信息等信息),需要同时给多人分享,此时就可以将需要查看这些数据的人员都拉到一个群中,让群里的机器人将这些关键指标内容推送到群里即可【(目前已实现在钉钉群里创建…

Web 器学习笔记(基础)

Filter 过滤器 概念&#xff1a;表示过滤器&#xff0c;是 JavaWeb 三大组件&#xff08;Servlet、Filter、Listener&#xff09;之一 作用&#xff1a;顾名思义可以过滤资源的请求&#xff0c;并实现特殊的需求 Filter 接口及它核心的 doFilter() 方法&#xff08;执行前就是…

Excel 公式函数:学习基本示例

数据准备 对于本教程&#xff0c;我们将使用以下数据集。 家居用品预算 S / N项目数量价格小计价格适中吗&#xff1f;1芒果96002橘子312003番茄125004食用油565005汤力水133900 房屋建筑项目时间表 S/NITEM开始日期结束日期持续时间&#xff08;天&#xff09;1调查土地0…

000_差分信号

1.什么是差分信号 差分信号又叫做差模信号&#xff0c;使用差分信号传输时&#xff0c;需要2根信号线&#xff0c;这2根信号线的振幅相等&#xff0c;相位相反&#xff0c;通过2根信号线的电压差值来表示逻辑0和逻辑1。 差分信号表示逻辑值如下图&#xff1a; 2.差分信号的特…

IDEA2023.2.1中创建第一个Tomcat的web项目

首先&#xff0c;创建一个普通的java项目。点击【file】-【new】-【project】 创建一个TomcatDemo项目 创建如下图 添加web部门。点击【file】-【project structure】 选择【modules】-选中项目“TomcatDemo” 点击项目名上的加号【】&#xff0c;添加【web】模块 我们就会发现…

【Vue】快速入门案例与工作流程的讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Vue快速入门》。&#x1f…

Springboot 实践(18)Nacos配置中心参数自动刷新测试

前文讲解了Nacos 2.2.3配置中心的服务端的下载安装&#xff0c;和springboot整合nacos的客户端。Springboot整合nacos关键在于使用的jar版本要匹配&#xff0c;文中使用版本如下&#xff1a; ☆ springboot版本: 2.1.5.RELEASE ☆ spring cloud版本 Greenwich.RELEASE ☆ sp…

学信息系统项目管理师第4版系列09_配置管理

1. 配置管理 1.1. 应用技术的和管理的指导和监控方法以标识和说明配置项的功能和物理特征&#xff0c;控制这些特征的变更&#xff0c;记录和报告变更处理和实现状态并验证与规定的需求的遵循性 1.1.1. GB/T 11457《信息技术软件工程术语》 2. 配置项 2.1. Configuration I…

Scapy 解析 pcap 文件从HTTP流量中提取图片

Scapy 解析 pcap 文件从HTTP流量中提取图片 前言一、网络环境示例二、嗅探流量示例三、pcap 文件处理最后参考 ​ 作者&#xff1a;高玉涵 ​ 时间&#xff1a;2023.9.17 10:25 ​ 环境&#xff1a;Linux kali 5.15.0-kali3-amd64&#xff0c;Python 3.11.4&#xff0c;scapy…

线性代数的本质(二)——线性变换与矩阵

文章目录 线性变换与矩阵线性变换与二阶方阵常见的线性变换复合变换与矩阵乘法矩阵的定义列空间与基矩阵的秩逆变换与逆矩阵 线性变换与矩阵 线性变换与二阶方阵 本节从二维平面出发学习线性代数。通常选用平面坐标系 O x y Oxy Oxy &#xff0c;基向量为 i , j \mathbf i,…

什么是无人机全自动飞行系统?概念、构成、作用深度解析

无人机的工业化应用深入催生出新的痛点&#xff0c;无人机应用飞手培养难、成本高、技术参差不齐&#xff0c;以及应急响应和采集作业价值等没有得到充分释放&#xff0c;由此无人机自动飞行系统、无人机自动机场横空出世&#xff0c;因其无人化、自动化、无人机值守的应用特性…