更新记录

1.0.2(2024-04-19)

新增方法:

  1. node(params, callback)
  2. clickByIndex(index)
  3. editByIndex(index, text)

1.0.1(2024-04-15)

  • 添加停止接收页面变动事件回调 stop()
  • 修复无障碍设置标题显示问题

1.0.0(2024-04-10)

查看更多

平台兼容性

Android Android CPU类型 iOS
适用版本区间:7.0 - 14.0 armeabi-v7a:支持,arm64-v8a:支持,x86:支持 ×

原生插件通用使用流程:

  1. 购买插件,选择该插件绑定的项目。
  2. 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
  3. 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
  4. 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
  5. 开发完毕后正式云打包

付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios

注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择


UniApp 原生安卓无障碍插件

插件提供了查询点击页面的节点获取屏幕节点的信息输入文本、支持点击坐标滑动屏幕、返回到桌面打开最近任务、获取应用程序包名获取屏幕上的所有节点以及遍历屏幕上的所有节点。这些无障碍接口足以帮助你完成一系列的操作,如实现各种自动化控制手机和执行自动化操作、自动化测试、用户行为模拟和界面操作等。

演示程序

扫码下载示例APP

初始化导入类

注意:请先打包自定义基座

const LinAccessibility = uni.requireNativePlugin('Lin-Accessibility');

打开设置获取无障碍权限 goAliveSetting()

示例调用:

LinAccessibility.goAliveSetting() // 跳转到设置

getServiceState() 判断无障碍服务是否开启

用于判断无障碍服务是否开启,返回值为布尔型。

返回值说明

返回值 说明
true 已开启无障碍
false 未开启无障碍

示例调用:

console.log(LinAccessibility.getServiceState()) // true 或 false

start(options, callback) 接收页面变动事件

start 方法参数说明:

参数名 类型 描述
options object 配置无障碍服务的参数
callback function 无障碍服务的响应

options 参数说明:

参数名 类型 描述
packageNames string[] 要监视的应用程序包的名称数组
notificationTimeout number 通知栏状态变化时的监听时间
monitorAllEvent boolean 是否监视所有事件

注:monitorAllEvent 设置不同的值 响应的结果也不同。

callback 的回调参数说明:

参数名 类型 描述
class_name string 触发事件的视图类名
package_name string 触发事件的应用程序包名
event_type number 触发的事件类型

event_type 触发的事件类型值说明:

event_type 说明
1 视图被点击
32 切换了页面
64 通知栏状态变化
2048 窗口内容变化

示例调用:

// 开始接收页面变动事件回调
LinAccessibility.start({
    packageNames: ['com.example.app1', 'com.example.app2'],
    notificationTimeout: 20,
    monitorAllEvent: true
}, (response) => {
    // 处理 LinAccessibility 无障碍服务的响应
    console.log(response);
});

stop() 停止接收页面变动事件回调

示例调用:

LinAccessibility.stop();

getState() 获取事件回调状态

示例调用:

console.log(LinAccessibility.getState()) // true 或 false

返回值说明

返回值 说明
true start() 事件回调运行中
false start() 事件回调未运行

node(params, callback) 方法

方法用于在当前界面上查找第一个满足条件的节点,并执行点击或编辑操作。

node 方法参数说明:

参数名 类型 描述
params object 配置条件参数
callback function 执行结果回调

params 参数说明:

参数名 类型 必填 说明
text string 节点的 text 属性
textMatch string 节点的 text 符合 textMatch 正则
id string 节点的 id
className string 节点的类名
packageName string 节点的包名
contentDesc string 节点的 contentDesc 属性
contentDescMatch string 节点的 contentDesc 符合 contentDescMatch 正则
edit string 需要编辑的内容
click boolean 是否点击节点

callback 回调参数说明:

参数名 类型 说明
accNode boolean 是否找到满足条件的节点
click boolean 是否成功点击节点
edit boolean 是否成功编辑节点

示例调用:

node({
    click: true,
    textMatch:".*匹配文字.*",
    edit: true,
    edit:"输入文本内容"
}, (result) => {
    const { accNode, click, edit } = result;
    if(accNode) {
        if(click) console.error("点击成功")
        if(edit) console.error("编辑成功")
    }else{
        console.error("没找见满足条件的节点")
    }
})

我们提供了丰富的无障碍操作API

方法名 描述 返回值
findFirstNodeByText(text) 查询是否存在文字符合的节点 boolean
clickFirstNodeByText(text) 点击第一个文字符合的节点 boolean
getNodeSizeById(id) 获取符合id的节点数量 number
clickById(id, index) 点击符合id的节点,可先用getNodeSizeById获取数量 boolean
findFirstNodeByNotFullText(text) 查询是否存在文字符合包含的节点 boolean
clickFirstNodeByNotFullText(text) 点击第一个文字符合包含的节点 boolean
findFirstNodeByContentDesc(text) 查询是否存在文字描述符合的节点 boolean
clickFirstNodeByDesc(text) 点击第一个文字描述符合的节点 boolean
findFirstNodeByNotFullDesc(text) 查询是否存在文字描述符合包含的节点 boolean
clickFirstNodeByNotFullDesc(text) 点击第一个文字描述符合包含的节点 boolean
edit(id, text) 输入文本 boolean
getFirstNodeInformByText(text, fields) 获取第一个符合文字的节点信息,fields包含如下字段 object
getNodeInformById(id, index, fields) 获取第index个符合id的节点信息 object
getFirstNodeInformById(id, fields) 获取第一个符合id的节点信息 object
getChildNodeInform(id, nodeIndex, childIndex, fields) 获取第nodeIndex个id符合的节点的第childIndex个节点信息 object
clickLocation(x, y) 点击坐标 void
slideScreen(start_x, start_y, end_x, end_y, duration) 滑动屏幕 void
goBack() 返回 boolean
goHome() 回到桌面 boolean
goRecentTasks() 打开最近任务 boolean
getTagState(texts, callback) 查询多个文字判断是否存在 void
moveAppToFront() 后台唤起应用程序。需要后台弹出窗口权限 void
getPackageName() 获取应用程序包名称 string
getAllNodes(callback) 获取 屏幕上的所有节点 void
forNodes(callback) 遍历 屏幕上的所有节点 void
clickByIndex(index) forNodes/getAllNodes方法遍历获得的index boolean
editByIndex(index, text) forNodes/getAllNodes方法遍历获得的index boolean

