Android使用辅助服务AccessibilityService实现自动化任务
Android 辅助服务(AccessibilityService)旨在帮助具有视觉、身体或年龄相关限制的用户更轻松地使用 Android 设备和应用。通过辅助服务,可以将一些人工操作自动化,从而解放用户的双手。
因此我们可以使用它来实现一些自动化任务,比如抢红包,测试,自动玩游戏(外挂?)。author: https://blog.csdn.net/keeng2008
- 编写辅助服务MyAccessibilityService,继承AccessibilityService
class MyAccessibilityService : AccessibilityService() {override fun onServiceConnected() {super.onServiceConnected()Log.i(TAG, "onServiceConnected")}override fun onAccessibilityEvent(event: AccessibilityEvent) {Log.i(TAG, "onAccessibilityEvent: $event")val packageName = event.packageName/* 处理界面变动事件 */}override fun onInterrupt() {Log.i(TAG, "onInterrupt")}
}
当辅助服务开启后,Service会开始运行,界面上的元素变动,窗口变动会回调onAccessibilityEvent。在其中可以实现模拟点击。
- 这个服务不能主动开启,需要用户在设置-无障碍中手动开启。
- 把MyAccessibilityService添加到Manifest
<serviceandroid:name=".accessbi.MyAccessibilityService"android:exported="true"android:label="控制辅助服务Demo"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/my_accessibility" /></service>
在res/xml中添加文件 my_accessibility.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackSpoken"android:accessibilityFlags="flagReportViewIds"android:canRetrieveWindowContent="true"android:canPerformGestures="true"android:notificationTimeout="100"/>
这样就已经注册好辅助服务,但是需要用户手动到“设置”中的“无障碍”,去启动无障碍功能。
- 引导用户直接跳转到无障碍中启动
- 3.1 判断当前是否已经启动
fun isAccessibilitySettingsOn(context: Context): Boolean {val accessibilityEnabled = Settings.Secure.getInt(context.contentResolver,Settings.Secure.ACCESSIBILITY_ENABLED)if (accessibilityEnabled != 1) return falseval value = Settings.Secure.getString(context.contentResolver,Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) ?: return falsereturn value.contains(context.packageName) &&value.contains(MyAccessibilityService::class.java.simpleName)}
- 3.2 跳转到无障碍设置界面
发现未开启服务后,引导用户跳转到设置界面,手动打开。
fun openAccessibilitySetting(context: Context) {val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)context.startActivity(intent)}
- 3.3 开启后能否保持状态
经测试,如果进程被主动杀死重启,那么开关就被关闭了。
其它情况下即使关机重启,更新APP,它的状态能保持-
- AccessibilityService常用方法
- 获取当前的APP: val packageName = event.packageName
- 获取当前的Activity:
fun getActivityName(context: Context, event: AccessibilityEvent): String {val componentName = ComponentName(event.packageName.toString(), event.className.toString())try {var activityName = context.packageManager.getActivityInfo(componentName, 0).toString()activityName =activityName.substring(activityName.indexOf(" "), activityName.indexOf("}"))return activityName} catch (e: Exception) {}return ""}
不是每个event都能获取到Activity的,比如一些Toast,Dialog的事件,拿不到Activity; 所以可以把最后的Activity保存起来,随时读取。
- 通过文本获取当前界面的View
fun findViewByText(svr: AccessibilityAble, text: String): AccessibilityNodeInfo? {val nodes = svr.getRootNode()?.findAccessibilityNodeInfosByText(text)if (nodes != null) {for (node in nodes) {if (node.text == text) {return node}}}return nodes?.firstOrNull()
}
AccessibilityAble: 主是要封装了对 getService().rootInActiveWindow 的引用, 这样可以从当前的全局根结点开始寻找。
- 通过viewId获取当前界面的View
格式示例 :“APP包名:id/operator_normal_iv”
fun findViewById(svr: AccessibilityAble, viewId: String): AccessibilityNodeInfo? {val nodes = svr.getRootNode()?.findAccessibilityNodeInfosByViewId(viewId)return nodes?.firstOrNull()
}
- 模拟View点击
val btn: AccessibilityNodeInfo? = AccessibilityUtils.findViewByText(svr, "下次再说")
if (btn != null && btn.isClickable && btn.isVisibleToUser) {btn.performAction(AccessibilityNodeInfo.ACTION_CLICK)
}
- 通过手势长按指定坐标
fun performLongPress(svr: AccessibilityAble, point: PointF, durationMill: Long) {// 创建手势描述val gestureBuilder = GestureDescription.Builder()// 移动到指定坐标val path = Path().apply {moveTo(point.x, point.y)}val duration: Long = durationMill // 持续时间 毫秒val strokeDescription = GestureDescription.StrokeDescription(path, 0, duration)// 添加手势到描述gestureBuilder.addStroke(strokeDescription)val gesture = gestureBuilder.build()// 执行手势val cb = object : AccessibilityService.GestureResultCallback() {override fun onCompleted(gestureDescription: GestureDescription?) {Log.i(TAG, "onCompleted, $gestureDescription")}override fun onCancelled(gestureDescription: GestureDescription?) {Log.i(TAG, "onCancelled, $gestureDescription")}}val res = svr.getService().dispatchGesture(gesture, cb, null)Log.i(TAG, "dispatchGesture, res: $res")
}
- 点击Node所在位置:主要是有些文本不可点击,直接模拟点击该位置
fun performClick(svr: AccessibilityAble, node: AccessibilityNodeInfo) {val rect = Rect()node.getBoundsInScreen(rect)val centerP = PointF(rect.exactCenterX(), rect.exactCenterY())Log.i(TAG, "Start Simple Click at $centerP")performLongPress(svr,centerP,100L)
}
author: https://blog.csdn.net/keeng2008 有了这神器,能实现些什么新奇玩法呢?抢红包,自动打卡,继续探索中。
相关文章:
Android使用辅助服务AccessibilityService实现自动化任务
Android 辅助服务(AccessibilityService)旨在帮助具有视觉、身体或年龄相关限制的用户更轻松地使用 Android 设备和应用。通过辅助服务,可以将一些人工操作自动化,从而解放用户的双手。 因此我们可以使用它来实现一些自动化任务&a…...
工业大数据分析算法实战-day15
文章目录 day15特定数据类型的算法工业分析中的数据预处理工况划分数据缺失时间数据不连续强噪声大惯性系统趋势项消除 day15 今天是第15天,昨日是针对最优化算法、规则推理算法、系统辨识算法进行了阐述,今日主要是针对其他算法中的特定数据类型的算法…...
C语言实现顺序表详解
文章目录 [TOC] 1.前言🙋🏼♂️2.顺序表🧣2.1 顺序表概念🧣2.2 顺序表特点🧣2.2 顺序表作用🧣 3.顺序表基操🧤3.1 结构体初始化🎉3.2 顺序表初始化🎉3.3 顺序表创建&am…...
【ES6复习笔记】对象方法扩展(17)
对象方法扩展 在 JavaScript 中,对象是属性和方法的集合。除了内置的方法,我们还可以通过扩展对象的原型来添加新的方法。本教程将介绍如何使用 Object.is、Object.assign 和 Object.setPrototypeOf 方法来扩展对象。 1. Object.is 判断两个值是否完全…...
【视觉惯性SLAM:相机成像模型】
相机成像模型介绍 相机成像模型是计算机视觉和图像处理中的核心内容,它描述了真实三维世界如何通过相机映射到二维图像平面。相机成像模型通常包括针孔相机的基本成像原理、数学模型,以及在实际应用中如何处理相机的各种畸变现象。 一、针孔相机成像原…...
学习笔记(C#基础书籍)-- C#基础篇
(12.24) C#介绍:《第一章》 特点:语法简洁,面向对象,支持绝大部分的web标准,强大的安全机制(垃圾回收器),兼容性好(遵循.NET的公共语言规范【CL…...
操作系统(26)数据一致性控制
前言 操作系统数据一致性控制是确保在计算机系统中,数据在不同的操作和处理过程中始终保持正确和完整的一种机制。 一、数据一致性的重要性 在当今数字化的时代,操作系统作为计算机系统的核心,负责管理和协调各种资源,以确保计算机…...
ubuntu24.04使用opencv4
ubuntu24.04LTS自带opencv4.5代码实例 //opencv_example.cpp #include <opencv2/opencv.hpp> #include <iostream>int main() {// 读取图像cv::Mat img cv::imread("image.jpg", cv::IMREAD_COLOR);if (img.empty()) {std::cerr << "无法读…...
【项目构建】Gradle入门
本文适用: 不知道什么是项目构建,可以了解下Ant,Maven,Gradle的区别。知道什么是项目构建,了解Ant,Maven,可以看到Gradle是怎么做的。知道什么是项目构建,了解Ant,Maven&…...
Electron -- Electron应用主要核心(二)
Electron 应用主要由以下几个核心组成部分构成: 主进程(Main Process): Electron 应用的入口点是主进程,通常是 main.js 文件。它负责管理应用的生命周期,包括创建窗口、处理系统事件和应用更新等。主进程可…...
【前端开发】HTML+CSS+JavaScript前端三剑客的基础知识体系了解
前言 🌟🌟本期讲解关于HTMLCSSJavaScript的基础知识,小编带领大家简单过一遍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 …...
git命令恢复/还原某个文件、删除远程仓库中的文件
有时刚创建的远程仓库,可能无意中把一些没用的文件上传到仓库,本文介绍一下怎么删除这些文件。 一、git命令恢复某个文件 第一步:拉取最新代码 git pull 第二步: 查看git 修改的文件状态 git status 第三步:查看…...
二十一、Ingress 进阶实践
架构参考 使用hostnetwork,推荐的方式,使用单独的物理服务器,不部署业务pod的主机。 一、Ingress Nginx Controller 安装 采用helm的安装方式,进行部署。 官网地址: https://kubernetes.github.io/ingress-nginx/deploy/ github地址: https://github.com/kubernetes/in…...
ES学习Promise对象(九)
这里写目录标题 一、概念二、示例基本使用使用 Promise 对象封装Ajaxthen() 方法catch() 方法 一、概念 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。Promise 是一个对象,Promise 提供统一…...
寻找适合小户型的开源知识库open source knowledge base之路
寻找一个开源的知识库,为了把以前花很多时间收集的信息或是项目/课程资料放到一个容易归类和管理的私有自主系统中,以便更容易查阅,花更少时间收集、对比版本及分享等一系列管理工作,同时确保在需要时可以相对快速找到有用的资料&…...
Linux高级--2.6 网络面试问题
tcp 与 udp的区别 1.tcp 是基于连接的 UDP是基于数据包 2.处理并发的方式不通 a.tcp用epoll进行监听的 b. udp是模拟tcp的连接过程,服务端开放一个IP端口,收到连接后,服务端用另一个IP和端口发包给客户端。 3.tcp根据协议MTU黏包及…...
在 CentOS 7 上安装 Node.js 20 并升级 GCC、make 和 glibc
在 CentOS 7 上安装 Node.js 20 并升级 GCC、make 和 glibc 📖 前言 在 CentOS 7 上使用 NVM 安装 Node.js 后,可能会遇到如下问题: node: /lib64/libm.so.6: version GLIBC_2.27’ not found (required by node) node: /lib64/libc.so.6:…...
音视频入门基础:MPEG2-TS专题(20)——ES流简介
《T-REC-H.222.0-202106-S!!PDF-E.pdf》第27页对ES进行了定义。ES流是PES packets(PES包)中编码的视频、编码的音频或其他编码的比特流。一个ES流(elementary stream)在具有且只有一个stream_id的PES packets序列中携带࿱…...
五子棋小游戏设计(Matlab)
基于Matlab的五子棋小游戏设计 (完整源码运行呈现的GUI界面) (完整的设计说明报告) 需要请随时联系博主,博主基本都在线,能秒回! 随着计算机技术的发展,将传统棋类游戏与编程技术…...
基于Pycharm与数据库的新闻管理系统(3)MongoDB
pip3 install pymongo 1.连接到MongoDB数据库 文件地址:db/mongo_db.py 从 pymongo 模块中导入 MongoClient 类;创建 MongoClient 的一个实例,该实例尝试使用提供的MongoDB连接字符串连接到MongoDB服务器。 from pymongo import MongoClie…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
