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

Android无障碍服务监听实现自动点击按钮

原理:

通过监听窗口改变事件,监听目标应用,通过视图ID(或文本、或描述、或其他如坐标之类的)找到目标视图,使用无障碍动作点击方法点击它

无障碍服务实现:

1、写一个自己的无障碍服务继承AccessibilityService

public class AppWindowChangeService extends AccessibilityService {private static final String TAG = "MyAppWindowChangeService";@Overridepublic void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {if (accessibilityEvent == null || accessibilityEvent.getPackageName() == null) return;CharSequence packageName = accessibilityEvent.getPackageName();CharSequence className = accessibilityEvent.getClassName();//监听当前窗口变化,获取Packageif(accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){Log.i(TAG, "onAccessibilityEvent: packageName = "+packageName+", className = "+className);} }@Overridepublic void onInterrupt() {Log.e(TAG, "onInterrupt");}}

2、AndroidManifest.xml声明这个服务:

<serviceandroid:name=".AppWindowChangeService"android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|fontScale|locale|uiMode"android:enabled="true"android:exported="false"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/detection_service_config"/></service>

3、在xml新建一个配置资源,做这个无障碍服务的相关配置:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-servicexmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeWindowStateChanged|typeViewClicked"android:accessibilityFeedbackType="feedbackGeneric"android:canRetrieveWindowContent="true"android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRetrieveInteractiveWindows" />

这里监听类型我还多加了一个typeViewClicked,后面可以用来找你点击的view的相关信息。

启用功能:

自行找到系统设置的无障碍服务功能界面,或者使用代码做跳转到无障碍服务界面:

Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);intent.setPackage("com.android.settings");startActivity(intent);

开启自己app的无障碍服务开关,无障碍服务就会启动起来了。

实践:

举个栗子,监听美团外卖启动页的广告的跳过按钮:

import android.accessibilityservice.AccessibilityService;
import android.os.Handler;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Toast;public class AppWindowChangeService extends AccessibilityService {private static final String TAG = "MyAppWindowChangeService";private static final String TARGET_PACKAGE_NAME = "com.sankuai.meituan.takeoutnew";private static final String TARGET_VIEW_ID = "com.sankuai.meituan.takeoutnew:id/ll_skip";private final Runnable runnable = this::findAndClickTargetView;private final Handler handler = new Handler();@Overridepublic void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {if (accessibilityEvent == null || accessibilityEvent.getPackageName() == null) return;CharSequence packageName = accessibilityEvent.getPackageName();CharSequence className = accessibilityEvent.getClassName();//监听当前窗口变化,获取Packageif(accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED){if (TARGET_PACKAGE_NAME.equals(packageName)) {Log.i(TAG, "Target package opened: " + packageName);// 查找并点击目标视图handler.removeCallbacks(runnable);handler.postDelayed(runnable, 200);}} else if (accessibilityEvent.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {Log.i(TAG, "onAccessibilityEvent: packageName = "+packageName+", className = "+className);Log.e(TAG, "onAccessibilityEvent: 点击view:" + className);AccessibilityNodeInfo source = accessibilityEvent.getSource();if (source != null) {String viewId = source.getViewIdResourceName();CharSequence text = source.getText();CharSequence contentDescription = source.getContentDescription();Log.e(TAG, "View ID: " + viewId);Log.e(TAG, "Text: " + text);Log.e(TAG, "Content Description: " + contentDescription);source.recycle(); // 释放资源}}}private void findAndClickTargetView() {AccessibilityNodeInfo rootNode = getRootInActiveWindow();Log.i(TAG, "findAndClickTargetView: rootNode == " + rootNode);if (rootNode != null) {AccessibilityNodeInfo targetNode = findNodeById(rootNode, TARGET_VIEW_ID);Log.i(TAG, "findNodeById: targetNode = "+targetNode);if (targetNode != null) {Log.i(TAG, "targetNode != null, start click");performClick(targetNode);targetNode.recycle();}rootNode.recycle();}}private AccessibilityNodeInfo findNodeById(AccessibilityNodeInfo rootNode, String viewId) {if (rootNode.getViewIdResourceName() != null && rootNode.getViewIdResourceName().equals(viewId)) {return AccessibilityNodeInfo.obtain(rootNode);}for (int i = 0; i < rootNode.getChildCount(); i++) {AccessibilityNodeInfo childNode = rootNode.getChild(i);if (childNode != null) {AccessibilityNodeInfo result = findNodeById(childNode, viewId);if (result != null) {return result;}childNode.recycle();}}return null;}private void performClick(AccessibilityNodeInfo node) {if (node != null && node.isClickable()) {node.performAction(AccessibilityNodeInfo.ACTION_CLICK);Log.i(TAG, "Clicked on node: " + node);Toast.makeText(this, "自动点击", Toast.LENGTH_SHORT).show();} else {Log.i(TAG, "Node is not clickable: " + node);}}@Overridepublic void onInterrupt() {Log.e(TAG, "onInterrupt");}}

目标包名和目标viewID是我通过点击的时候输出打印看到的,给他倒推回去记录到代码当中。

查找view的动作需要做延时获取,实测马上去获取是获取不到的。

实际实现中,可以记录多个包名,以及对应的需要点击的视图,做李跳跳的效果。

Android高版本注意:如果打开其他App之后日志不打印,回到自己应用之后才会一次性把之前的动作日志打印出来的情况需要将应用的省电策略改为无限制!!!这个问题网上都没有提到,之前一直不生效困扰了我好久。

相关文章:

Android无障碍服务监听实现自动点击按钮

原理&#xff1a; 通过监听窗口改变事件&#xff0c;监听目标应用&#xff0c;通过视图ID&#xff08;或文本、或描述、或其他如坐标之类的&#xff09;找到目标视图&#xff0c;使用无障碍动作点击方法点击它 无障碍服务实现&#xff1a; 1、写一个自己的无障碍服务继承Acc…...

Deveco Studio首次编译项目初始化失败

编译项目失败 Ohpm install失败的时候重新使用管理者打开程序 build init 初始化失败遇到了以下报错信息 Installing pnpm8.13.1... npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to https://registry.npm.taobao.org/pnpm failed, r…...

Redis缓存应用场景【Redis场景上篇】

文章目录 1.缓存基础2.缓存异步场景1.缓存穿透2.缓存击穿3.缓存雪崩总结 3.缓存一致性 1.缓存基础 Redis由于性能高效&#xff0c;通常可以做数据库存储的缓存。一般而言&#xff0c;缓存分为服务端缓存和客户端缓存。缓存有以下三种模式&#xff1a; Cache Aside&#xff08…...

线程与进程基础

文章目录 前言一、 线程与进程1.1 什么是线程与进程&#xff1f;1.2 并发与并行1.3 同步调用与异步调用1.4 为什么要使用多线程&#xff1f; 前言 在学习juc前&#xff0c;需要先对进程和线程之间整体有一个认知。我们之前或多或少接触过&#xff0c;一些特别高大上的概念&…...

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题 这篇文章是接我cocos专栏的上一篇文章继续写的&#xff0c;我上一篇文章写的是 cocos 开发触摸屏项目&#xff0c;需要嵌入一个网页用来展示&#xff0c;最后通过 electron 打包成 exe 程序&#xff0c;而且网页里面…...

OpenCV的简单练习

1、读取一张彩色图像并将其转换为灰度图。 import matplotlib.pyplot as pltimg plt.imread("./flower.png") # 灰度化 img_gray img[:,:,0]*0.299 img[:,:,1]*0.587 img[:,:,2]*0.114plt.subplot(121) plt.imshow(img) plt.subplot(122) plt.imshow(img_gray,c…...

JAVA:建造者模式(Builder Pattern)的技术指南

1、简述 建造者模式(Builder Pattern)是一种创建型设计模式,它通过将对象的构造过程与表示分离,使得相同的构造过程可以创建不同的表示。建造者模式尤其适用于创建复杂对象的场景。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 本文将详细介绍建…...

12.11函数 结构体 多文件编译

1.脑图 定义一个数组&#xff0c;用来存放从终端输入的5个学生的信息【学生的信息包含学生的姓名、年纪、性别、成绩】 1>封装函数 录入5个学生信息 2>封装函数 显示学生信息 3>封装函数 删除第几个学生信息&#xff0c;删除后调用显示学生信息函数 显示 4> 封…...

Debezium系列之:使用Debezium采集oceanbase数据库

Debezium系列之:使用Debezium采集oceanbase数据库 一、oceanbase数据库二、安装OceanBase三、安装oblogproxy四、基于Docker的简单采集案例五、生产实际应用案例Debezium 是一个开源的分布式平台,用于监控数据库变化和捕捉数据变动事件,并以事件流的形式导出到各种消费者。D…...

VMware虚拟机 Ubuntu没有共享文件夹的问题

在虚拟机的Ubuntu系统中&#xff0c;共享文件目录存放在 mnt/hgfs 下面&#xff0c;但是我安装完系统并添加共享文件后发现&#xff0c;在mnt下连/hgfs目录都没有。 注意&#xff1a;使用共享文件目录需要已安装VMtools工具。 添加共享文件目录 一&#xff1a;在超级用户下 可…...

spring使用rabbitmq当rabbitmq集群节点挂掉 spring rabbitmq怎么保证高可用

##spring rabbitmq代码示例 Controller代码 import com.alibaba.fastjson.JSONObject; import com.newland.mi.config.RabbitDMMQConfig; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageProperties; import org.springframewo…...

简单vue3前端打包部署到服务器,动态配置http请求头后端ip方法教程

vue3若依框架前端打包部署到服务器&#xff0c;需要部署到多个服务器上&#xff0c;每次打包会很麻烦&#xff0c;今天教大家一个动态配置请求头api的方法&#xff0c;部署后能动态获取(修改)对应服务器的请求ip 介绍两种方法&#xff0c;如有需要可以直接尝试步骤一&#xff…...

C语言关于溢出和不溢出的判断

通过实验来判断整数溢出&#xff0c;浮点数溢出的情况 #include <stdio.h> #include <limits.h> #include <float.h> int main(void) { // 整数溢出 int int_max INT_MAX; // INT_MAX 是 int 类型的最大值 int int_min INT_MIN; // INT_MIN …...

活动预告 |【Part1】Microsoft Azure 在线技术公开课:使用 Microsoft Fabric 实现数据湖仓

课程介绍 通过 Microsoft Learn 免费参加 Microsoft Azure 在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft Cloud 技术的了解。参加“使用 Microsoft Fabric 实现数据湖仓”活动&#xff0c;了解如何在 AI 的帮助下统一数据分析。了解如何简…...

Unreal的Audio::IAudioCaptureStream在Android中录制数据异常

修改OpenAudioCaptureStream启动参数为PCM_32&#xff0c;在PC上正常&#xff0c;在Android系统&#xff0c;读取的的数据计算出的音量值在0.4-0.6之间跳动&#xff0c;数据异常。 Audio::FAudioCaptureDeviceParams Params;/** 设置声卡不支持的采样数和通道数开始音频流不会成…...

6、AI测试辅助-测试报告编写(生成Bug分析柱状图)

AI测试辅助-测试报告编写&#xff08;生成Bug分析柱状图&#xff09; 一、测试报告1. 创建测试报告2. 报告补充优化2.1 Bug图表分析 3. 风险评估 总结 一、测试报告 测试报告内容应该包含&#xff1a; 1、测试结论 2、测试执行情况 3、测试bug结果分析 4、风险评估 5、改进措施…...

【第五节】docker应用系列篇: 使用Docker容器实现ElasticSearch+Kibana部署

系列文章目录 【第五节】docker应用系列篇&#xff1a; 使用Docker容器实现ElasticSearchKibana部署 系列文章目录前言一、 docker运行es二、 docker运行kibina 前言 配一次&#xff0c;真觉得方面 一、 docker运行es docker pull elasticsearch:7.17.0# mkdir -p /opt/es/co…...

openwrt 通过DHCP/DNS(Dnsmasq)屏蔽指定域名(hosts)

1、准备好hosts文件 2、登录openwrt后台&#xff1a;系统-TTYD终端-root登录&#xff1a; cd /etc ls vi hosts_by_me vi hosts_by_me 创建/打开 hosts_by_me文件&#xff0c;把准备好的hosts文件的内容复制粘贴进去&#xff0c;然后保存退出:wq cat hosts_by_me查看确认保…...

opencv——识别图片颜色并绘制轮廓

图像边缘检测 本实验要用到Canny算法&#xff0c;Canny边缘检测方法常被誉为边缘检测的最优方法。 首先&#xff0c;Canny算法的输入端应为图像的二值化结果&#xff0c;接收到二值化图像后&#xff0c;需要按照如下步骤进行&#xff1a; 高斯滤波。计算图像的梯度和方向。非极…...

docker简单私有仓库的创建

1&#xff1a;下载Registry镜像 导入镜像到本地中 [rootlocalhost ~]# docker load -i registry.tag.gz 进行检查 2&#xff1a;开启Registry registry开启的端口号为5000 [rootlocalhost ~]# docker run -d -p 5000:5000 --restartalways registry [rootlocalhost ~]# dock…...

简单掌握C++中的函数模板

1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数&#xff0c;以支持多种不同的形参&#xff0c;避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。 函数模板的声明形式为&#xff1a; template<typenam…...

Win11 右键菜单缺少“新建文本文档“win11 某些软件中文乱码

Win11 右键菜单缺少“新建文本文档“Win11 右键菜单缺少"新建文本文档"是‌常见系统配置问题‌&#xff0c;主要通过注册表修复或记事本应用重装即可解决。‌‌核心解决方法&#xff08;win11 亲测可行&#xff09;‌注册表修复&#xff08;最常用&#xff09;‌按Wi…...

鸿蒙备考题库页面构建:错题本、小组榜单与备考提示模块详解

鸿蒙备考题库页面构建&#xff1a;错题本、小组榜单与备考提示模块详解 前言 在 HarmonyOS 6.0 应用开发中&#xff0c;教育类应用的错题管理、学习排行榜和系统提示是提升用户粘性的关键功能模块。本文将以“备考题库”应用中的“错题本”高频错题列表、“小组榜单”学习排名和…...

巴别鸟vs坚果云:企业云盘同步机制踩坑与实战配置

干企业网盘这行&#xff0c;最怕听到用户说"同步慢"。我们2019年上线第一版云盘时&#xff0c;同步1GB的CAD图纸包要40分钟&#xff0c;用户骂完就跑。踩了三年坑才知道&#xff0c;"能同步"和"同步好用"根本是两回事。 本文从踩坑实录加配置实战…...

AI设计泳装,效率能翻几倍?

炎夏未至&#xff0c;泳装行业的备战硝烟却已弥漫。设计师灵感枯竭、打版反复修改、样衣成本高企……每一个痛点都像一座大山&#xff0c;压得品牌方喘不过气。面对Z世代瞬息万变的审美&#xff0c;“快”与“准”成了决胜关键。北京先智先行科技有限公司&#xff0c;正携旗下“…...

Unity游戏资源提取实战指南:AssetStudio高阶用法与避坑手册

1. 这不是“又一个AssetStudio教程”&#xff0c;而是我拆了27款Unity手游后总结的资源提取生存手册AssetStudio、Unity游戏资源提取、Unity AssetBundle、Unity3D反编译——这几个词&#xff0c;过去三年里我每天至少在技术群、论坛、工单系统里看到50次。但绝大多数人点开Ass…...

【FlinkSQL笔记】(三)Flink SQL 核心重难点(窗口函数、水印)

一、窗口函数 流式数据无限无边界&#xff0c;例如想要统计每5分钟、每1小时的数据&#xff0c;必须用窗口函数&#xff0c;这是Flink SQL和普通SQL最大的区别之一。 1、 滚动窗口 TUMBLE&#xff08;最常用&#xff09; 特点&#xff1a;无重叠、无间隔、固定时长&#xff0c;…...

【教程】全流程基于最新导则下的生态环境影响评价技术方法及图件制作与案例实践技术应用

专题一&#xff1a;生态环境影响评价框架及流程 以某既包含陆域、又包含水域的项目为主要案例&#xff0c;兼顾其它类型项目&#xff0c;主要内容包括&#xff1a; 1、生态环境影响评价基本思路与要求&#xff1a;工作程序、报告编制技术要求与规范 2、资料收集与初步踏勘&a…...

Python数据流式处理:Streaming深度解析与实战

Python数据流式处理&#xff1a;Streaming深度解析与实战 引言 在Python开发中&#xff0c;数据流式处理是处理大数据和实时数据的关键技术。作为一名从Rust转向Python的后端开发者&#xff0c;我深刻体会到流式处理在处理海量数据时的优势。Python提供了多种流式处理工具&…...

计算机网络知识点全面总结(有这一篇就够了!!!)

计算机网络知识点全面总结&#xff08;有这一篇就够了&#xff01;&#xff01;&#xff01;&#xff09; 一、计算机网络概述 1.1 计算机网络的分类 按照网络的作用范围&#xff1a;广域网&#xff08;WAN&#xff09;、城域网&#xff08;MAN&#xff09;、局域网&#xff…...