Android 静默安装二(无障碍服务版)

近期开发上线一个常驻app,项目已上线,今天随笔记录一下静默安装相关内容。我分三篇静默安装(root版)、静默安装(无障碍版)、监听系统更新、卸载、安装。
先说说我的项目需求:要求app一直运行,通过指令进行自动安装并在安装成功后自动开启。行业人事都了解,非root权限不可能无声无息的完成此要求。我分两步完成了此功能开发。今天记录一下无障碍权限下实现自动安装app。
本文使用AccessibilityService执行系统安装程序自动安装指定文件。

一、自定义AccessibilityService并监听系统弹窗节点


/*** 自动安装服务*/
class AutoInstallService : AccessibilityService() {// 检查节点private fun checkNodes(node: AccessibilityNodeInfo):Boolean{if (node==null) {return false}if (node.className.isEmpty()) {return false}try {// 检查当前窗体if (node.className.equals("android.widget.Button")) {if (node.text.toString().isEmpty()) {return false}// 模拟点击if (node.text.equals("安装")||node.text.equals("完成")||node.text.equals("打开")||node.text.equals("确定")) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK)return true}// 检查滑动节点} else if (node.className.equals("android.widget.ScrollView")){node.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)}// 检查下级窗体for (i in 0..node.childCount) {var child = node.getChild(i)if (checkNodes(child)) {return true}}}catch (e:Exception){e.printStackTrace()}return false}private var nodes:MutableMap<Int,Boolean> = LinkedHashMap()// 分析系统弹窗节点override fun onAccessibilityEvent(p0: AccessibilityEvent?) {// 监听系统窗体p0?.let {it.source?.let {obj->{var eventType = it.eventTypeif (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {// 监听窗体节点if (nodes.get(it.windowId) == null) {if (checkNodes(obj))nodes.put(it.windowId,true)}}}}}}// 销毁override fun onDestroy() {super.onDestroy()jumpToAccessServiceSetUi(this)}// 连接成功后退出设置页面override fun onServiceConnected() {super.onServiceConnected()// 连接成功,执行返回按钮performGlobalAction(GLOBAL_ACTION_BACK)Thread.sleep(500L)performGlobalAction(GLOBAL_ACTION_BACK)}override fun onInterrupt() {}// 跳转辅助服务fun jumpToAccessServiceSetUi(context:Context){context?.let {try {it.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))}catch (e:Exception){var intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)intent.flags = Intent.FLAG_ACTIVITY_NEW_TASKit.startActivity(intent)e.printStackTrace()}}}/*** 检查辅助服务是否开启* @appcaliionId 应用id* @ct     设备id*/fun checkAccessServiceState(appcaliionId:String,ct:Context):Boolean{try {var state = Settings.Secure.getInt(ct.contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 0)if (state != 1) {return false} else{var serviceName = Settings.Secure.getString(ct.contentResolver,Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)if (serviceName.isEmpty()) {return serviceName.contains(appcaliionId)}return false}} catch (e:Exception){e.printStackTrace()}return false}}

这是我自定的AccessibilityService,内部包含了跳转到开启AccessibilityService设置页面,分析系统弹窗节点,添加安装节点,自动执行。开启AccessibilityService服务,销毁后重新开启AccessibilityService。

2、AccessibilityService注册

在清单文件中注册自定义的AutoInstallService

 <service android:name="com.zhujing.nadedemospace.AutoInstallService"android:label="自动安装服务"android:exported="true"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility_config" /></service>

accessibility_config自定义配置

<accessibility-servicexmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeAllMask"android:accessibilityFlags="flagDefault"android:accessibilityFeedbackType="feedbackGeneric"android:canRetrieveWindowContent="true"/>

三、使用

// 开启无障碍findViewById<View>(R.id.open_accessbt).setOnClickListener {if (!AutoInstallService().checkAccessServiceState("com.zhujing.nadedemospace",this)) {AutoInstallService().jumpToAccessServiceSetUi(this)}}// 安装应用findViewById<View>(R.id.install_apk).setOnClickListener {//var intent = Intent(Intent.ACTION_GET_CONTENT)intent.type = "*/*"intent.addCategory(Intent.CATEGORY_OPENABLE)startActivityForResult(intent,100)}// 调用系统安装方法
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 100 && resultCode == RESULT_OK && data?.data != null){var uri = data?.datavar intent = Intent(Intent.ACTION_VIEW)intent.flags = Intent.FLAG_ACTIVITY_NEW_TASKintent.setDataAndType(uri,"application/vnd.android.package-archive")startActivity(intent)}}

