【Android】用无障碍服务整个脚本——我看刑

news2024/12/27 11:43:18

本文灵感来源:李跳跳真实好友 app

目录

  • 无障碍服务(AccessibilityService)
  • 模拟点击
      • 组件ID & 组件文本
      • 坐标
  • 后台保活
  • 效果图
  • 存在缺陷
      • 缺陷一
      • 缺陷二
      • 缺陷三
      • 缺陷四

无障碍服务(AccessibilityService)

无障碍服务(AccessibilityService),是Google推出为了帮助残障用户使用 Android 设备和应用而推出的比较特殊的service。通过无障碍服务,开发者可提供界面增强功能,来协助残障用户或可能暂时无法与设备进行全面互动的用户完成操作。

无障碍服务虽然不位于Android四大组件之中,但功能给产品带来的影响却不可小觑,例如曾经的自动抢红包功能,甚至因为太过火爆,而被某些手机厂商加入到系统功能之中,那时抢红包靠的就不是手速。其它类似使用无障碍服务开发的产品有微光盲人生活辅助平台讯飞心智无障碍助手软件等。

在App开发过程中,为了使一个service被视为无障碍服务,必须在清单的application标签中添加一个service标签、过滤器,为了与 Android 4.1 及更高版本兼容,还必须添加BIND_ACCESSIBILITY_SERVICE权限。

<service
     android:name=".MyAccessibilityService"
     android:enabled="true"
     android:exported="true"
     android:label="@string/app_name"
     android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
     <intent-filter>
         <action android:name="android.accessibilityservice.AccessibilityService" />
     </intent-filter>

     <meta-data
         android:name="android.accessibilityservice"
         android:resource="@xml/accessibility_config" />
 </service>

从 Android 4.0 开始,需要在清单中添加一个引用配置文件的<meta-data>标签👆,通过这个标签去引用设置的无障碍服务功能。

accessibility_config.xml

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description" 
    android:packageNames="com.example.android.apis"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>

<!--description:服务的描述文字-->
<!--canPerformGestures:是否支持手势-->
<!--notificationTimeout:事件的发送间隔事件,单位毫秒-->
<!--canRetrieveWindowContent:是否允许读取窗口中的内容-->
<!--accessibilityFeedbackType:事件的反馈类型,暂时不知道用作啥-->
<!--settingsActivity:开启服务界面显示一个设置按钮,可以返回应用指定界面-->
<!--canRequestTouchExplorationMode:在这种模式下,被触摸的项目会被大声说出,用户界面可以被激活通过手势探索-->
<!--accessibilityEventTypes:可以接收的事件类型,例如界面变化、点击等。typeAllMask 接收所有,根据实际情况选择合适的类型,减少电量的消耗-->

配置的全部属性可点击链接前往查看👉AccessibilityService Styleable

创建MyAccessibilityService类,并继承AccessibilityService,实现其抽象方法。

class MyAccessibilityService : AccessibilityService() {

	// 当系统检测到与无障碍服务指定的事件过滤参数匹配的 AccessibilityEvent 时执行
    override fun onAccessibilityEvent(event: AccessibilityEvent?) {
        TODO("Not yet implemented")
    }

	// 当系统要中断服务正在提供的反馈时执行
    override fun onInterrupt() {
        TODO("Not yet implemented")
    }
    
    // 连接上无障碍服务时执行
    override fun onServiceConnected() {
        super.onServiceConnected()
    }

	// 可选,关闭无障碍服务时执行
	override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }
}

启动无障碍服务的设置界面。

startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))

手动启动无障碍功能,onServiceConnected方法会收到回调,这里可以写启动某个App的代码。

MainActivity.getContext()?.packageManager?.let {
    startActivity(it.getLaunchIntentForPackage(packageName))
}

当系统检测到与无障碍服务指定的事件时,执行onAccessibilityEvent,接下来开始模拟点击操作。

模拟点击

开始模拟点击前,请先安装好Appium,可前往观看本人编写的文章进行学习App自动化测试 —— Appium的使用

