当前位置: 首页 > news >正文

再次理解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提供的回调,以便在帐号操作完成之后向调用此帐号服务的业务返回对应的接口,同时触发这个业务对结果的处理。

相关文章:

再次理解Android账号管理体系

目录 ✅ 0. 需求 &#x1f4c2; 1. 前言 &#x1f531; 2. 使用 2.1 账户体系前提 2.2 创建账户服务 2.3 操作账户-增删改查 &#x1f4a0; 3. 源码流程 ✅ 0. 需求 试想&#xff0c;自己去实现一个账号管理体系&#xff0c;该如何做呢&#xff1f; ——————————…...

如何在Blender中压缩/减小GLTF模型的大小

GLTF 如何在Blender中压缩/减小GLTF模型的大小 Blender是一款功能强大的开源软件&#xff0c;旨在创建3D图形&#xff0c;动画和视觉效果。它支持多种文件格式的导入和导出&#xff0c;包括GLB&#xff0c;GLTF&#xff0c;DAE&#xff0c;OBJ&#xff0c;ABC&#xff0c;USD…...

IntelliJ IDEA使用_Plugin插件推荐

官网插件库&#xff1a;https://plugins.jetbrains.com/search 代码规范检测&#xff1a;Alibaba Java Coding Guidelines码云&#xff1a;Giteemybatis插件&#xff1a;MyBatisX多颜色括号&#xff1a;Rainbow Brackets操作快捷键提示&#xff1a;Key Promoter X力扣&#xff…...

Ajax fetch navigator.sendBeacon 三个的区别

Ajax、fetch 和 navigator.sendBeacon 是用于发送网络请求的不同方法。 Ajax: Ajax 是一种传统的用于发送异步请求的技术。它使用 XMLHttpRequest 对象来发送数据和接收响应。通过创建 XMLHttpRequest 对象&#xff0c;你可以通过调用其 open() 方法指定请求的类型和 URL&#…...

map-reduce执行过程

Map阶段 Map 阶段是 MapReduce 框架中的一个重要阶段&#xff0c;它负责将输入数据转换为中间数据。Map 阶段由一个或多个 Map 任务组成&#xff0c;每个 Map 任务负责处理输入数据的一个子集。 执行步骤 Map 阶段的过程可以分为以下几个大步骤&#xff1a; 输入数据分配&a…...

技术人员怎样提升对业务的理解

技术服务于业务。 一个技术人员想要走得更远&#xff0c;不能仅局限于技术&#xff0c;需要对自己所从事的业务领域有不断深入和全面的理解。 所谓业务领域&#xff0c;就是大家平常自我介绍&#xff0c;不会仅简单说我是搞C的&#xff0c;我是搞JAVA的&#xff0c;而是游戏后台…...

【分布式】分布式事务:2PC

分布式事务的问题可以分为两部分&#xff1a; 并发控制 concurrency control原子提交 atomic commit 分布式事务问题的产生场景&#xff1a;一份数据被分片存在多台服务器上&#xff0c;那么每次事务处理都涉及到了多台机器。 可序列化&#xff08;并发控制&#xff09;&…...

回归与聚类算法系列④:岭回归

目录 1. 背景 2. 数学模型 3. 特点 4. 应用领域 5. 岭回归与其他正则化方法的比较 6、API 7、代码 8、总结 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数…...

idea配置git(gitee)并提交(commit)推送(push)

Intellij Idea VCS | 版本控制 - 知乎 IDEA项目上传到gitee仓库_idea上传代码到gitee_robin19712的博客-CSDN博客 git程序下载国内镜像地址&#xff1a; https://registry.npmmirror.com/binary.html?pathgit-for-windows/v2.42.0.windows.2/ 解压后放到固定路径&#xff1a…...

(19)Task异步:任务创建,返回值,异常捕捉,任务取消,临时变量

一、Task任务的创建 1、用四种方式创建&#xff0c;界面button,info各一。 程序代码 private void BtnStart_Click(object sender, EventArgs e){Task t new Task(() >{DisplayMsg($"[{Environment.CurrentManagedThreadId}]new Task.---1");});t.Start()…...

设备树的理解与运用