四、总结

我使用的是AccessibilityService无障碍服务实现自动安装的,严格意义上这并不算静默安装。andorid系统被限制的角度来说,这也是一种曲线救国的实现方式。能够满足,无需用户手动操作实现应用安装。欢迎各位指导……

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

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

相关文章

数字科技优化金融供给,内外协同激活新质生产力

来源 | 镭射财经&#xff08;leishecaijing&#xff09; 新一轮产业变革悄然发生&#xff0c;决定产业高度和竞争格局的底层生产力&#xff0c;也正在经历一场从量变到质变的跃迁。新质生产力则是这场跃迁后的最新呈现。 站在新质生产力爆发的时代拐点&#xff0c;金融业达成…

【鸿蒙HarmonyOS开发笔记】组件编程技巧之样式复用

样式复用 概述 当多个组件具有相同的样式时&#xff0c;若每个组件都单独设置&#xff0c;将会有大量的重复代码。为避免重复代码&#xff0c;开发者可使用Styles或者Extend装饰器将多条样式设置提炼成一个方法&#xff0c;然后直接在各组件声明的位置进行调用&#xff0c;这…

中国贸易金融跨行交易区块链平台CTFU、区块链福费廷交易平台BCFT、中国人民银行贸易金融区块链平台CTFP、银行函证区块链服务平台BPBC

中国人民银行贸易金融区块链平台CTFP介绍 贸易金融的发展概况及存在的问题 1.1 贸易金融的概况 贸易金融是指商业银行在贸易双方债权债务关系的基础上&#xff0c;为国内或跨国的商品和服务贸易提供的贯穿贸易活动整个价值链、全程全面性的综合金融服务。伴随全球化的进程&a…

Docker安装配置

1. 安装docker-ce sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum -y install docker-ce sudo systemctl enable docker 2. 设置代理 参照&#xff1a;https://docs.docker.com/config/daemon/systemd/#httpht…

基于yolov5的单目测距实现与总结+相机模型+标定

写这篇文章的目的是为了总结我之前看的标定&#xff0c;相机模型以及单目测距的内容&#xff0c;如果有错误&#xff0c;还请不吝赐教。 参考链接&#xff1a; 相机模型、相机标定及基于yolov5的单目测距实现 深度学习目标检测目标追踪单目测距 单目测距代码部署&#xff08;目…

深度学习入门:pytorch基础学习、各模块解析、调优技巧和问题结局

整理了一下之前写的深度学习基础知识文章&#xff0c;方便浏览&#xff01; 1. pytorch基础学习系列文章&#xff0c;里面代码和示例 《PyTorch深度学习实践》05 用PyTorch实现线性回归 《PyTorch深度学习实践》06 用PyTorch实现Logistic回归 《PyTorch深度学习实践》07加载数…

【Flask开发实战】防火墙配置文件解析(二)之shell读取内容

一、前言 上一篇文章中&#xff0c;介绍了防火墙配置文件包含的基本元素和格式样式&#xff0c;并模拟了几组有代表性的规则内容&#xff0c;作为基础测试数据。在拿到基础测试数据后&#xff0c;关于我们最终想解析成的数据是什么样式的&#xff0c;其实不难看出&#xff0c;…

Dynamo设置明细表字段格式——保留小数位数

Hello大家好&#xff01;我是九哥~ 今天简单分享一个API的用法&#xff0c;就是设置明细表的中字段的字段格式。 本次呢&#xff0c;主要介绍下如何通过Dynamo设置长度、面积等几种字段的格式&#xff0c;设置小数位数的显示&#xff0c;如下图&#xff1a; 当然了&#xf…

基于ssm的网络游戏公司官方平台设计与实现论文

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对网络游戏信息管理混乱&#xff0c;出错率高&#xff0c;信息安全性差…

