FindNode 示例
Action 中的查询 - I
最基本的查询是“{}”或在 TC 中:
var output = device.sendAai({})
默认的“template”是“more”(除非“setConfig”改变它),默认的动作是“getIds”,同上:
var output = device.sendAai({query:"TP:more", action:"getIds"})
这将返回屏幕上的大多数节点,默认返回是节点 ID 列表(操作:“getIds”):
{count: 89, ids: ['80006cbe','7440','7bc2','7f83','8344','8705','8ac6','8e87','1f6e7',…]}
您可以执行以下操作:
{query:“CC:!=0”} 或 {query:”CC:>0}:非零子计数。
{query:”IT:>10000”}:接受大于10000的自定义输入类型值。
{query:"CC:!=0&&IT:>10000"}:查找子节点非零且输入类型大于 10,000 的节点。
{query:”TP:textInput&&IX:2”, action:”setText(Hello)”}:找到第三个文本字段并在文本字段中输入“Hello”。
{query:”T:Input text here”, action:”setText(Hello)”}:找到空文本字段有初始提示文本,搜索提示并输入“Hello”。
>> device.sendAai({query:"T:*REAL, \nSANTA CLARA*", action:"getText"})
{retval: '3367 EL CAMINO REAL,
SANTA CLARA, CA 95051'}
>> device.sendAai({actions:["scrollIntoView(T:ci:john)", "click"]})
Action 中的查询 - II
示例 1:在底部导航栏上查找节点:
>> device.sendAai({query:"TP:line,bottom,-1", action:"getText"})
{retval: ['Chats','Calls','Contacts','Today']}
通过使用偏移量 (OX)、索引 (IX) 或“T:”等查询,您几乎可以定位上述示例中的每个节点,点击“联系人”图标以下 3 个示例:
>> device.sendAai({query:"TP:line,bottom,-1&&IX:2", action:"click"})
{retval: true}
>> device.sendAai({query:"TP:line,bottom,-1&&T:Contacts&&OY:-1", action:"click"})
{retval: true}
>> device.sendAai({query:"TP:line,bottom,-1", action:"click(T:Contacts&&OY:-1)"})
{retval: true}
示例 2:从 About 电话中检索信息:
获取信息:
>> device.sendAai({query:"T:Model name&&OX:1", action:"getText"})
{retval: 'Galaxy S10+'}
或者,您可以使用 UiElement 类:
>> var obj = UiElement.findObject(device, "T:Model name&&OX:1")
UiElement: 3d012
>> obj.getText()
Galaxy S10+
示例 3:假设您想从 Yahoo Finance 获取股票代码的首页:
>> device.sendAai({query:"R:.ticker&&T:/[A-Z]{1,4}/", action:"getText"}).retval.forEach(
(p) => {print( p + ":" +
device.sendAai({action:"getDescription(OX:1&&T:" + p + ")"}).retval
)
}
)
TGT:164.76
T:16.76
AAPL:154.48
SBUX:92.14
TSLA:309.07
CSCO:43.30
示例 4:在 Skype 文本框中输入文本:
输入文字前:
文字输入后,需要点击按钮发送:
这可以通过在一个查询命令中使用来完成:
>> var input = "Hello";
>> device.sendAai({query:"TP:textInput", actions:[aaix("setText", input), "click(OX:2)"]});
{count: 2, list: [{retval: true},{retval: true}]}
aaix("setText", input) 将返回 'setText("Hello")',比 'setText("'+input+'")' 好得多,对多个参数有用。
以下功能查找人员,单击,发送消息并返回主页面。
function sendAai(device, obj) {
var retval = device.sendAai(obj);
if (retval == null) {
throw "Error on: " + JSON.stringify(obj) + ":" + lastError();
}
print("$ " + JSON.stringify(obj) + "\n" + JSON.stringify(retval));
return retval;
}
function sendSkype(device, name, text) {
sendAai(device, {actions:[
aaix("scrollIntoView", "T:" + name),
"click",
"newQuery(TP:textInput)",
aaix("setText", text),
"click(OX:2)",
"waitQuery(T:Type a message)",
"sendKey(Back)"
]})
}
sendSkype(device, "John", "I will get back to you");
示例 5:在第一个示例中,您可以使用“T:<text>”和偏移点击图标,一些应用程序不提供底部导航栏的标签:
由于这是在最后一行显示,我们可以使用“TP:line,bottom,-1”返回节点,使用“IX”从节点列表中定位单个节点。 例如:单击搜索图标:
device.sendAai({query:"TP:line,bottom,-1&&IX:2", action:"click"})
示例 6:在某个聊天窗口中,它显示了姓名(或电话号码),要获取它,请使用以下查询:
>> device.sendAai({query:"TP:line,top,1&&IX:1", action:"getText"})
{retval: (999)999-9999}
要返回,请单击左箭头:
>> device.sendAai({query:"TP:line,top,1&&IX:0", action:"click"})
{retval: true}
注意:新版本的“Messages”,“TP:line”不再起作用,您仍然可以检索第一行或最后一行信息,使用“VG”获取组信息,使用“RN”减少到感兴趣的节点。
第一行:
>> device.sendAai({query:"TP:reduced&&IX:0&&VG&&RN&&ST:x"})
{count: 6, ids: ['1669cf','168f59','16931a','1696db','169a9c','167151']}
获取名称:
>> device.sendAai({query:"TP:reduced&&VG&&RN&&ST:x&&IX:1", action:"getText"})
{retval: 'Daniel'}
>> device.sendAai({query:"TP:reduced&&VG&&RN&&ST:x", action:"getText(IX:1)"})
{retval: 'Daniel'}
>> device.sendAai({query:"TP:reduced&&VG&&RN&&ST:x", action:["addQuery(IX:1)", "getText"]})
{count: 2, list: [{count: 1},{retval: 'Daniel'}]}
最后一行:
>> device.sendAai({query:"TP:reduced&&IX:-1&&VG&&RN&&ST:x"})
{count: 5, ids: ['16227c','162dbf','15db29','15deea','16570a']}
想要输入文字点击发送按钮,使用2的偏移量定位发送按钮:
>> device.sendAai({query:"TP:textInput", action:["setText(Hello)", "click(OX:2)"]})
{count: 2, list: [{retval: true},{retval: true}]}
示例 7:轻松找到并单击。
要单击箭头,请使用:
>> device.sendAai({query:"T:Channels&&OX:1", action:"click"})
{retval: true}
Action 中的查询 - III
示例 1:考虑以下杂货店应用程序:
“scrollIntoView”会一直滚动,直到找到“*Orange*”,将“Valencia Oranges …”节点存入ML,VG会获得ViewGroup。 使用 UI Explorer 找出价格的资源 ID 和添加到购物车的“+”按钮。 “scrollIntoView”将使找到的节点完全可见,因为节点是水果的名称,完全可见但图像被遮挡。 添加一个“Viewgroup”将使其工作。
>> device.sendAai({actions:[
"scrollIntoView(T:*Orange*)",
"addQuery(VG)",
"showOnScreen",
"getText(R:.tv_price)",
"click(R:/.iv_edit_right|.tv_num/)"
]})
{count: 5, list: [{retval: true},{count: 13},{retval: true},{retval: '$6.99'},{retval: true}]}
版本 14 将允许“scrollIntoView”返回多个节点,更简单:
>> device.sendAai({actions:[
"scrollIntoView(T:*Oranges*&&VG)",
"getText(R:.tv_price)",
"click(R:.iv_edit_right)"
]})
{count: 5, list: [{retval: true},{count: 8},{retval: true},{retval: '$6.99'},{retval: true}]}
示例 2:使用“选中”来操作复选框。
要扩展到详细的报警信息,“\s”来匹配不同种类的空格:
>> device.sendAai({query:"T:/3:00\\sAM/&&OX:1", action:"click"})
{retval: true}
要将今天旁边的复选框从 true 更改为 false,请使用“checked”,仍然需要使用“3:00 AM”作为锚点,因为屏幕上可能还有其他带有“Today”的警报。
>> device.sendAai({query:"T:/3:00\\sAM/&&OY:1&&OX:1", actions:["getChecked", "setChecked(false)", "getChecked"]})
{count: 3, list: [{retval: true},{changedCount: 1},{retval: false}]}
下一个:
这里是星期天到星期六的循环闹钟,例如,它使用“D:Sunday”和“T:S”来表示第一个复选框。 使用 intersectX (TX) 获取所有选中的框。 在这个例子中,“C:.CheckBox”不是必需的,但作为例子很好:
>> device.sendAai({action:"getDescription(D:Sunday&&C:.CheckBox&&TX)"})
{retval: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']}
要选中所有复选框,setChecked 支持查询,它返回已更改的数量。
>> device.sendAai({query:"D:Sunday&&C:.CheckBox&&TX", action:"setChecked(true)"})
{changedCount: 7}
有几种方法可以关闭周日和周六:
>> device.sendAai({query:"D:/Sunday|Saturday/", action:"setChecked(false)"})
{changedCount: 2}
>> device.sendAai({query:"T:S", action:"setChecked(false)"})
{changedCount: 2}
To obtain the value of these checkboxes:
>> device.sendAai({query:"D:Sunday&&C:.CheckBox&&TX", action:"getChecked"})
{retval: [false,true,true,true,true,true,false]}
示例 3:OY 和 OX 的顺序很重要,以下是开发人员选项之一:
“禁用 adb 授权超时”右侧没有节点,因此在 X 上应用偏移量将变为空:
>> device.sendAai({query:"T:Disable adb authorization*&&OX:1&&OY:1"})
null
>> lastError()
Offset out of range
如果“OX”和“OY”的顺序颠倒,它将起作用,它在 X 之前在 Y 上应用偏移量,将得到正确的节点:
>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1"})
{count: 1, ids: ['25c8d4']}
>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1", action:"getChecked"})
{retval: false}
>> device.sendAai({query:"T:Disable adb authorization*&&OY:1&&OX:1", actions:["setChecked(true)", "getChecked"]})
{count: 2, list: [{changedCount: 1},{retval: true}]}
把所有东西放在一起,使用“openAndroidSetting”打开开发者选项:
>> device.sendAai({actions:[
"openAndroidSetting(APPLICATION_DEVELOPMENT_SETTINGS)",
"scrollIntoView(T:Disable adb authorization*)",
"addQuery(OY:1&&OX:1)",
"setChecked(true)",
"sendKey(Back)"
]})
{count: 5, list: [{retval: true},{retval: true},{count: 1},{changedCount: 1},{retval: true}]}
例4:将开发者选项“窗口动画比例”改为“2x”,需要用“+”改为T:*2x,因为是新窗口,需要新查询。
>> device.sendAai({actions:[
"openAndroidSetting(APPLICATION_DEVELOPMENT_SETTINGS)",
"scrollIntoView(T:Window animation scale)",
"click",
"click(+T:*2x)",
"sendKey(back)"
]})
{count: 5, list: [{retval: true},{retval: true},{retval: true},{retval: true},{retval: true}]}
[speedtest]
对于不可滚动的应用程序,“TP:line,bottom”将返回 null 但底部导航栏中的节点并不难:
请注意视频被图像边界包围。
您可以使用其中一个标签作为锚点(使用“ON:last”或“IX:-1”以确保查询适用于预期节点(最后一个文本),以防屏幕中的其他位置具有相同的文本:
>> device.sendAai({query:"T:Speed&&IX:-1&&TX", action:"getText"})
{retval: ['Speed',{},'Video','Status','Map','VPN']}
请注意有一个空节点,因为“TX”将返回没有文本/描述的图像节点。 添加匹配任何字符的帖子基本查询“XT”以将其删除:
>> device.sendAai({query:"T:Speed&&IX:-1&&TX&&XT:/./", action:"getText"})
{retval: ['Speed','Video','Status','Map','VPN']}
如果您不认识底部导航栏中的单词怎么办:
>> device.sendAai({query:"TP:anyText&&IX:-1&&TX&&XT:/./", action:"getText"})
{retval: ['Speed','Video','Status','Map','VPN']}
单击第二个元素(“视频”):
>> device.sendAai({query:"TP:anyText&&IX:-1&&TX&&XT:/./", action:"click(IX:1)"})
{retval: true}
>> device.sendAai({query:"TP:anyText&&IX:-1&&TX&&XT:/./&&IX:-1", action:"click"})
{retval: true}
获取图标很简单,在“TX”前加上“OY:-1”即可:
>> device.sendAai({query:"TP:anyText&&IX:-1&&OY:-1&&TX", action:"getNodes('C,R')"})
{count: 5, list: [{class: '.ImageView', id: '21637d', resourceId: '.navigation_bar_item_icon_view'},{class: '.ImageView', id: '217dc4', resourceId: '.navigation_bar_item_icon_view'},{class: '.ImageView', id: '21980b', resourceId: '.navigation_bar_item_icon_view'},{class: '.ImageView', id: '21b252', resourceId: '.navigation_bar_item_icon_view'},{class: '.ImageView', id: '21cc99', resourceId: '.navigation_bar_item_icon_view'}]}
如果只想单击 VPN 顶部的图标,请使用 OQ:
>> device.sendAai({action:"click(T:VPN&&IX:-1&&OY:-1)"})
{retval: true}
获得今日产量:
>> device.sendAai({query:"T:Production Today&&OY:1", actions:["getText", "getText(OX:1)"]})
{count: 2, list: [{retval: '38.3'},{retval: 'kWh'}]}
要获得太阳能发电量:
>> device.sendAai({query:"T:*Solar Power Now", action:"getText"})
{retval: '1.17 kW
Solar Power Now'}
>> var production = device.sendAai({query:"T:*Solar Power Now", action:"getText"}).retval.split("\n",1)
1.17 kW
获取 SolarEdge 太阳能产量的 JavaScript:
function sendAai(device, obj) {
var retval = device.sendAai(obj);
if (retval == null) {
throw "Error on: " + JSON.stringify(obj) + ":" + lastError();
}
print(">>" + JSON.stringify(obj) + "\n" + JSON.stringify(retval));
return retval;
}
function getSolarProduction(device) {
var retval = sendAai(device, {actions:[
"openApp(mySolarEdge)",
"waitQuery(T:Lifetime,20000)",
"newQuery(R:.pv_power_now)",
"getText",
"sendKey(Back)",
"sendKey(Back)"]});
var prodStr = retval.list[3].retval;
var groups = prodStr.match(/(\d+(\.\d+)?) (W|kW)/);
if (groups == null) {
throw "Cannot find pattern in mySolarEdge";
}
var unit = groups.splice(-1);
var number = groups[1];
if (unit == "kW") {
number = number * 1000;
} else if (unit != "W") {
throw "Unknown unit: " + unit;
}
return number;
}
>> getSolarProduction(device)
>> {"actions":["openApp(mySolarEdge)","waitQuery(T:Lifetime,20000)","newQuery(R:.pv_power_now)","getText","sendKey(Back)","sendKey(Back)"]}
{"count":6,"list":[{"retval":true},{"retval":true},{"count":1},{"retval":"1.17 kW\nSolar Power Now"},{"retval":false},{"retval":true}]}
1170