M8Test Help

最佳实战

在使用无障碍服务查找节点时,我们可以通过无障碍选择器 选择所需节点。对于一些简单节点,通过节点的文本或者描述信息即可获取唯一节点;但对于另一些节点,无法通过某些属性唯一定位,这时就需要通过层级结构来定位,例如指定父节点、子节点及兄弟节点的属性(无需全部使用,只需能唯一确定或获取所需数量的节点即可)。

通过文本或描述选择节点

如下图所示,界面中包含非常明显且内容唯一的文本,此时可通过文本内容获取节点。

333

我们可以通过无障碍选择器的 text 方法来筛选节点信息:

334
import com.m8test.script.GlobalVariables._accessibility import com.m8test.script.GlobalVariables._console // 定义一个选择器用于筛选文本为"插件"的节点 val selector = _accessibility!!.createSelector().text { it == "插件" } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
// 定义一个选择器用于筛选文本为"插件"的节点 def selector = $accessibility.createSelector().text { it == "插件" } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
import com.m8test.accessibility.api.AccessibilityNode; import com.m8test.accessibility.api.AccessibilitySelector; import kotlin.jvm.functions.Function1; import static com.m8test.script.GlobalVariables.$accessibility; import static com.m8test.script.GlobalVariables.$console; // 定义一个选择器用于筛选文本为"插件"的节点 AccessibilitySelector selector = $accessibility.createSelector().text(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "插件".equals(o); } return false; } }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node);
// 定义一个选择器用于筛选文本为"插件"的节点 let selector = $accessibility.createSelector().text(function (it) { return it === "插件" }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
-- 定义一个选择器用于筛选文本为"插件"的节点 local selector = _accessibility:createSelector():text(function(text) return text == "插件" end) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(0, -1) -- 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console:log("找到节点", node)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 定义一个选择器用于筛选文本为"插件"的节点 $selector = $accessibility->createSelector()->text(function ($text) { return $text == javaString("插件"); }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console->log(javaString("找到节点"), $node);
from m8test_java.com.m8test.script.GlobalVariables import _accessibility from m8test_java.com.m8test.script.GlobalVariables import _console # 定义一个选择器用于筛选文本为"插件"的节点 selector = _accessibility.createSelector().text(lambda text: text == "插件") # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
# encoding: utf-8 # 定义一个选择器用于筛选文本为"插件"的节点 selector = $accessibility.createSelector.text { |text| text == "插件" } # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)

除单独使用 text 方法外,还可结合其他方法组合选择器。例如判断是否在小红书首页,除找到文本为首页的节点外,还需该节点处于选中状态,这时就可以增加 selected 方法来选择被选中的节点,即同时满足文本为首页且处于选中状态的节点。若能找到这样的节点,就表明处于小红书首页。

335
import com.m8test.script.GlobalVariables._accessibility import com.m8test.script.GlobalVariables._console // 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 val selector = _accessibility!!.createSelector() .text { it == "首页" } .selected { it } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
// 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 def selector = $accessibility.createSelector() .text { it == "首页" } .selected { it } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
import com.m8test.accessibility.api.AccessibilityNode; import com.m8test.accessibility.api.AccessibilitySelector; import kotlin.jvm.functions.Function1; import static com.m8test.script.GlobalVariables.$accessibility; import static com.m8test.script.GlobalVariables.$console; // 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 AccessibilitySelector selector = $accessibility.createSelector().text(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "首页".equals(o); } return false; } }).selected(new Function1() { @Override public Object invoke(Object o) { return o; } }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node);
// 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 let selector = $accessibility.createSelector().text(function (it) { return it === "首页" }).selected(function (it) { return it }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
-- 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 local selector = _accessibility:createSelector():text(function(text) return text == "首页" end):selected(function(flag0) return flag0 end) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(0, -1) -- 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console:log("找到节点", node)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 $selector = $accessibility->createSelector()->text(function ($text) { return $text == javaString("首页"); })->selected(function ($selected) { return $selected; }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console->log(javaString("找到节点"), $node);
from m8test_java.com.m8test.script.GlobalVariables import _accessibility from m8test_java.com.m8test.script.GlobalVariables import _console # 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 selector = _accessibility.createSelector().text(lambda text: text == "首页").selected(lambda selected: selected) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
# encoding: utf-8 # 定义一个选择器用于筛选文本为"首页"并且处于选中状态的节点 selector = $accessibility.createSelector .text { |text| text == "首页" } .selected { |selected| selected } # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)

除通过文本选择节点外,还可通过节点的描述信息选择节点。一般情况下,图标按钮会包含描述信息,以帮助残障人士通过无障碍服务使用应用。但有些应用不会添加描述信息,甚至像微信这样的应用会限制无障碍服务的使用,所以对于描述信息,有则用,无则不用。

在小红书首页的搜索按钮中,其描述信息为 搜索 ,我们可以使用该描述信息选择节点:

336
import com.m8test.script.GlobalVariables._accessibility import com.m8test.script.GlobalVariables._console // 定义一个选择器用于筛选描述信息为"搜索"的节点 val selector = _accessibility!!.createSelector().desc { it == "搜索" } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
// 定义一个选择器用于筛选描述信息为"搜索"的节点 def selector = $accessibility.createSelector().desc { it == "搜索" } // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
import com.m8test.accessibility.api.AccessibilityNode; import com.m8test.accessibility.api.AccessibilitySelector; import kotlin.jvm.functions.Function1; import static com.m8test.script.GlobalVariables.$accessibility; import static com.m8test.script.GlobalVariables.$console; // 定义一个选择器用于筛选描述信息为"搜索"的节点 AccessibilitySelector selector = $accessibility.createSelector().desc(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "搜索".equals(o); } return false; } }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node);
// 定义一个选择器用于筛选描述信息为"搜索"的节点 let selector = $accessibility.createSelector().desc(function (it) { return it === "搜索" }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(0, -1) // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)
-- 定义一个选择器用于筛选描述信息为"搜索"的节点 local selector = _accessibility:createSelector():desc(function(desc) return desc == "搜索" end) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(0, -1) -- 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console:log("找到节点", node)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 定义一个选择器用于筛选描述信息为"搜索"的节点 $selector = $accessibility->createSelector()->desc(function ($desc) { return $desc == javaString("搜索"); }); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne(0, -1); // 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console->log(javaString("找到节点"), $node);
from m8test_java.com.m8test.script.GlobalVariables import _accessibility from m8test_java.com.m8test.script.GlobalVariables import _console # 定义一个选择器用于筛选描述信息为"搜索"的节点 selector = _accessibility.createSelector().desc(lambda desc: desc == "搜索") # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 _console.log("找到节点", node)
# encoding: utf-8 # 定义一个选择器用于筛选描述信息为"搜索"的节点 selector = $accessibility.createSelector.desc { |desc| desc == "搜索" } # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 这里简单打印节点,实际开发中需要判断节点是否为null, 如果不为null可以对节点进行操作,例如点击、设置文本等。 $console.log("找到节点", node)

通过层次结构选择节点

若节点既无文本信息也无描述信息,我们可以通过定义层次结构来选择节点。这种方法稍显复杂,因为可能需要设置父节点、子节点及兄弟节点的选择器来描述所选节点的层级关系,当然无需全部设置,根据实际需求设置即可。

通过层次结构选择节点时,主要用到 className 方法,因为每个节点的 className 都不为空,一定有值。通过这种方式,只要层级结构定义足够详细,就可以选择界面上任意所需节点。

下面是通过层次结构选择节点的步骤:

第一步,定义需要选择的节点的选择器。这是最重要的一步,首先必须确定需要选择的节点是什么。这里以选择小红书视频界面中右侧的工具栏(15 表示深度,0 表示索引)为例,该工具栏包含点赞收藏分享等信息,其类名为 android.widget.LinearLayout

337
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 val selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" }
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 def selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" }
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 AccessibilitySelector selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.LinearLayout".equals(o); } return false; } })
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 let selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.LinearLayout" })
-- 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 local selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.LinearLayout" end)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 $selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.LinearLayout"; })
# 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.LinearLayout")
# 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.LinearLayout" }.

