Android自动化之AccessibilityService

功能介绍

无障碍服务是一种应用,可提供界面增强功能,来协助残障用户或可能暂时无法与设备进行全面互动的用户完成操作。例如,正在开车、照顾孩子或参加喧闹聚会的用户可能需要其他或替代的界面反馈方式。

AccessibilityService: 类

当AccessibilityEvent事件被启动后AccessibilityService 会接收回调函数运行于后台,这些事件指的是在用户接口间的状态转换,比如,焦点变化,按钮被点击等。

简单来说,通过继承于此类并且实现它的抽象方法,我们可以在service中接收到页面变动、页面组件变动和应用通知等消息,并做出响应的操作,并且可以通过该类获取到的视图节点做一些点击、滑动等操作,而且在android8.0之后支持连续手势。

借助此功能可以实现某某App的某某辅助、某某脚本、某某爬虫工具,官 方 wài guà 最 为 致 命。

快速开始

详细请看官方文档

1. 创建无障碍服务

创建一个扩展 AccessibilityService 的类

package com.example.android.apis.accessibility;

import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;

public class MyAccessibilityService extends AccessibilityService {
    @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventType = event.getEventType();//事件类型
        CharSequence packageName = event.getPackageName();//触发事件的包名
        if (packageName == null) return;
        String packageNameString = packageName.toString();
        // 要过滤的包名
        if (!packageNameString.startsWith("com.tencent")) return;
        switch (eventType) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
                // 页面发生变化
                AccessibilityNodeInfo rootNode = getRootInActiveWindow();
                if (rootNode == null) return;
                curWin = event.getClassName().toString();
                Log.d(TAG, "Activity切换,当前窗体:" + curWin);
                break;
            }
            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
                // 组件发生变化
                String className = event.getClassName().toString();
                Log.d(TAG, "Activity内容改变事件:" + className.toString());
                AccessibilityNodeInfo rootNode = getRootInActiveWindow();
                if (rootNode == null) return;
            }
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: {
                // 应用通知
                List<CharSequence> texts = event.getText();
                if (!texts.isEmpty()) {
                    for (CharSequence text : texts) {
                        String content = text.toString();
                        Log.d(TAG, "收到通知:" + content);
                    }
                }
                break;
            }
        }
    }

    @Override
    public void onInterrupt() {
    }
    
    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Toast.makeText(this, "xxx辅助功能已开启", Toast.LENGTH_SHORT).show();
    }
}

2. 清单声明、权限以及无障碍物服务配置

AndroidManifest.xml<application />中声明

<service android:name=".MyAccessibilityService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:label="@string/accessibility_service_label">
      <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
      </intent-filter>
      <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/robot_accessibility" />
</service>

其中@xml/robot_accessibility是无障碍服务的配置

在res中新建文件夹xml,在xml中创建robot_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="feedbackAllMask"
    android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows|flagIncludeNotImportantViews|flagRequestEnhancedWebAccessibility"
    android:canPerformGestures="true"
    android:canRetrieveWindowContent="true"
    android:notificationTimeout="300" />

打开辅助功能,运行应用,查看日志

使用手册

  1. 能有单独的音量设置
  2. 有快速开启关闭的快捷键(Android 8.0以上在虚拟导航栏有快捷设置)
  3. 指纹手势
  4. 多语言文字转语音
  5. 为用户执行操作 (更改输入焦点和选择、滚动列表、转到主屏幕、按“返回”按钮,以及打开通知屏幕和最近用过的应用列表等,所有可见元素都能由无障碍服务选择)
    // 封装一个点击节点的方法 (NodeID为自定义枚举类,getId得到的是字符串,可以直接用字符串)
    private boolean clickView(NodeID nodeId, int index) {
        AccessibilityNodeInfo rootNode = getRootInActiveWindow();
        if (rootNode == null) {
            List<AccessibilityWindowInfo> windows = getWindows();
            if (windows.size() != 0) {
                Log.d(TAG, "windows: " + windows);
                rootNode = windows.get(0).getRoot();
            }
            if (rootNode == null) {
                Log.d(TAG, "获取不到rootNode");
                return false;
            }
        }
        List<AccessibilityNodeInfo> nodes = rootNode.findAccessibilityNodeInfosByViewId(nodeId.getId());
        int size = nodes.size();
        if (size != 0) {
            AccessibilityNodeInfo node = nodes.get(index);
            Log.d(TAG, nodeId + " 共找到" + size + "个控件, 点击第" + (index + 1) + "个," + node);
            node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            return true;
        }
        Log.d(TAG, nodeId + " 点击失败");
        return false;
    }
    // 当一些控件没有id,可以通过getChild或者getParent的方式拿到 返回为一个AccessibilityNodeInfo实例,此后可以调用方法进行点击、滑动或者获取它在屏幕中的位置
    private AccessibilityNodeInfo getViewChild(NodeID nodeId, int index, int childIndex) {
        AccessibilityNodeInfo rootNode = getRootInActiveWindow();
        if (rootNode == null) {
            List<AccessibilityWindowInfo> windows = getWindows();
            if (windows.size() != 0) {
                Log.d(TAG, "windows: " + windows);
                rootNode = windows.get(0).getRoot();
            }
            if (rootNode == null) {
                Log.d(TAG, "获取不到rootNode");
                return null;
            }
        }
        List<AccessibilityNodeInfo> nodes = rootNode.findAccessibilityNodeInfosByViewId(nodeId.getId());
        int size = nodes.size();
        if (size != 0) {
            AccessibilityNodeInfo node = nodes.get(index);
            Log.d(TAG, nodeId + " 共找到" + size + "个控件");
            AccessibilityNodeInfo nodeChild = node.getChild(childIndex);
            return nodeChild;
        }
        Log.d(TAG, nodeId + " childIndex: " + childIndex + " 点击失败");
        return null;
    }
  1. 监听手势
  2. 连续手势 (Android8.0以上)
    // 一个通过手势模拟点击的例子 rect为控件的位置 可以通过AccessibilityNodeInfo实例的getBoundsInScreen方法获取
    public void clickGesture(Rect rect) {
        Path path = new Path();
        path.moveTo(rect.centerX(), rect.centerY());
        GestureDescription.StrokeDescription strokeDescription;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            strokeDescription = new GestureDescription.StrokeDescription(path, 10, 10);
            GestureDescription.Builder gestureDescription = new GestureDescription.Builder().addStroke(strokeDescription);
            this.dispatchGesture(gestureDescription.build(), null, null);
        }
    }
    // 通过手势在x轴上滑动的例子 注意的距离可能需要通过dpi计算
    public void horizontalSlideGesture(Rect rect, int distanceX) {
        // 有需要请认真阅读Path类说明
        Path path = new Path();
        path.moveTo(rect.centerX(), rect.centerY());
        path.lineTo((float) (rect.centerX() + distanceX), rect.centerY());
        GestureDescription.StrokeDescription strokeDescription;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            strokeDescription = new GestureDescription.StrokeDescription(path, 0, 1500);
            GestureDescription.Builder gestureDescription = new GestureDescription.Builder().addStroke(strokeDescription);
            this.dispatchGesture(gestureDescription.build(), null, null);
        }
    }
  1. 使用焦点类型