组件ID & 组件文本

要想拿到组件的ID怎么搞?启动安装好的Appium,填写以下参数后启动Session。

{
  "platformName": "操作系统",
  "platformVersion": "操作系统版本号",
  "deviceName": "设备名称",
  "appPackage": "应用包名(文末有链接)",
  "appActivity": "app启动的第一个活动(可阅读参考文档了解如何获取)",
  "noReset": "true"
}

在这里插入图片描述
启动后会出现这样的界面,操作三个步骤后即可获取组件的ID。

Android的AccessibilityService类,提供了一个getRootInActiveWindow()方法,可以根据这个方法获取当前屏幕的根节点,接着就可以根据组件ID & 组件文本去查找到该点击的位置了。

// 根据ID查找组件
val iv_click = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.daimajia.gold:id/iv_check")
// 根据文本查找组件
val my = rootInActiveWindow.findAccessibilityNodeInfosByText("我的")

当然,不是所有的组件都有一个组件ID,也不是屏幕上只要有文字就一定能识别到并且触发其点击事件的。

坐标

有了以上两个查找界面组件,也可以让脚本自动化的差不多了,但还是有些许小瑕疵,例如,返回上一页的按钮,如果没有组件的ID和文字提示点击该按钮可以返回上一页,那么,以上的两个方法是无法做到点击该按钮的,如图:

在这里插入图片描述

而在Android提供的getRootInActiveWindow()方法中,并没有提供以坐标定位点击的位置,但还是提供了一个叫GestureDescription的类,让我们去处理坐标点击(滑动)的方案,使用该类就能解决掉组件没有ID或文字导致的无法识别到应该点击哪里的问题,但也因此诞生了一个新的问题:手机分辨率兼容。

后台保活

无障碍服务(AccessibilityService),是一个在后台运行的程序,既然涉及到后台,还得再提一次保活的问题。

在我的Socket 多人聊天室的实现 (含前后端源码讲解)(一)一文中使用的保活方式是在手机前台状态栏显示一个Notification,除此之外,当然有其它的方式,比如说整个app的弹窗,比较有代表性的腾* 的手机管家、36* 手机助手。

在这里图方便,依旧采用前台状态栏显示Notification的方式来实现保活,代码如下:

private fun startNotification() {
    val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
    val notificationId: String = UUID.randomUUID().toString()
    val notificationName: String = UUID.randomUUID().toString()
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // 高版本的模拟器或手机还需要开启渠道才能显示通知
        val notificationChannel = NotificationChannel(
            notificationId,
            notificationName,
            NotificationManager.IMPORTANCE_HIGH
        )
        notificationManager.createNotificationChannel(notificationChannel)
    }
    val builder = NotificationCompat.Builder(this, notificationId)
    builder.setSmallIcon(R.mipmap.ic_launcher)
    builder.setContentTitle(getString(R.string.app_name))
    builder.setContentText("用来保活的Notification,勿删!!!")
    builder.setAutoCancel(false)
    notificationManager.notify(0, builder.build())
}

效果图

在这里插入图片描述 在这里插入图片描述

存在缺陷

缺陷一

无障碍服务只能手动启动,部分品牌手机启用无障碍服务还得输入密码,且每启动一次软件就要开启一次,操作不是很方便。此题无解。

缺陷二

定位所使用的单位是像素(px),不同的手机像素不同,会出现点击的位置出错的问题。关于该问题,目前想到的方法有二:

  • 其一,整理出不同分辨率的手机点击的坐标,运行程序时,根据手机分辨率使用对应的坐标方案。
  • 其二,图片相似度比对,该方案来自外挂三部曲(三) —— Android 图片相似度对比

缺陷三

当程序自动点击一次并进入下一个界面,会受到页面加载速度的影响,需要加上Thread.sleep(long millis)来让线程暂缓执行,当几个页面中的某一个页面加载时间过长时,就会出现点击顺序错乱的问题,我现在还没想明白,为啥 李跳跳真实好友 这款app执行的速度那么快,有空真得反编译看一下人家是怎么写的才行,如果正在看文章的你知晓该如何解题,希望您能在评论区留下你的答案。