接口调用示例:

// 初始化导入类
const LinAccessibility = uni.requireNativePlugin('Lin-Accessibility');
// 开始接收页面变动事件回调
LinAccessibility.start({
    applicationId: 'myAppId',
    packageNames: ['com.example.app1', 'com.example.app2'],
    notificationTimeout: 5000,
    monitor_all_event: true
}, (response) => {
    // 处理 LinAccessibility 无障碍服务的响应
    console.log(response);
});

// 停止接收页面变动事件回调
let isStopped = LinAccessibility.stop();
console.log("Is stopped", isStopped);

// 查询是否存在文字符合的节点
let isTextFound = LinAccessibility.findFirstNodeByText("ExampleText");
console.log("Text found: ", isTextFound);

// 点击第一个文字符合的节点
let isClicked = LinAccessibility.clickFirstNodeByText("ExampleText");
console.log("Clicked: ", isClicked);

// 获取符合id的节点数量
let nodeCount = LinAccessibility.getNodeSizeById("exampleId");
console.log("Node count: ", nodeCount);

// 点击符合id的节点,可先用getNodeSizeById获取数量
let isNodeClicked = LinAccessibility.clickById("exampleId", 0);
console.log("Node clicked: ", isNodeClicked);

// 查询是否存在文字符合包含的节点
let isTextPartiallyFound = LinAccessibility.findFirstNodeByNotFullText("ExampleText");
console.log("Text partially found: ", isTextPartiallyFound);

// 点击第一个文字符合包含的节点
let isPartialTextClicked = LinAccessibility.clickFirstNodeByNotFullText("ExampleText");
console.log("Partial text clicked: ", isPartialTextClicked);

// 查询是否存在文字描述符合的节点
let isDescFound = LinAccessibility.findFirstNodeByContentDesc("ExampleDesc");
console.log("Desc found: ", isDescFound);

// 点击第一个文字描述符合的节点
let isDescClicked = LinAccessibility.clickFirstNodeByDesc("ExampleDesc");
console.log("Desc clicked: ", isDescClicked);

// 查询是否存在文字描述符合包含的节点
let isPartialDescFound = LinAccessibility.findFirstNodeByNotFullDesc("ExampleDesc");
console.log("Partial desc found: ", isPartialDescFound);

// 点击第一个文字描述符合包含的节点
let isPartialDescClicked = LinAccessibility.clickFirstNodeByNotFullDesc("ExampleDesc");
console.log("Partial desc clicked: ", isPartialDescClicked);

// 输入文本
let isTextEntered = LinAccessibility.edit("exampleId", "ExampleText");
console.log("Text entered: ", isTextEntered);

// 获取第一个符合文字的节点信息
LinAccessibility.getFirstNodeInformByText("ExampleText", ['className', 'text', 'packageName'], (nodeInfo) => {
    console.log("Node information: ", nodeInfo);
});

// 获取第index个符合id的节点信息
LinAccessibility.getNodeInformById("exampleId", 0, ['className', 'text', 'packageName'], (nodeInfo) => {
    console.log("Node information: ", nodeInfo);
});

// 获取第一个符合id的节点信息
LinAccessibility.getFirstNodeInformById("exampleId", ['className', 'text', 'packageName'], (nodeInfo) => {
    console.log("Node information: ", nodeInfo);
});

// 获取第nodeIndex个id符合的节点的第childIndex个节点信息
LinAccessibility.getChildNodeInform("exampleId", 0, 0, ['className', 'text', 'packageName'], (nodeInfo) => {
    console.log("Node information: ", nodeInfo);
});

// 点击坐标
LinAccessibility.clickLocation(100, 200);

// 滑动屏幕
LinAccessibility.slideScreen(100, 200, 300, 400, 500);

// 返回
let isBack = LinAccessibility.goBack();
console.log("Back: ", isBack);

// 回到桌面
let isHome = LinAccessibility.goHome();
console.log("Home: ", isHome);

// 打开最近任务
let recentTasksOpened = LinAccessibility.goRecentTasks();
console.log("Recent tasks opened: ", recentTasksOpened);

// 查询多个文字判断是否存在
LinAccessibility.getTagState(['text1', 'text2'], (status) => {
  console.log('Does the text exist', status)
});

// 获取应用程序包名称
let packageName = LinAccessibility.getPackageName();
console.log("Package name: ", packageName);

// 获取屏幕上的所有节点
LinAccessibility.getAllNodes((nodes) => {
    console.log("All nodes: ", nodes);
});

// 遍历屏幕上的所有节点
LinAccessibility.forNodes((node) => {
    console.log("Node: ", node);
});

let index = 24
// 点击节点(根据索引)forNodes/getAllNodes方法遍历获得的 index
LinAccessibility.clickByIndex(index);

// 输入文本(根据索引)forNodes/getAllNodes方法遍历获得的 index
LinAccessibility.editByIndex(index, 'ExampleText');

以上接口足以让你完成大部分的需求了,如果有什么疑问,请在下方留言哦。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

android.permission.REORDER_TASKS android.permission.BIND_ACCESSIBILITY_SERVICE

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问