AAIS

概述

AAI 脚本(AAIS)是建立在 AAI 的 FindNode 之上的非常小的脚本,它具有非常简单的语法和几十个命令,AAIS 并不是复杂的 JS/REST API 的替代品,它适用于编写简单的测试或临时脚本。AAIS 解析器会在执行过程中将命令转换为 JavaScript(以及 FindNode 命令)。它具有与 JavaScript 不同的几个属性:

  • 由于它是基于 FindNode 构建的,它继承了 FindNode 的属性:
    • 基于对象,而不是基于坐标。
    • 与 FindNode 的查询语言完全兼容。
    • 支持在不同分辨率和尺寸的混合设备环境中运行脚本。
    • 使用 "寻找" 替代依赖设备的向上/向下翻页。"寻找" 会滚动直到找到节点。
  • 没有条件、循环或变量(仅有 JS 变量),不适合复杂脚本。
  • 任何失败或错误都会导致脚本停止。
  • 它被设计用于在多个设备上运行,用户可以选择设备集(1 到 50),它将为每个设备启动一个线程来运行脚本。
  • 支持 MDCC(多设备控制中心)和 WDM(Windows 桌面模式)。
  • 与 JavaScript 集成良好,JavaScript 代码块用 "{}" 括起来,并且可以在任何新行中使用。根据设备数目将被循环多次执行。
  • "print"、"get" 和 "sendAai" 的任何错误消息或输出将保存在日志文件中。JavaScript 的 log() 也可以保存到日志文件中。
  • "get" 和 "sendAai" 允许 JavaScript 获取输出(getOutput())。
  • AAIS 脚本可以执行 JavaScript 的模板字面量,允许通过 ${<expression>} 进行 JS 表达式或变量的替换。
  • "//" 是注释字符,"//" 之后的任何内容都将被忽略。
  • AAIS 支持每个命令多行。


多行支持

AAIS 支持基本的多行支持。有两种方法可以实现多行支持:

"<文本 1>\
<文本 2>"

这适用于所有双引号,在行尾处的 "\" 允许跨多行连接文本。例如:

{var a = 1, b = 2}
print "The sum of \
${a} and \
${b} is \
${a+b}"

将在日志文件中显示 "The sum of 1 and 2 is 3"。

{ <query/action>
<query/action> }

这主要适用于 "sendAai",复杂的命令可能需要多个参数来完成任务。不匹配的 "{}" 或 "[]" 将导致脚本错误。

{var tp = "all"}
// 7 lines command
sendAai {actions:[ 
 "getCount(+TP:\
${tp})",
 "getCount(+TP:more)",
 "getCount(+TP:basic)",
 "getCount(+TP:reduced)"
]}
{
 var output = getOutput();
 firstNum = output.list[0].count;
 lastNum = output.list[output.list.length -1].count;
 log("firstNum = " + firstNum);
 log("lastNum = " + lastNum);
}
print "From ${tp} template number of ${firstNum} reduced to ${lastNum}"

Log File:
2023-01-13 06:31:30  info     system           {name: 'samsung-SM-S908U1', object: 'device@1237418919', value: {count: 4, list: [{count: 162},{count: 69},{count: 64},{count: 63}]}, error: {}}
2023-01-13 06:31:30  info     system           firstNum = 162
2023-01-13 06:31:30  info     system           lastNum = 63
2023-01-13 06:31:30  info     system           From all template nodes number of 162 reduced to 63

注意

  • 确保大括号和方括号匹配,否则会出现错误。


AAIS 命令

点击/长按

在屏幕上点击或长按查询字符串或文本。如果未找到查询或文本,脚本将停止执行。有关查询语法,请参阅 FindNode 用户指南。如果在 "寻找" 或 "等待" 命令之后的 "点击" 没有参数,则会点击“查找 ” 命令的第一个匹配项。

用法:

点击/长按 <text|query>

示例:

点击 "T:About phone||OX:1"
长按 "Information" 
// 查找并点击 John
寻找 "John"
点击
等待 "Click for detail"
点击


启动/重启

启动或重启一个应用程序,重启会强制关闭应用程序并重新启动。如果找不到应用程序,脚本将停止执行。

用法:

启动/重启 <包名>
启动/重启 <应用程序名称>

示例:

启动 "com.raider.skype"
等待 "Favorites"
重启 "Skype"


等待

该命令会等待匹配项被找到或超时。如果超时,脚本将停止执行。如果未指定超时时间,默认为5000毫秒。有关查询语法,请参阅 FindNode 用户指南

用法:

等待 <text|query>
等待 <text|query>, <timeout in milliseconds>

示例:

等待 "Finish"
等待 "R:.icon_done", 20000


文本

向文本字段输入文本,文本字段通过位置或初始提示字符串进行定位,如果找不到文本字段,脚本将停止执行。为了准确地根据位置定位文本字段,文本字段将根据从左上到右下的位置进行排序。

用法:

文本 <text> 	         // 在第一个文本字段中输入文本
文本 <text>, <position>  // 位置从0开始 - 第一个文本字段,1 - 第二个文本字段,...
文本 <text>, <hint> 	 // 输入具有初始提示字符串的文本字段

