IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android自动化之AccessibilityService -> 正文阅读

[移动开发]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) 方法设置无障碍功能焦点。

后记

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

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:18:44  更:2021-07-22 14:20:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 13:44:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码