扣丁书屋

Android 无障碍开发入门

一、AccessibilityService

根据官方的介绍,是指开发者通过增加类似contentDescription的属性,从而在不修改代码的情况下,让残障人士能够获得使用体验的优化,大家可以打开AccessibilityService来试一下,点击区域,可以有语音或者触摸的提示,帮助残障人士更好的使用App

现在被广泛应用在自动化,比如自动抢红包,抖音自动关注点赞等

官方文档:

https://developer.android.com/guide/topics/ui/accessibility/service

二、AccessibilityService 开发流程

1.确定执行脚本的APK安装包

2.通过UIAutomator 获取包名及UI控件ID,或者下载一个开发者助手apk,也可以进行控件ID获取,代码君已经帮你下载好了,需要自取

http://share.dmjzy.cn/f/17143538-501591536-a374b2(访问密码:8401)

3.编写脚本代码

4.调试、兼容性处理

三、核心代码

1.AccessibilityService主要是实现onAccessibilityEvent

public class AccessibilitySampleService extends AccessibilityService{

    /**当无障碍服务连接之后回调*/
   @Override
   public void  onServiceConnected() {
        super.onServiceConnected()
    }

    /**当触发了需要监听的无障碍事件后回调*/
   @Override 
   public void onAccessibilityEvent(AccessibilityEvent event){
       // 获取包名
       String pkgName = event.getPackageName().toString();
       int eventType = event.getEventType();

       AccessibilityOperator.getInstance().updateEvent(this, event);
       //过滤出目标包,如果要检测所有包,可以去掉此判断
       if (pkgName.equals(pageName)) {
           AccessibilityLog.printLog("eventType: " + eventType + " pkgName: " + pkgName);

           switch (eventType) {
               case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                   //执行具体的脚本
                   toOperator();
                   break;
               case AccessibilityEvent.TYPE_VIEW_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                   break;
               case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                   break;
           }
       }
   } 
   /**无障碍服务断开后回调*/
   @Override 
   public void onInterrupt(){
       // TODO Auto-generated method stub 
   }
}

方法说明

1. onServiceConnected

当声明的无障碍服务连接之后, 系统会回调此方法. 在这个方法里, 可以做一些初始化工作. 比如保存服务的实例 标识服务连接的状态等.

也可以通过

android.accessibilityservice.AccessibilityService#getServiceInfo

动态更改xml配置文件中声明的无障碍配置信息.

2. onAccessibilityEvent

当监听的事件触发时, 系统会回调此方法, 比如view被点击了 window内容改变了等.

可以用

android.view.accessibility.AccessibilityRecord#getSource

获取对象AccessibilityNodeInfo, 这个对象就是无障碍操作的核心对象, 通常可以理解为android开发中的view控件.

可以通过AccessibilityNodeInfo对象, 进行控件的点击操作 输入文本操作 滚动操作 获取文本操作等

3. onInterrupt

当中途关闭了无障碍服务时回调, 通常这个时候无障碍服务不可用, 调用api都会失败.

4. AccessibilityService 其他方法说明

方法名 方法说明
disableSelf() 禁用当前服务,也就是在服务可以通过该方法停止运行
findFoucs(int falg) 查找拥有特定焦点类型的控件
getRootInActiveWindow() 如果配置能够获取窗口内容,则会返回当前活动窗口的根结点
performGlobalAction(int action) 执行全局操作,比如返回,回到主页,打开最近等操作,此方法可以模拟用户点击返回键和home键,操作见下面的官方文档
setServiceInfo(AccessibilityServiceInfo info) 设置当前服务的配置信息
getSystemService(String name) 获取系统服务
onKeyEvent(KeyEvent event) 如果允许服务监听按键操作,该方法是按键事件的回调,需要注意,这个过程发生了系统处理按键事件之前

更多AccessibilityService参数说明见官方文档:

https://developer.android.google.cn/reference/kotlin/android/accessibilityservice/AccessibilityService

AccessibilityEvent

字段名 字段说明
TYPE_NOTIFICATION_STATE_CHANGED 通知栏状态变化
TYPE_VIEW_CLICKED 视图被点击
TYPE_WINDOW_CONTENT_CHANGED 窗口内容变化
TYPE_WINDOW_STATE_CHANGED 窗口状态变化,即切换activity

2. AndroidManifest.xml注册服务