Spark面试整理-解释RDD的宽依赖和窄依赖以及它们对Spark任务调度的影响

在Apache Spark中,RDD(弹性分布式数据集)的依赖关系分为两种类型:窄依赖(Narrow Dependency)和宽依赖(Wide Dependency)。这些依赖关系定义了RDD之间的关联方式,对Spark的任务调度和性能有重要影响。 窄依赖(Narrow Dependency) 定义:在窄依赖中,每个父RDD的分区最…

java零钱兑换(力扣Leetcode322)

零钱兑换 力扣原题链接 问题描述 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff0c;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少 的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1。 你可…

函数递归的总结回顾

函数递归的本质就是其名字——递与归。先递出去&#xff0c; 再收回来。 而递归的思想就是为了让一个复杂的问题变成一个简单的问题 按照我目前的理解&#xff0c;函数递归有两点很重要。一个是它的限定条件&#xff0c;另一个就是函数体内“自调”&#xff08;就是自我调用语句…

1-Flume中agent的source

Flume&#xff08;1.11.0版本&#xff09; 简介 概述 Flume本身是由Cloudera公司开发的后来贡献给了Apache的一套针对日志数据进行收集(collecting)、汇聚(aggregating)和传输(moving)的机制 Flume本身提供了简单且灵活的结构来完成日志数据的传输 Flume有两大版本&#x…

jQuery 选择器--获取元素

文章目录 1 jQuery 基础选择器2 层级选择器3 隐式迭代(重要)4 jQuery 筛选选择器5 jQuery 筛选方法(重点)案例--下拉菜单 6 jQuery 排他思想*案例--左右Tab栏切换 7 jQuery 链式编程 1 jQuery 基础选择器 2 层级选择器 3 隐式迭代(重要) 示例&#xff1a; 4 jQuery 筛选选择器…

oracle表备份及还原

工作中&#xff0c;经常使用Navicat访问及操作Oracle数据库&#xff0c;备份表非常方便Ctrlc、Ctrlv&#xff1b;最近备份表&#xff0c;发现这种操作有问题&#xff1b;数据表有2条检查&#xff0c;使用Ctrlc、Ctrlv操作&#xff0c;发现新备份的表出现4条检查&#xff0c;再对…

Python实战:命令行工具开发

本文将深入探讨如何使用Python开发一个命令行工具。我们将从项目规划、功能实现、用户交互、错误处理和测试等方面进行详细讲解。我们将展示如何使用Python标准库中的argparse模块来处理命令行参数&#xff0c;以及如何构建一个功能完整、易于使用的命令行工具。 一、引言 命…

冷库制冷量计算与机组、换热器、膨胀阀选型配管

1、冷库冷负荷估算: 能计算出冷库耗冷量需要提供的最基本条件: 货物种类; 库房尺寸(长宽高); 储藏量,吨; 进货量,吨/天; 冷却时间,小时; 进货温度,℃; 出货温度,℃。 2、冷库贮存量计算: 冷库吨位计算公式:G=∑Vlρsη/1000 式中: G—冷库吨位(t); Vl—冷…

流畅的 Python 第二版(GPT 重译)(十二)

第五部分&#xff1a;元编程 第二十二章&#xff1a;动态属性和属性 属性的关键重要性在于&#xff0c;它们的存在使得将公共数据属性作为类的公共接口的一部分完全安全且确实可取。 Martelli、Ravenscroft 和 Holden&#xff0c;“为什么属性很重要” 在 Python 中&#xff0…

前端如何一次处理十万条数据的渲染

前端如何一次处理十万条数据的渲染 一、下载第三方插件二、在入口文件引入三、示例 一、下载第三方插件 npm install --save el-table-infinite-scroll二、在入口文件引入 import ElTableInfiniteScroll from "el-table-infinite-scroll"; Vue.use(ElTableInfinite…

docker 配置国内阿里镜像源

在/etc/docker/目录下新建daemon.json文件 在文件中写入 {"registry-mirrors": ["https://jmphwhtw.mirror.aliyuncs.com"] } 以管理员身份运行命令 systemctl daemon-reload systemctl restart docker