无障碍服务可以使用 AccessibilityNodeInfo.findFocus() 方法来确定哪个界面元素具有输入焦点或无障碍功能焦点。您还可以使用 focusSearch() 方法搜索可通过输入焦点选择的元素。最后,无障碍服务可以使用 performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS) 方法设置无障碍功能焦点。

后记

本文仅个人记录使用,还有一些常用封装方法,仅供参考,并非最优解。
实际使用请通读官方文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: Android无障碍服务是一种功能,可以帮助用户更轻松地使用设备,包括视觉、听觉、运动和认知障碍。它可以通过提供语音反馈、触觉反馈、放大屏幕等方式来帮助用户。无障碍服务还可以自动化一些任务,例如读取通知、填写表单等。 ### 回答2: AndroidAccessibilityService是一个系统级别的服务,可以帮助用户在Android系统上更好的使用功能,尤其是对于那些具有身体障碍、视觉障碍和听觉障碍等特殊需求的用户来说,AccessibilityService可以提供完美的解决方案,通过对系统上的事件和用户交互进行监听和分析,然后帮助用户轻松的实现他们想要达成的功能。 AccessibilityService的工作原理是通过监听Android系统上的一些事件,比如界面控件的变化、通知的出现、文本输入等等,然后对这些事件进行判断和处理,最终将结果反馈给用户。通过AccessibilityService框架,用户可以设置所需要实现的功能,并在设备中启用对应的服务,这样AccessibilityService便能够按照用户的需求来对事件进行分析,并在需要时向用户发送通知或执行指定的操作。 AccessibilityServiceAndroid的应用场景中得到了广泛的应用,它可以用来优化屏幕导航、改善文字输入、提高阅读体验、帮助用户控制设备等等。比如对于肢体残疾的用户,他们可能难以使用传统的手持设备,但是通过使用可支持无障碍功能的设备,他们可以轻松地使用语音识别来输入文字、使用语音命令来操作设备、使用触控手势来控制屏幕等等。 总之,AccessibilityService为使用Android设备的用户提供了一个更加便捷和自然的界面和服务,有效的帮助了一部分特殊需求的用户,使得智能手持设备向着更加无障碍化、智能化、人性化的方向不断发展和完善。 ### 回答3: Android AccessibilityService是一个服务,它可以让用户在使用设备时更加方便,无论用户是否患有视力或听力障碍。通过使用Android AccessibilityService,开发人员可以改善用户体验,例如提高可访问性、方便操作等。许多应用程序都可以从Android AccessibilityService中受益,这些应用程序包括辅助浏览、读取屏幕、听屏幕等。 Android AccessibilityService的基本原理是将一个服务添加到Android系统中,该服务可以监视系统事件,并在用户发出命令时自动触发相应的功能。例如,当用户在屏幕上点击文本框时,AccessibilityService可以自动弹出一个软件键盘以便用户进行输入。 开发人员可以使用Android AccessibilityService API来开发自己的服务,并实现自己的功能。例如,开发人员可以使用这些API来获取用户在屏幕上执行的所有事件,并根据这些事件来触发相应的功能,例如高亮屏幕,增加音量等。 总之,Android AccessibilityService使得使用设备更加方便,无论用户是否具有视力或听力障碍,而且可以广泛应用于各种应用程序中。开发人员在设计应用程序时应该考虑到这一点,并尽可能地提高应用程序的可访问性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

happy_plus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值