由于节点本身的信息有限,我们可以通过定义其父节点、子节点及兄弟节点的选择器来获取更多信息(无需全部使用,只要能唯一确定节点即可)。

第二步,为父节点(14,1)定义选择器。可以看到其类名为 android.widget.FrameLayout ,当然,除类名外,也可以用其他属性作为条件。

338
// 节点(小红书视频界面右边的工具栏)父节点的选择器 val parentSelector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" }
// 节点(小红书视频界面右边的工具栏)父节点的选择器 def parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" }
// 节点(小红书视频界面右边的工具栏)父节点的选择器 AccessibilitySelector parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.FrameLayout".equals(o); } return false; } });
// 节点(小红书视频界面右边的工具栏)父节点的选择器 let parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.FrameLayout" })
-- 节点(小红书视频界面右边的工具栏)父节点的选择器 local parentSelector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.FrameLayout" end)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)父节点的选择器 $parentSelector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.FrameLayout"; });
# 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.FrameLayout"))
# encoding: utf-8 # 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.FrameLayout" }

第三步,为子节点定义选择器。如果仅指定父节点选择器,可能仍有较多节点满足条件,这时可以定义子节点选择器来限制子节点必须满足的条件。例如索引为 0(16,0)的子节点类名为 android.widget.Button

339
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 val child0Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 def child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 AccessibilitySelector child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.Button".equals(o); } return false; } })
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 let child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(function (it) { return it === "android.widget.Button" })
-- 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 local child0Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` :className(function(it) return it == "android.widget.Button" end)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 $child0Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` ->className(function ($it) { return $it == "android.widget.Button"; })
# 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(lambda it: it == "android.widget.Button")
# encoding: utf-8 # 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` className { |className| className == "android.widget.Button" }.

