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