设备树&#xff1a; 本质是一个文件&#xff0c;包含很多节点&#xff0c;每个节点里边是对设备属性的描述&#xff08;包括GPIO&#xff0c;时钟&#xff0c;中断等等&#xff09;,其中节点&#xff08;node&#xff09;和属性&#xff08;property&#xff09;就是设备树最重…...

【AIGC】提示词 Prompt 分享

提示词工程是什么&#xff1f; Prompt engineering&#xff08;提示词工程&#xff09;是指在使用语言模型进行生成性任务时&#xff0c;设计和调整输入提示&#xff08;prompts&#xff09;以改善模型生成结果的过程。它是一种优化技术&#xff0c;旨在引导模型产生更加准确、…...

【Axure视频教程】取整函数

今天教大家在Axure里如何使用三种不同的取整函数&#xff0c;包括向上取整、向下取整和四舍五入取整。具体效果可以参考下方视频。该教程从0开始制作&#xff0c;手把手教学&#xff0c;无论是新手小白还是有一定基础的同学&#xff0c;都可以学习的哦。 【视频教程——试看版…...

MySQL清空表

当我们需要清空一个表中的所有行时&#xff0c;除了使用 DELETE * FROM table 还可以使用 TRUNCATE TABLE 语句。 如果想要清空一个表&#xff0c; TRUNCATE TABLE 语句比 DELETE语句更加有效。 TRUNCATE TABLE 语法 TRUNCATE TABLE 的语法很简单&#xff0c;如下&#xff1a…...

使用IDEA创建Vue3通过Vite实现工程化

1、创建Vite项目的分步说明 IntelliJ IDEA与Vite构建工具集成&#xff0c;改善了前端开发体验。Vite 由一个开发服务器和一个构建命令组成。构建服务器通过本机 ES 模块提供源文件。生成命令将代码与汇总捆绑在一起&#xff0c;汇总预配置为输出高度优化的静态资产以供生产。In…...

GitLab使用的最简便方式

GitLab介绍 GitLab是一个基于Git版本控制系统的开源平台&#xff0c;用于代码托管&#xff0c;持续集成&#xff0c;以及协作开发。它提供了一套完整的工具&#xff0c;以帮助开发团队协同工作、管理和部署代码。 往往在企业内部使用gitlab管理代码&#xff0c;记录一下将本地代…...

MySQL数据库20G数据迁移至其他服务器的MySQL库或者云MySQL库

背景&#xff1a;20G的MySQL数据迁移至火山云MySQL库&#xff0c;使用navicat的数据传输工具迁移速度耗费时间过长。 方案一&#xff1a;使用火山云提供的MySQL数据迁移服务&#xff08;其他大厂应该提供的也有&#xff09; 方案二&#xff1a;使用数据迁移工具kettle&#x…...

build.gradle配置文件详解

Andorid Studio高版本和低版本的build.gradle配置逻辑有些差异 安卓项目中相关编译文件的介绍 gradle-wrapper.properites&#xff1a;配置Gradle Wrapper gradle.properties&#xff1a;配置Gradle的编译参数。具体配置见Gradle官方文档:com.android.build.gradle | Andro…...

2024拼多多校招面试真题汇总及其解答(二)

6. 【算法题】归并排序 归并排序(Merge Sort)是一种分治算法,它将待排序的序列递归地分成两个子序列,然后将两个有序的子序列合并成一个有序的序列。 归并排序的算法流程如下: 递归地将待排序的序列分成两个子序列,直到每个子序列只有一个元素。将两个有序的子序列合并…...

自动化运维工具Ansible教程(一)【入门篇】

文章目录 前言Ansible 入门到精通入门篇进阶篇精通篇入门篇1. Ansible 简介2. 安装 Ansible1. 通过包管理器安装&#xff1a;2. 通过源码安装&#xff1a; 3. Ansible 的基本概念和核心组件4. 编写和运行第一个 Ansible Playbook5. 主机清单和组织结构主机清单组织结构 6. Ansi…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

用递归算法解锁「子集」问题 —— LeetCode 78题解析

文章目录 一、题目介绍二、递归思路详解&#xff1a;从决策树开始理解三、解法一&#xff1a;二叉决策树 DFS四、解法二&#xff1a;组合式回溯写法&#xff08;推荐&#xff09;五、解法对比 递归算法是编程中一种非常强大且常见的思想&#xff0c;它能够优雅地解决很多复杂的…...