并且该节点索引为 0 的子节点(17,0)的类名为 android.widget.TextView

// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 val child00Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 def child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 AccessibilitySelector child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.TextView".equals(o); } return false; } });
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 let child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(function (it) { return it === "android.widget.TextView" })
-- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 local child00Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" :className(function(it) return it == "android.widget.TextView" end)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 $child00Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" ->className(function ($it) { return $it == "android.widget.TextView"; });
# 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(lambda it: it == "android.widget.TextView"))
# encoding: utf-8 # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" className { |className| className == "android.widget.TextView" }

索引为 1 的节点(17,1)的类名为 android.widget.ImageView

// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 val child01Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 def child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" }
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 AccessibilitySelector child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.ImageView".equals(o); } return false; } });
// 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 let child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(function (it) { return it === "android.widget.ImageView" })
-- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 local child01Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" :className(function(it) return it == "android.widget.ImageView" end)
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 $child01Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" ->className(function ($it) { return $it == "android.widget.ImageView"; });
# 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(lambda it: it == "android.widget.ImageView"))
# encoding: utf-8 # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" className { |className| className == "android.widget.ImageView" }
340

一般情况下,设置了父节点及子节点选择器后,就能正常选择到节点了。若仍有多个节点满足条件,可继续设置兄弟节点的选择器,或更详细地设置父节点及子节点的选择器,也可设置更多子节点的选择器。在此例中,通过上述设置已足够。

找到节点后,我们就可以直接通过层次结构获取所需的节点信息:

341
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 val selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0)?.child(0)?.text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1)?.child(1)?.text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2)?.child(1)?.text()) }
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 def selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 AccessibilitySelector selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.LinearLayout".equals(o); } return false; } }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(0, -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()); }
// 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 let selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.LinearLayout" }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
-- 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 local selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.LinearLayout" end) -- 通过 parent 方法设置父节点的选择器 :parent(parentSelector) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(0, child0Selector) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(0, -1) -- 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node ~= nil then -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console:log("点赞", node:child(0):child(0):text()) -- 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console:log("评论", node:child(1):child(1):text()) -- 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console:log("收藏", node:child(2):child(1):text()) end
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 $selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.LinearLayout"; }) // 通过 parent 方法设置父节点的选择器 ->parent($parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(0, $child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne(0, -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if ($node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console->log(javaString("点赞"), $node->child(0)->child(0)->text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console->log(javaString("评论"), $node->child(1)->child(1)->text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console->log(javaString("收藏"), $node->child(2)->child(1)->text()); }
# 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.LinearLayout") # 通过 parent 方法设置父节点的选择器 .parent(parentSelector) # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector)) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node is not None): # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0).child(0).text()) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1).child(1).text()) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2).child(1).text())
# encoding: utf-8 # 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.LinearLayout" }. # 通过 parent 方法设置父节点的选择器 parent(parentSelector). # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(0, child0Selector) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text) end

完整的代码如下:

import com.m8test.script.GlobalVariables._accessibility import com.m8test.script.GlobalVariables._console // 节点(小红书视频界面右边的工具栏)父节点的选择器 val parentSelector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 val child00Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 val child01Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 val child0Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" } // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 val selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0)?.child(0)?.text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1)?.child(1)?.text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2)?.child(1)?.text()) }
// 节点(小红书视频界面右边的工具栏)父节点的选择器 def parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 def child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 def child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 def child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" } // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 def selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
import com.m8test.accessibility.api.AccessibilityNode; import com.m8test.accessibility.api.AccessibilitySelector; import kotlin.jvm.functions.Function1; import static com.m8test.script.GlobalVariables.$accessibility; import static com.m8test.script.GlobalVariables.$console; // 节点(小红书视频界面右边的工具栏)父节点的选择器 AccessibilitySelector parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.FrameLayout".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 AccessibilitySelector child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.TextView".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 AccessibilitySelector child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.ImageView".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 AccessibilitySelector child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.Button".equals(o); } return false; } }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector); // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 AccessibilitySelector selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.LinearLayout".equals(o); } return false; } }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(0, -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()); }
// 节点(小红书视频界面右边的工具栏)父节点的选择器 let parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.FrameLayout" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 let child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(function (it) { return it === "android.widget.TextView" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 let child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(function (it) { return it === "android.widget.ImageView" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 let child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(function (it) { return it === "android.widget.Button" }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 let selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.LinearLayout" }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(0, -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
-- 节点(小红书视频界面右边的工具栏)父节点的选择器 local parentSelector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.FrameLayout" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 local child00Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" :className(function(it) return it == "android.widget.TextView" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 local child01Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" :className(function(it) return it == "android.widget.ImageView" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 local child0Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` :className(function(it) return it == "android.widget.Button" end) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(0, child00Selector) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(1, child01Selector) -- 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 local selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.LinearLayout" end) -- 通过 parent 方法设置父节点的选择器 :parent(parentSelector) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(0, child0Selector) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(0, -1) -- 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node ~= nil then -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console:log("点赞", node:child(0):child(0):text()) -- 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console:log("评论", node:child(1):child(1):text()) -- 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console:log("收藏", node:child(2):child(1):text()) end
<?php /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)父节点的选择器 $parentSelector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.FrameLayout"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 $child00Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" ->className(function ($it) { return $it == "android.widget.TextView"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 $child01Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" ->className(function ($it) { return $it == "android.widget.ImageView"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 $child0Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` ->className(function ($it) { return $it == "android.widget.Button"; }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(0, $child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(1, $child01Selector); // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 $selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.LinearLayout"; }) // 通过 parent 方法设置父节点的选择器 ->parent($parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(0, $child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne(0, -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if ($node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console->log(javaString("点赞"), $node->child(0)->child(0)->text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console->log(javaString("评论"), $node->child(1)->child(1)->text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console->log(javaString("收藏"), $node->child(2)->child(1)->text()); }
from m8test_java.com.m8test.script.GlobalVariables import _accessibility from m8test_java.com.m8test.script.GlobalVariables import _console # 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.FrameLayout")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(lambda it: it == "android.widget.TextView")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(lambda it: it == "android.widget.ImageView")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(lambda it: it == "android.widget.Button") # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector)) # 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.LinearLayout") # 通过 parent 方法设置父节点的选择器 .parent(parentSelector) # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector)) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node is not None): # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0).child(0).text()) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1).child(1).text()) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2).child(1).text())
# encoding: utf-8 # 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.FrameLayout" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" className { |className| className == "android.widget.TextView" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" className { |className| className == "android.widget.ImageView" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` className { |className| className == "android.widget.Button" }. # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(0, child00Selector). # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(1, child01Selector) # 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.LinearLayout" }. # 通过 parent 方法设置父节点的选择器 parent(parentSelector). # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(0, child0Selector) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(0, -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text) end