缺陷四

控件ID值可能会随着app的更新而发生变化,当findAccessibilityNodeInfosByViewId(String str)找不到对应的控件ID时,脚本的执行计划可能会因此而错乱。

注意:无障碍服务本意是为了帮助残障用户使用 Android 设备和应用而设计出来的,请勿用于违法用途。Android开发者已经够少的了,再少下去就要绝迹了…

本文代码下载链接👉【代码下载】

参考文档
1、无障碍服务
2、查找app的第一个启动页
3、获取App包名的方法
4、创建自己的无障碍服务

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

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

相关文章

从零搭建Sentry

前言 Sentry 为一套开源的应用监控和错误追踪的解决方案。这套解决方案由对应各种语言的 SDK 和一套庞大的数据后台服务组成。应用需要通过与之绑定的 token 接入 Sentry SDK 完成数据上报的配置。通过 Sentry SDK 的配置&#xff0c;还可以上报错误关联的版本信息、发布环境。…

四信机房环境监测方案上线 实现集中监控,统一管理

随着“东数西算”工程和新基建的加速落地&#xff0c;数智化技术正逐渐渗透到各领域。以机房行业为例&#xff0c;由于数据中心建设规模的逐步壮大&#xff0c;机房设备市场需求同步增长&#xff0c;为行业用户带来更多可能性。 伴随着机房中设备数量不断增多&#xff0c;如何…

Vue2实现浏览器ctrl+f功能

Vue2实现浏览器ctrlf功能 安装插件 使用一个Vue2的插件search-bar-vue2 npm install search-bar-vue2全局注册 //全局注册 import SearchBar from search-bar-vue2 Vue.use(SearchBar)局部注册 <template><div><search-bar :root"#app" :highlig…

【VUE】实现分页组件

&#x1f4d8;前言 &#x1f6a9;&#x1f6a9;&#x1f6a9; &#x1f48e;个人主页: 阿选不出来 &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;个人简介: 一名大二在校生,学习方向前端,不定时更新自己学习道路上的一些笔记. &#x1f4a8;&#x1f4a8;&#x1f4a…

Navigation--导航机理

1.ROS navigation为移动机器人导航相关包的集合&#xff0c;实现定位规划避障等相关功能。 整体工作流程为&#xff1a; 1.加载地图 navigation通过map_server加载现有地图。navigation无建图相关包&#xff0c;需另外实现后保存&#xff0c;默认只支持2维地图&#xff0c;其…

[附源码]Python计算机毕业设计Django游戏商城平台论文

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

推荐测试用例管理工具,看这篇就行。

我们在考虑测试用例管理的时候&#xff0c;其实不能单纯考虑测试用管理&#xff0c;因为你的测试用例是需要和需求关联起来的&#xff0c;是需要和 bug 关联起来的。在有些行业&#xff0c;比如汽车、医药&#xff0c;不仅要对需求进行测试&#xff0c;还需要对架构设计、详细设…

某CCF C会议对国内和国外作者实行两套标准, 引27%+中稿者发声!

点击文末公众号卡片&#xff0c;不错过计算机会议投稿信息 本文主要反映轻松参会交流群内UIC22(CCF C类) 的81位国内中稿作者的诉求&#xff08;占UIC22中稿数的27%&#xff09;。目前群内作者们的诉求为&#xff0c;希望国内作者可选择线上参会。因为线下参会有困难&#xff0…

2023年湖北监理工程师报考时间是什么时候?

2023年湖北监理工程师报考时间是什么时候&#xff1f; 监理工程师考试时间虽说是全国统一的&#xff0c;但是监理工程师报名时间不统一&#xff0c;每个省份自行安排报名时间&#xff0c;监理工程师报名时间基本都是在2.3月份开始报名&#xff0c;具体关注每个省人事考试院网站…

文件包含漏洞(原理及介绍)