示例:

文本 "Hello world"
文本 "Hello world", "Please input a message"
文本 "Hello world", 2


按键

按下一个键码(和可选的元状态)或键码名称,错误的键码名称将停止脚本的执行。

用法:

按键 <keycode name>
按键 KeyCode, <keycode>
按键 KeyCode, <keycode>, <meta state>

示例:

按键 Home
按键 KeyCode, 47, 1

请参考https://developer.android.com/reference/android/view/KeyEvent了解所有的键码名称。

以下是常用的键码名称(不区分大小写):

Enter
Back
Home
Back_space
Search
Power
Tab


寻找

根据屏幕上的方向滚动,直到找到匹配项,如果找不到,脚本将停止并显示错误。默认方向为“down”。

用法:

寻找 <text|query> [<direction>]

有四个方向:

  • "down":从当前位置向下搜索(默认值,如果未指定方向)。
  • "up":从当前位置向上搜索。
  • "fromTop":从应用程序顶部开始向下滚动。
  • "fromBottom":滚动到应用程序底部,然后向上搜索。

示例:

寻找 "${name}"
寻找 "T:OK||C:.Button"
click


执行

执行另一个 AAIS 或 JavaScript 脚本,如果脚本生成错误,则会停止执行。默认路径为 Documents\scripts 目录。如果扩展名为 ".js",则加载为 JavaScript;如果扩展名为 ".tst",则加载为 AAIS。通过 "执行" JavaScript 可以提供函数/常量以供 AAIS 集成,或执行无法在 AAIS 中完成的任务。

用法:

执行 <文件路径和文件名>

示例:

执行 "aais\\skype.tst"
执行 "C:\\aais\\skype.tst"
执行 "nestLib.js"


打印

将文本字符串打印到日志文件中。

用法:

打印 <文本>


延迟

临时暂停脚本执行指定的毫秒数。

用法:

延迟 <毫秒数> 

示例:

延迟 10000


选择

用于点击复选框,接受 true/false。"false" 将取消勾选,"true" 将设置勾选。

用法:

选择 <文本|查询> true|false

示例:

选择 "C:.Checkbox&&T:Milk"


进度

用于设置滑块的值,如 ".SeekBar" 的类名。在 FindNode 中显示为 "rangeInfo"(getNodes(RI)),它具有整数或浮点数类型,并具有最小值和最大值。确保值在范围内。

用法:

进度 <query> <整数或浮点数值>

示例:

进度 "T:Notifications&&OY:1&&OX:1", 1200


get

从 FindNode 获取信息。它有 4 种类型的 get(在需要时可能会添加更多),参数是可选的。返回值将保存到日志文件中,并可以从 JavaScript 的 "getOutput()" 中获取。

用法:

get <查询>, <类型>

类型:

  • "id":获取查询的 id/id。无需参数。
  • "text":获取与查询匹配的节点的文本信息。无需参数。
  • "description":获取与查询匹配的节点的描述信息。无需参数。
  • "node":根据可选参数获取匹配节点的信息。

示例:

exec "volumeLib.js"
get "T:Notifications&&OY:1&&OX:1", "node"
{
 var rangeInfo = getOutput().list[0].rangeInfo;
 var current = rangeInfo.current;
 var min = rangeInfo.min;
 var max = rangeInfo.max;
 var mid = (max-min)/4;
 if (current > mid*3) {
  tooLoud(getDevice(), current);
 } else if (current < mid) {
  tooSoft(getDevice(), current);
 }
}


sendAai

sendAai 使用 "device.sendAai" 向 FindNode 发送命令,返回值将保存到日志文件中,并可以从 JavaScript 的 "getOutput()" 中获取。任何失败(从 FindNode 接收到 null)都会导致脚本停止。目前,AAIS 不允许每个命令多行输入,下一个版本将支持多行命令。

用法:

sendAai {<查询或动作>}

示例:

sendAai {actions:[
"openAndroidSetting(application development settings)",
"scrollIntoView(T:Window animation scale)", 
"click", 
"click(+T:Animation scale .5x)", 
"sendKey(Back)", 
"sendKey(Back)"]}


与 JavaScript 的集成

AAIS 是一个解析器,它读取以 ".tst" 扩展名的 AAIS 脚本并生成用于执行的 JavaScript,与 JavaScript 的集成很简单,将 JavaScript 代码放在 "{}" 中。要在 AAIS 和 JavaScript 之间传递数据:

  • AAIS 的 "get" 和 "sendAai" 输出可以在 JavaScript 函数 getOutput() 中获取。
  • 所有 AAIS 的双引号中可以包含模板文字中的表达式 "…${<expression>}…",这允许从 JavaScript 将变量传递到 AAIS。

例如:

{ <JavaScript> 代码 }

{
<JavaScript 代码>
}

示例:

exec "phoneLib.js"
get "T:Android version&&OY:1", "text"
{ 
setVersion(getDevice(), getOutput().retval); 
}

假设 "phoneLib.js" 中定义了 "setVersion()" 函数。