结合虚拟屏幕

在安卓系统中,虚拟屏幕支持无障碍服务的使用,但这一功能需在安卓 11 及以上版本中实现。其操作方式十分简便:只需先创建或获取虚拟屏幕,再将该虚拟屏幕的 ID 作为参数,传递给无障碍服务相关类的对应方法即可。

import com.m8test.script.GlobalVariables.* import com.m8test.script.core.api.display.Display // 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 fun getDisplay(): Display { return _displays.getAll().firstOrNull() ?: _displays.create { // 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 } } // 获取一个虚拟屏幕 val display = getDisplay() // 节点(小红书视频界面右边的工具栏)父节点的选择器 val parentSelector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 val child00Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 val child01Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 val child0Selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" } // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 val selector = _accessibility!!.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 val node = selector.findOne(display.getId(), -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0)?.child(0)?.text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1)?.child(1)?.text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2)?.child(1)?.text()) }
import com.m8test.script.core.api.display.Display // 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 Display getDisplay() { def allDisplays = $displays.getAll() if (allDisplays.size() > 0) return allDisplays.get(0) // 创建虚拟屏幕, create 方法会返回一个 Display 对象 def display = $displays.create { // 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 } return display } // 获取一个虚拟屏幕 def display = getDisplay() // 节点(小红书视频界面右边的工具栏)父节点的选择器 def parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className { it == "android.widget.FrameLayout" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 def child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className { it == "android.widget.TextView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 def child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className { it == "android.widget.ImageView" } // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 def child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className { it == "android.widget.Button" } // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 def selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className { it == "android.widget.LinearLayout" } // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 def node = selector.findOne(display.getId(), -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
import com.m8test.accessibility.api.AccessibilityNode; import com.m8test.accessibility.api.AccessibilitySelector; import com.m8test.script.core.api.display.Display; import kotlin.jvm.functions.Function1; import java.util.List; import static com.m8test.script.GlobalVariables.*; private static Display getDisplay() { List<Display> allDisplays = $displays.getAll(); if (allDisplays.size() > 0) return (Display) allDisplays.get(0); // 创建虚拟屏幕, create 方法会返回一个 Display 对象 return $displays.create(new Function1() { @Override public Object invoke(Object o) { // 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 return null; } }); } // 获取一个虚拟屏幕 Display display = getDisplay(); // 节点(小红书视频界面右边的工具栏)父节点的选择器 AccessibilitySelector parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.FrameLayout".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 AccessibilitySelector child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.TextView".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 AccessibilitySelector child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.ImageView".equals(o); } return false; } }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 AccessibilitySelector child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.Button".equals(o); } return false; } }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector); // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 AccessibilitySelector selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(new Function1() { @Override public Object invoke(Object o) { if (o instanceof String) { return "android.widget.LinearLayout".equals(o); } return false; } }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 AccessibilityNode node = selector.findOne(display.getId(), -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()); }
/** * 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 * * @returns {Packages.com.m8test.script.core.api.display.Display} */ function getDisplay() { let allDisplays = $displays.getAll() if (allDisplays.size() > 0) return allDisplays.get(0) // 创建虚拟屏幕, create 方法会返回一个 Display 对象 return $displays.create(function (config) { // 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 }) } // 获取一个虚拟屏幕 let display = getDisplay() // 节点(小红书视频界面右边的工具栏)父节点的选择器 let parentSelector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.FrameLayout" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 let child00Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(function (it) { return it === "android.widget.TextView" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 let child01Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(function (it) { return it === "android.widget.ImageView" }) // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 let child0Selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(function (it) { return it === "android.widget.Button" }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector) // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 let selector = $accessibility.createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(function (it) { return it === "android.widget.LinearLayout" }) // 通过 parent 方法设置父节点的选择器 .parent(parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector) // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 let node = selector.findOne(display.getId(), -1) // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text()) // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text()) // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text()) }
-- 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 --- @return m8test_java.com.m8test.script.core.api.display.Display function getDisplay() local allDisplays = _displays:getAll() if not allDisplays:isEmpty() then return allDisplays:get(0) else return _displays:create(function(config) -- 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 end) end end -- 获取一个虚拟屏幕 local display = getDisplay() -- 节点(小红书视频界面右边的工具栏)父节点的选择器 local parentSelector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.FrameLayout" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 local child00Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" :className(function(it) return it == "android.widget.TextView" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 local child01Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" :className(function(it) return it == "android.widget.ImageView" end) -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 local child0Selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` :className(function(it) return it == "android.widget.Button" end) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(0, child00Selector) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(1, child01Selector) -- 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 local selector = _accessibility:createSelector() -- 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` :className(function(it) return it == "android.widget.LinearLayout" end) -- 通过 parent 方法设置父节点的选择器 :parent(parentSelector) -- 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 :child(0, child0Selector) -- 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 local node = selector:findOne(display:getId(), -1) -- 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node ~= nil then -- 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console:log("点赞", node:child(0):child(0):text()) -- 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console:log("评论", node:child(1):child(1):text()) -- 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console:log("收藏", node:child(2):child(1):text()) end
<?php /** @var m8test_java\com\m8test\script\core\api\display\Displays $displays */ global $displays; /** * 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 * @param \m8test_java\com\m8test\script\core\api\display\Displays $displays * @return \m8test_java\com\m8test\script\core\api\display\Display */ function getDisplay($displays) { $allDisplays = $displays->getAll(); if ($allDisplays->size() > 0) { return $allDisplays->get(0); } else { return $displays->create(function ($config) { // 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 }); } } // 获取一个虚拟屏幕 $display = getDisplay($displays); /** @var m8test_java\com\m8test\accessibility\api\Accessibility $accessibility */ global $accessibility; /** @var m8test_java\com\m8test\script\core\api\console\Console $console */ global $console; // 节点(小红书视频界面右边的工具栏)父节点的选择器 $parentSelector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.FrameLayout"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 $child00Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" ->className(function ($it) { return $it == "android.widget.TextView"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 $child01Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" ->className(function ($it) { return $it == "android.widget.ImageView"; }); // 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 $child0Selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` ->className(function ($it) { return $it == "android.widget.Button"; }) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(0, $child00Selector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(1, $child01Selector); // 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 $selector = $accessibility->createSelector() // 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` ->className(function ($it) { return $it == "android.widget.LinearLayout"; }) // 通过 parent 方法设置父节点的选择器 ->parent($parentSelector) // 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 ->child(0, $child0Selector); // 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 $node = $selector->findOne($display->getId(), -1); // 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if ($node != null) { // 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console->log(javaString("点赞"), $node->child(0)->child(0)->text()); // 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console->log(javaString("评论"), $node->child(1)->child(1)->text()); // 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console->log(javaString("收藏"), $node->child(2)->child(1)->text()); }
from m8test_java.com.m8test.script.GlobalVariables import _accessibility from m8test_java.com.m8test.script.GlobalVariables import _console from m8test_java.com.m8test.script.GlobalVariables import _displays # 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 def getDisplay(): allDisplays = _displays.getAll() if allDisplays.size() > 0: return allDisplays.get(0) else: return _displays.create(lambda config: # 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 config) # 获取一个虚拟屏幕 display = getDisplay() # 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.FrameLayout")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" .className(lambda it: it == "android.widget.TextView")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" .className(lambda it: it == "android.widget.ImageView")) # 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` .className(lambda it: it == "android.widget.Button") # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child00Selector) # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(1, child01Selector)) # 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = (_accessibility.createSelector() # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` .className(lambda it: it == "android.widget.LinearLayout") # 通过 parent 方法设置父节点的选择器 .parent(parentSelector) # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 .child(0, child0Selector)) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(display.getId(), -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if (node is not None): # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 _console.log("点赞", node.child(0).child(0).text()) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 _console.log("评论", node.child(1).child(1).text()) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 _console.log("收藏", node.child(2).child(1).text())
# encoding: utf-8 java_import 'com.m8test.script.core.api.display.Display' # encoding: utf-8 # 获取一个虚拟屏幕,如果已经存在的话则直接使用原有的,否则创建一个 # @return [Display] 已存在或者新创建的虚拟屏幕 def getDisplay allDisplays = $displays.getAll if allDisplays.size > 0 allDisplays.get(0) else $displays.create { |config| # 这里可以配置虚拟屏幕,推荐直接使用默认配置,如果出错的话再手动配置 } end end # 获取一个虚拟屏幕 display = getDisplay() # 节点(小红书视频界面右边的工具栏)父节点的选择器 parentSelector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)父节点的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.FrameLayout" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的选择器 child00Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的类名为 "android.widget.TextView" className { |className| className == "android.widget.TextView" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的选择器 child01Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为1的子节点的类名为 "android.widget.ImageView" className { |className| className == "android.widget.ImageView" } # 节点(小红书视频界面右边的工具栏)索引为0的子节点的选择器 child0Selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)索引为0的子节点的类名为 `android.widget.Button` className { |className| className == "android.widget.Button" }. # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(0, child00Selector). # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(1, child01Selector) # 定义一个选择器用于选择小红书视频界面右边工具栏,包含了`点赞`、`收藏`、`分享`等信息 selector = $accessibility.createSelector. # 节点(小红书视频界面右边的工具栏)的类名是`android.widget.LinearLayout` className { |className| className == "android.widget.LinearLayout" }. # 通过 parent 方法设置父节点的选择器 parent(parentSelector). # 通过 child 方法设置子节点的选择器, 第一个参数为索引,第二个参数为选择器 child(0, child0Selector) # 通过选择的 findOne 方法查找节点,如果没有找到则返回 null, 第一个参数为虚拟屏幕 id, android 11(api 30) 以下的手机会忽略该参数, 0 表示主屏幕(物理屏幕镜像),第二个参数为超时时间,单位为毫秒, 如果为负数, 查找一次直接返回, 无论有没有节点满足条件, 如果为0, 则表示一直查找知道找到满足条件的节点, 如果为大于0的数值, 那么就会在该时间内返回, 无论有没有节点满足条件。 node = selector.findOne(display.getId(), -1) # 获取点赞,评论以及收藏数量, 可以直接通过层次结构获取节点 if node # 节点(小红书视频界面右边的工具栏)索引为0的子节点的索引为0的子节点的为点赞数量 $console.log("点赞", node.child(0).child(0).text) # 节点(小红书视频界面右边的工具栏)索引为1的子节点的索引为1的子节点的为评论数量 $console.log("评论", node.child(1).child(1).text) # 节点(小红书视频界面右边的工具栏)索引为2的子节点的索引为1的子节点的为收藏数量 $console.log("收藏", node.child(2).child(1).text) end
Last modified: 08 August 2025