文件包含漏洞&#xff08;原理及介绍&#xff09; File inclusion&#xff0c;文件包含&#xff08;漏洞&#xff09;。程序开发人员通常出于灵活性的考虑&#xff0c;会将被包含的文件设置成变量&#xff0c;然后动态调用这些文件。但正是因为调用的灵活性导致用户可能调用一…

flex布局子项属性

flex布局子项属性 1、flex属性 源代码 flex属性定义子项目分配剩余空间&#xff0c;用flex来表示占多少份数 flex: number; 填数值&#xff0c;分配剩余空间的占比 2、align-self控制子项自己在侧轴上的排列方式 源代码 align-self属性允许单个项目有…

Semi-Supervised Classification with Graph Convolutional Networks

Semi-Supervised Classification with Graph Convolutional Networks, ICLR, 2017 要点&#xff1a; 1、可扩展的半监督学习方法 2、基于卷积神经网络的有效变体&#xff0c;直接对图进行操作 3、通过谱图卷积的局部一阶近似来激励卷积架构的选择 4、在图的边数上进行线性缩放…

车辆纵向动力学、加速性能和燃料消耗研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 车辆纵向动力学方面包括车辆传动系统换挡控制、制动系统的设计与控制以及车辆状态的参数估计;车辆横向动力学方面涉及车辆转向…

lua vm 共享 proto

lua vm共享proto 场景 在skynet中&#xff0c;对于每一个lua服务&#xff0c;实际上就是在snlua上启动了一个lua虚拟机去完成lua逻辑&#xff0c;所以skynet的服务是相互隔离的。 这样就会产生一个问题&#xff0c;多个服务都require同一个lua库&#xff0c;每个服务内都会有…

原生API编写简单富文本编辑器001

原生API编写简单富文本编辑器001 从这一节开始&#xff0c;我们将亲自动手&#xff0c;使用我们之前介绍过的浏览器原生API来实现一个简单的可以处理文本的富文本编辑器。 1. 设计 这一个简单版的编辑器&#xff0c;由于我们是基于原生的API&#xff0c;基于浏览器原生API的…

线性表-双向链表

双向链表 双向链表也叫双向表&#xff0c;是链表的一种&#xff0c;它由多个结点组成&#xff0c;每个结点都由一个数据域和两个指针域组成&#xff0c;数据域用来存储数据&#xff0c;其中一个指针域用来指向其后继结点&#xff0c;另一个指针域用来指向前驱结点。链表的头结…

手动实现SpringBoot日志链路追踪

概述 有时候一个业务调用链场景&#xff0c;很长&#xff0c;调了各种各样的方法&#xff0c;看日志的时候&#xff0c;各个接口的日志穿插&#xff0c;确实让人头大。 模糊匹配搜索日志能解决吗&#xff1f;能解决一点点。但是不能完全呈现出整个链路相关的日志。 那要做到方…

致迷茫的程序员一封信——我的程序生涯

0、开头 大家好&#xff0c;我是罗鹏程&#xff0c;一个很老套的开头&#xff0c;哈哈哈。 这封信姗姗来迟&#xff0c;与其说是一封信&#xff0c;不如说是来听听我的故事。从2020开始&#xff0c;收到过很多网友的问题&#xff0c;职业的选择&#xff0c;是做大数据还…

Intellij Idea生成含有META-INF的jar包

新建一个module&#xff0c;如果不会新建的话&#xff0c;参考&#xff1a;Intellij Idea新建module。命名为jar_test。 新建一个java类DateUtil&#xff0c;可以输出当前时间对应的是星期几。代码如下&#xff1a; import java.util.Calendar; import java.util.Date;publi…

编译原理 1 - 概述、形式语言

第1章 引论一些概念1.3 编译程序的总体结构1.4 编译程序的组织第二章 形式语言2.1 文法描述中的基本概念上下文无关文法第1章 引论 一些概念 机器语言&#xff1a;以0、1代码表示的机器指令所构成的语言 每一个具体的计算机系统都具有自己的指令系统 汇编语言&#xff1a;用助…