由于 AAIS 脚本可以在多个设备上运行,所有的 JS 命令块将逐个设备执行多次。因此,在上面的示例中,如果选择了 20 个设备,将会执行 20 次 "setVersion"。"getDevice()" 将返回 20 个不同的设备。

您可以先执行(加载)一个 JS 库(带有常量或函数):

exec <library>.js

JS 代码块将与 "exec" 处于相同的上下文中,因此您可以方便地访问它们。

此外,AAIS 还提供了几个函数:

exec "phoneLib.js"
get "T:Model name&&OX:1", "text"
{ saveVar("modelName", getOutput().retval) }
get "T:Model number&&OX:1", "text"
{ saveVar("modelNumber", getOutput().retval) }
get "T:IMEI&&OX:1", "text"
{ 
    saveInfo(getDevice(), 
    loadVar("modelName"), 
    loadVar("modelNumber"), 
    getOutput().retval); 
}

saveVar 和 loadVar 与 getDevice() 相关,因此 loadVar 将始终返回相同设备上的 saveVar,彼此不会干扰。

如果您只想执行一次而不是每个设备都执行,请使用 "doOnce()"。

exec "runLib.js"
get "T:Run ID", "text"
{ 
	if (doOnce()) {
		saveDatabase(getOutput().retval); 
	}
}


函数

AAIS JavaScript 中内置了几个函数:

getDevice() → device

将返回当前设备。

getDevices() → 设备数组

将返回所有选定的设备。

saveVar(<name>, <value>)

将使用指定的名称存储变量,该变量存储在 getDevice() 的范围内。

loadVar(<name>) → <value>

将加载指定名称的变量并返回其值。该值仅在使用 saveVar() 与相同的 getDevice() 存储时可见。

saveGlobalVar(<name>, <value>)

将在由名称标识的全局范围中存储变量,任何设备都可以访问它。

loadGlobalVar(<name>) → <value>

将返回由名称标识的全局范围。

doOnce() → true|false

第一次运行时返回 true,随后的运行将返回 false。

getOutput() → 来自 FindNode 的输出

此函数仅适用于 "get" 和 "sendAai",JavaScript 代码块需要紧接在 "get" 或 "sendAai" 命令之后,对其他命令使用 "getOutput" 将生成错误并停止脚本执行。有关返回格式,请参阅日志文件中的内容。

getArg() → 字符串数组

Runner 允许用户将参数作为字符串数组传递给 JavaScript。结合变量替换,可以在运行时创建查询/操作。当支持命令行模式时,getArg() 将返回命令模式下的参数。Runner 中有一个按钮用于设置参数。

log(<message>)

此函数类似于 AAIS 的 "print" 函数,它将消息附加到现有的 Runner 日志文件中。

throw(<message>)

由于 AAIS 被转换为 JavaScript,您可以使用 throw(<message>) 来停止执行。错误消息将被记录并显示给用户。

"…${<expression>}…"

模板文字中的表达式允许任何双引号包含 ${…} 包围的 JavaScript 表达式。对于变量替换或简单的 JavaScript 表达式非常有用。



AAIS 示例

此示例打开特斯拉应用程序并检索汽车的 VIN 和里程:

exec "teslaLib.js"
open "Tesla"
find "T:VIN:"
get "T:VIN:&&OX:1", "text"
{ saveVar("vin", getOutput().retval) }
get "T:/[0-9,]+ miles/", "text"
{ saveMileage(new Date(), loadVar("vin"), getOutput().retval) }
print "Done"

根据索引号打开应用程序,可以从 JavaScript 传递 "app" 到 AAIS:

{
    var apps = ["Skype", "Whatsapp", "Telegram"];
    var arguments = getArg();
    var app = apps[0];
    if (arguments.length > 0) {
        var appNum;
        if(isNaN(appNum = parseInt(arguments[0]))) {
            throw "Need a number;"
        }
        if (appNum < 1 || appNum > apps.length) {
            throw "Option out of range";
        }
        app = apps[appNum-1];
    }
}
open "${app}"
print "${app} opened"


创建脚本

将脚本保存为带有 ".tst" 扩展名的文本文件,例如 skype.tst,或者您可以使用录制和回放功能在 AAIS 中录制脚本(需要选择对象模式)。



运行脚本

在 Runner 中运行 AAIS 脚本,结果将存储在 "Task" 中:

  • MDCC:
    • 打开 MDCC 窗口。
    • 通过缩略图设备选择设备或选择一个设备组。主设备将始终被选中。
    • 点击 "Runner"。
    • 选择一个或多个脚本,当复选框被点击时,它将显示执行顺序。
    • 点击运行按钮,它将在设备上运行脚本。错误将显示在 Runner 旁边的消息框中。点击 "Log" 可以访问日志。
  • WDM:
    • 在 WDM 设备窗口中,点击菜单 "Runner"。
    • 选择一个或多个脚本,当复选框被点击时,它将显示执行顺序。
    • 点击运行按钮,它将在设备上运行脚本。
    • 点击 Runner 上的任务窗口的第一个按钮。
    • 任务窗口将显示,可以查看进度和生成的日志文件。