<!-- 注册辅助功能服务-->
       <service
           android:name=".AccessibilitySampleService"
           android:exported="true"
           android:label="码君助手"
           android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
           android:process=":BackgroundService">
           <intent-filter>
               <action android:name="android.accessibilityservice.AccessibilityService" />
           </intent-filter>
           <!--       通过xml文件完成辅助功能相关配置,也可以在onServiceConnected中动态配置-->
           <meta-data
               android:name="android.accessibilityservice"
               android:resource="@xml/accessibility_config" />
       </service>

3. 在资源文件夹新增xml文件夹,新建accessibility_config文件,代码如下

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:description="@string/accessibility_desc"
    android:notificationTimeout="10" />

<!--  canPerformGestures  //申请手势权限-->
<!--accessibility_desc:码君助手,让你的手机更智能一点 -->

accessibility_config说明

官方文档说明:

https://developer.android.google.cn/reference/android/R.styleable#AccessibilityService

这里列举一些比较常用的

字段名 字段说明
accessibilityEventTypes 表示该服务对界面中的哪些变化感兴趣,即哪些事件通知,比如窗口打开,滑动,焦点变化,长按等.具体的值可以在AccessibilityEvent类中查到,如typeAllMask表示接受所有的事件通知
accessibilityFeedbackType 表示反馈方式,比如是语音播放,还是震动。feedbackGeneric代表所有
canRetrieveWindowContent 表示该服务能否访问活动窗口中的内容.也就是如果你希望在服务中获取窗体内容的化,则需要设置其值为true
notificationTimeout 接受事件的时间间隔,通常将其设置为100即可
packageNames 表示对该服务是用来监听哪个包的产生的事件。如果不写代表监听所有的应用。中间可以用";"来分割。
canPerformGestures 表示可以执行手势属性
canTakeScreenshot 是否能够截屏

4、编写执行脚本

try {
           Thread.sleep(2000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/btn_later");// 关闭弹框

           Thread.sleep(1000);
           AccessibilityOperator.getInstance().clickById("com.xxxx.packagename:id/tab_work");//切换到工作tab
           AccessibilityLog.printLog("切换到工作tab: ");

       } catch (InterruptedException e) {
           e.printStackTrace();
       }

AccessibilityNodeInfo

方法名 方法说明
findAccessibilityNodeInfosByText() 通过字符串查找节点元素
findAccessibilityNodeInfosByViewId() 通过视图id查找节点元素
performAction() 在节点上执行一个动作,比如点击、向上滑动等,更多操作见下面的官方文档
getParent() 获取父节点
getChild() 获取子节点
isEnabled() 判断节点是否激活
isClickable() 判断节点是否可以点击
isScrollable() 判断节点是否可以滚动
isSelected() 判断节点是否选中
isPassword() 判断节点是否是密码输入框
isFocusable() 判断节点是否可以获取焦点
getText() 获取节点的文本信息
getContentDescription() 节点的内容描述
getViewIdResourceName() 获取节点控件的id ,获取到的值大概是这样的:com.ss.android.ugc.aweme:id/afy
getBoundsInScreen() 获取节点在屏幕中的位置
getClassName() 获取节点的类型/类名,值:android.widget.LinearLayout
getChild() 获取子节点的AccessibilityNodeInfo信息

更多请查看官方文档:

https://developer.android.google.cn/reference/android/view/accessibility/AccessibilityNodeInfo


https://mp.weixin.qq.com/s/xCKkQgLKEOt-ZzhcO8e1ew

最多阅读

简化Android的UI开发 1年以前  |  514330次阅读
Android 深色模式适配原理分析 11月以前  |  24683次阅读
Android Studio 生成so文件 及调用 1年以前  |  3928次阅读
30分钟搭建一个android的私有Maven仓库 2年以前  |  3798次阅读
Android设计与开发工作流 1年以前  |  3696次阅读
Google Enjarify:可代替dex2jar的dex反编译 2年以前  |  3545次阅读
Android多渠道打包工具:apptools 2年以前  |  3195次阅读
Google Java编程风格规范(中文版) 2年以前  |  3079次阅读
Android UI基本技术点 2年以前  |  3029次阅读
Android-模块化-面向接口编程 1年以前  |  3018次阅读
Android死锁初探 1年以前  |  3017次阅读
Android内存异常机制(用户空间)_NE 1年以前  |  2867次阅读
Stetho 2年以前  |  2812次阅读
Android权限 - 第一篇 2年以前  |  2808次阅读

手机扫码阅读