diff --git a/app/src/main/assets/docs/all.html b/app/src/main/assets/docs/all.html index daefb94c..16913ed1 100644 --- a/app/src/main/assets/docs/all.html +++ b/app/src/main/assets/docs/all.html @@ -2,7 +2,7 @@ - Index | Auto.js 3.0.0 文档 + App | Auto.js 3.0.0 文档 @@ -25,24 +25,27 @@
@@ -67,28 +70,3699 @@

目录

- + +
-

@include overview -@include qa -@include globals -@include widgets-based-automation -@include coordinates-based-automation -@include images -@include console -@include events -@include timers -@include shell -@include ui -@include files -@include app -@include http -@include dialogs -@include engines -@include modules -@include work-with-java

+ + + + + +

App#

+

app模块提供一系列函数,用于与其他应用的交互。例如打开文件、拍照、发送邮件等。

+

同时提供了方便的基础函数startActivity和sendBroadcast,用他们可完成app模块没有内置的和其他应用的交互。

+

app.viewFile(path)#

+
+

用其他应用查看文件。

+

app.editFile(path)#

+
+

用其他应用编辑文件。

+

app.uninstall(packageName)#

+
+

卸载应用。

+

app.openUrl(url)#

+
+

用浏览器打开网站url。

+

app.takePhoto(path)#

+
+

调用相机应用拍照,完成后保存到路径path。

+

app.sendEmail(options)#

+
+

根据选项options调用邮箱应用发送邮件。这些选项均是可选的。

+

app.intent(intent)#

+
+

返回用intent对象构造的android.content.Intent对象。

+

例如:

+
var i = app.intent({
+    action: "android.intent.action.VIEW",
+    type: "text/plain",
+    data: "file:///sdcard/1.txt",
+});
+

如果你看了一脸懵逼,请百度安卓Intent

+

app.startActivity(intent)#

+
+

相当于context.startActivity(intent)。

+

app.sendBroadcast(intent)#

+
+

相当于context.sendBroadcast(intent)。

+ + +

Console#

+
Stability: 2 - Stable

控制台模块提供了一个和Web浏览器中相似的用于调试的控制台。用于输出一些调试信息、中间结果等。 +console模块中的一些函数也可以直接作为全局函数使用,例如log, print等。

+

console.show()#

+

显示控制台。这会显示一个控制台的悬浮窗(需要悬浮窗权限)。

+

console.hide()#

+

隐藏控制台悬浮窗。

+

console.clear()#

+

清空控制台。

+

console.log([data][, ...args])#

+
+

打印到控制台,并带上换行符。 可以传入多个参数,第一个参数作为主要信息,其他参数作为类似于 printf(3) 中的代替值(参数都会传给 util.format())。

+
const count = 5;
+console.log('count: %d', count);
+// 打印: count: 5 到 stdout
+console.log('count:', count);
+// 打印: count: 5 到 stdout
+

详见 util.format()。

+

console.verbose([data][, ...args])#

+
+

与console.log类似,但输出结果以灰色字体显示。输出优先级低于log,用于输出观察性质的信息。

+

console.info([data][, ...args])#

+
+

与console.log类似,但输出结果以绿色字体显示。输出优先级高于log, 用于输出重要信息。

+

console.warn([data][, ...args])#

+
+

与console.log类似,但输出结果以蓝色字体显示。输出优先级高于info, 用于输出警告信息。

+

console.error([data][, ...args])#

+
+

与console.log类似,但输出结果以红色字体显示。输出优先级高于warn, 用于输出错误信息。

+

console.assert(value, message)#

+
+

断言。如果value为false则输出错误信息message并停止脚本运行。

+

console.input(data[, ...args])#

+
+

与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串用eval计算后返回。

+

部分机型可能会有控制台不显示输入框的情况,属于bug。

+

例如:

+
var n = console.input("请输入一个数字:"); 
+//输入123之后:
+toast(n + 1);
+//显示124
+

console.rawInput(data[, ...args])#

+
+

与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串直接返回。

+

部分机型可能会有控制台不显示输入框的情况,属于bug。

+

例如:

+
var n = console.input("请输入一个数字:"); 
+//输入123之后:
+toast(n + 1);
+//显示1231
+

console.setSize(w, h)#

+
+

设置控制台的大小,单位像素。

+

console.setPosition(x, y)#

+
+

设置控制台的位置,单位像素。

+

print(text)#

+
+

在控制台中输出文本text。不会自动换行。

+ + +

Android7.0以上点按与手势模拟#

+
Stability: 2 - Stable

本章节介绍了一些适用于Android7.0以上、不需要root权限、依赖于无障碍服务的点按与手势模拟的全局函数。

+

注意以下命令只有Android7.0及以上才有效

+

click(x, y)#

+
+

模拟点击坐标(x, y),并返回是否点击成功。只有在点击执行完成后脚本才继续执行。

+

一般而言,只有点击过程(大约150毫秒)中被其他事件中断(例如用户自行点击)才会点击失败。

+

使用该函数模拟连续点击时可能有点击速度过慢的问题,这时可以用[press][]函数代替。

+
+

可以在开发者选项中启用指针位置来查看坐标

+
+

longClick(x, y)#

+
+

模拟长按坐标(x, y), 并 返回是否成功。只有在长按执行完成(大约600毫秒)时脚本才会继续执行。

+

一般而言,只有长按过程中被其他事件中断(例如用户自行点击)才会长按失败。

+

press(x, y, duration)#

+
+

模拟按住坐标(x, y), 并返回是否成功。只有按住操作执行完成时脚本才会继续执行。

+

如果按住时间过短,那么会被系统认为是点击;如果时长超过500毫秒,则认为是长按。

+

一般而言,只有按住过程中被其他事件中断才会操作失败。

+

swipe(x1, y1, x2, y2, duration)#

+
+

模拟从坐标(x1, y1)滑动到坐标(x2, y2),并返回是否成功。只有滑动操作执行完成时脚本才会继续执行。

+

一般而言,只有滑动过程中被其他事件中断才会滑动失败。

+

gesture(duration, [x1, y1], [x2, y2], ...)#

+
+

模拟手势操作。例如gesture(1000, [0, 0], [500, 500], [500, 1000])为模拟一个从(0, 0)到(500, 500)到(500, 100)的手势操作,时长为2秒。

+

gestures([delay1, duration1, [x1, y1], [x2, y2], ...], [delay2, duration2, [x3, y3], [x4, y4], ...], ...)#

+

同时模拟多个手势。每个手势的参数为[delay, duration, 坐标], delay为延迟多久(毫秒)才执行该手势;duration为手势执行时长;坐标为手势经过的点的坐标。其中delay参数可以省略,默认为0。

+

例如手指捏合:

+
gestures([0, 500, [800, 300], [500, 1000]],
+         [0, 500, [300, 1500], [500, 1000]]);
+

setScreenMetrics(width, height)#

+
+

设置脚本坐标点击所适合的屏幕宽高。如果脚本运行时,屏幕宽度不一致会自动放缩坐标。

+

例如在1920*1080的设备中,某个操作的代码为

+
setScreenMetrics(1080, 1920);
+click(800, 200);
+longClick(300, 500);
+

那么在其他设备上AutoJs会自动放缩坐标以便脚本仍然有效。

+

RootAutomator#

+
Stability: 2 - Stable

RootAutomator是一个使用root权限来模拟触摸的对象,用它可以完成触摸与多点触摸,并且这些动作的执行没有延迟。

+

注意以下命令需要root权限

+
var ra = new RootAutomator();
+

RootAutomator.tap(x, y[, id])#

+
+

点击位置(x, y)。其中id是一个整数值,用于区分多点触摸,不同的id表示不同的"手指",例如:

+
var ra = new RootAutomator();
+//让"手指1"点击位置(100, 100)
+ra.tap(100, 100, 1);
+//让"手指2"点击位置(200, 200);
+ra.tap(200, 200, 2);
+ra.exit();
+

如果不需要多点触摸,则不需要id这个参数。 +多点触摸通常用于手势或游戏操作,例如模拟双指捏合、双指上滑等。

+

RootAutomator.swipe(x1, x2, y1, y2[, duration, id])#

+
+

模拟一次从(x1, y1)到(x2, y2)的时间为duration毫秒的滑动。

+

RootAutomator.press(x, y, duration[, id])#

+
+

模拟按下位置(x, y),时长为duration毫秒。

+

使用该函数模拟连续点击时可能有点击速度过慢的问题,这时可以用[RootAutomator.press][]函数代替。

+

RootAutomator.longPress(x, y[\, id])#

+
+

模拟长按位置(x, y)。

+

以上为简单模拟触摸操作的函数。如果要模拟一些复杂的手势,需要更底层的函数。

+

RootAutomator.touchDown(x, y[\, id])#

+
+

模拟手指按下位置(x, y)。

+

RootAutomator.touchMove(x, y[\, id])#

+
+

模拟移动手指到位置(x, y)。

+

RootAutomator.touchUp([id])#

+
+

模拟手指弹起。

+

使用root权限点击和滑动的简单命令#

+
Stability: 1 - Experimental

注意:本章节的函数在后续版本很可能有改动!请勿过分依赖本章节函数的副作用。推荐使用[RootAutomator][]代替本章节的触摸函数。

+

以下函数均需要root权限,可以实现任意位置的点击、滑动等。

+ +

例如:

+
Tap(100, 100);
+sleep(500);
+

注意,动作的执行可能无法被停止,例如:

+
for(var i = 0; i < 100; i++){
+  Tap(100, 100);
+}
+

这段代码执行后可能会出现在任务管理中停止脚本后点击仍然继续的情况。 +因此,强烈建议在每个动作后加上延时:

+
for(var i = 0; i < 100; i++){
+  Tap(100, 100);
+  sleep(500);
+}
+

Tap(x, y)#

+
+

点击位置(x, y), 您可以通过"开发者选项"开启指针位置来确定点击坐标。

+

Swipe(x1, y1, x2, y2, [duration])#

+
+

滑动。从(x1, y1)位置滑动到(x2, y2)位置。 +

+ +

Device#

+
Stability: 2 - Stable

device模块提供了与设备有关的信息与操作,例如获取设备宽高,内存使用率,IMEI,调整设备亮度、音量等。

+

此模块的部分函数,例如调整音量,需要"修改系统设置"的权限。如果没有该权限,会抛出异常并跳转到权限设置界面。

+

device.width#

+
+

设备宽度。例如1080。

+

device.height#

+
+

设备高度。例如1920。

+

device.buildId#

+
+

Either a changelist number, or a label like "M4-rc20".

+

修订版本号,或者诸如"M4-rc20"的标识。

+

device.broad#

+
+

The name of the underlying board, like "goldfish".

+

设备的主板(?)型号。

+

device.brand#

+
+

The consumer-visible brand with which the product/hardware will be associated, if any.

+

与产品或硬件相关的厂商品牌,如"Xiaomi", "Huawei"等。

+

device.device#

+
+

The name of the industrial design.

+

设备在工业设计中的名称。

+

deivce.model#

+
+

The end-user-visible name for the end product.

+

设备型号。

+

device.product#

+
+

The name of the overall product.

+

整个产品的名称。

+

device.bootloader#

+
+

The system bootloader version number.

+

设备Bootloader的版本。

+

device.hardware#

+
+

The name of the hardware (from the kernel command line or /proc).

+

设备的硬件名称(来自内核命令行或者/proc)。

+

device.fingerprint#

+
+

A string that uniquely identifies this build. Do not attempt to parse this value.

+

构建(build)的唯一标识码。

+

device.serial#

+
+

A hardware serial number, if available. Alphanumeric only, case-insensitive.

+

硬件序列号。

+

device.sdkInt#

+
+

The user-visible SDK version of the framework; its possible values are defined in Build.VERSION_CODES.

+

安卓系统API版本。例如安卓4.4的sdkInt为19。

+

device.incremental#

+
+

The internal value used by the underlying source control to represent this build. E.g., a perforce changelist number or a git hash.

+

device.release#

+
+

The user-visible version string. E.g., "1.0" or "3.4b5".

+

Android系统版本号。例如"5.0", "7.1.1"。

+

device.baseOS#

+
+

The base OS build the product is based on.

+

device.securityPatch#

+
+

The user-visible security patch level.

+

安全补丁程序级别。

+

device.codename#

+
+

The current development codename, or the string "REL" if this is a release build.

+

开发代号,例如发行版是"REL"。

+

device.getIMEI()#

+
+

返回设备的IMEI.

+

device.getAndroidId()#

+
+

返回设备的Android ID。

+

Android ID为一个用16进制字符串表示的64位整数,在设备第一次使用时随机生成,之后不会更改,除非恢复出厂设置。

+

device.getMacAddress()#

+
+

返回设备的Mac地址。该函数需要在有WLAN连接的情况下才能获取,否则会返回null。

+

可能的后续修改:未来可能增加有root权限的情况下通过root权限获取,从而在没有WLAN连接的情况下也能返回正确的Mac地址,因此请勿使用此函数判断WLAN连接。

+

device.getBrightness()#

+
+

返回当前的(手动)亮度。范围为0~255。

+

device.getBrightnessMode()#

+
+

返回当前亮度模式,0为手动亮度,1为自动亮度。

+

device.setBrightness(b)#

+
+

设置当前手动亮度。如果当前是自动亮度模式,该函数不会影响屏幕的亮度。

+

此函数需要"修改系统设置"的权限。如果没有该权限,会抛出SecurityException并跳转到权限设置界面。

+

device.setBrightnessMode(mode)#

+
+

设置当前亮度模式。

+

此函数需要"修改系统设置"的权限。如果没有该权限,会抛出SecurityException并跳转到权限设置界面。

+

device.getMusicVolume()#

+
+

返回当前媒体音量。

+

device.getNotificationVolume()#

+
+

返回当前通知音量。

+

device.getAlarmVolume()#

+
+

返回当前闹钟音量。

+

device.getMusicMaxVolume()#

+
+

返回媒体音量的最大值。

+

device.getNotificationMaxVolume()#

+
+

返回通知音量的最大值。

+

device.getAlarmMaxVolume()#

+
+

返回闹钟音量的最大值。

+

device.setMusicVolume(volume)#

+
+

设置当前媒体音量。

+

此函数需要"修改系统设置"的权限。如果没有该权限,会抛出SecurityException并跳转到权限设置界面。

+

device.setNotificationVolume(volume)#

+
+

设置当前通知音量。

+

此函数需要"修改系统设置"的权限。如果没有该权限,会抛出SecurityException并跳转到权限设置界面。

+

device.setAlarmVolume(volume)#

+
+

设置当前闹钟音量。

+

此函数需要"修改系统设置"的权限。如果没有该权限,会抛出SecurityException并跳转到权限设置界面。

+

device.getBattery()#

+
+

返回当前电量百分比。

+

device.isCharging()#

+
+

返回设备是否正在充电。

+

device.getTotalMem()#

+
+

返回设备内存总量,单位字节(B)。1MB = 1024 * 1024B。

+

device.getAvailMem()#

+
+

返回设备当前可用的内存,单位字节(B)。

+ + +

Dialogs#

+
Stability: 2 - Stable

dialogs 模块允许用户通过对话框与脚本进行交互。

+

dialogs.rawInput(title[, default])#

+
+

显示一个包含输入框的对话框。如果指定了 default ,那么对话框显示时输入框的内容就为该值。

+

该函数也可通过 rawInput(title[, default])prompt(title[, default]) 或者 dialogs.prompt(title[, default]) 来调用。调用时脚本将阻塞直至对话框被关闭。如果用户输入内容并点击确定,函数将返回输入的内容;否则返回 null

+

dialogs.input(title[, default])#

+

等效于 eval(dialogs.rawInput(title, default))

+

dialogs.prompt(title[, default])#

+

见 dialogs.rawInput

+

dialogs.alert(title[, content])#

+
+

显示一个只包含“确定”按钮的提示对话框。

+

该函数也可通过 alert(title[, content]) 来调用。调用时脚本将阻塞直至对话框被关闭。该函数无返回值。

+

dialogs.confirm(title[, content])#

+
+

显示一个包含“确定”和“取消”按钮的提示对话框。

+

该函数也可通过 confirm(title[, content]) 来调用。调用时脚本将阻塞直至对话框被关闭。如果用户点击“确定”则返回 true ,否则返回 false

+

dialogs.select(title, items)#

+
+

显示一个带有选项列表的对话框。

+

该函数也可通过 dialogs.select(title, ...items) 来调用。
例如: dialogs.select("标题", ["A", "B", "C"]) 可以用 dialogs.select("标题", "A", "B", "C") 替代。

+

调用时脚本将阻塞直至对话框被关闭。如果用户点击了对话框中的某个选项,该函数会返回该选项的位置(选中第一个选项返回0,第二个选项返回1,以此类推),否则返回-1。

+

dialogs.singleChoice(title, items[, index])#

+
+

显示一个带有单选框选项列表的对话框。

+

调用时脚本将阻塞直至对话框被关闭。如果用户选中了对话框中的某个选项并点击“确定”,该函数会返回该选项的位置(选中第一个选项返回0,第二个选项返回1,以此类推),否则返回-1。

+

dialogs.multiChoice(title, items[, indexes])#

+
+

显示一个带有多选框选项列表的对话框。

+

调用时脚本将阻塞直至对话框被关闭。如果用户点击“确定”按钮,该函数会返回所有已选选项的位置组成的数组,否则返回空数组。 +

+ +

Engines#

+
Stability: 2 - Stable

engines模块包含了一些与脚本引擎有关的函数,包括运行其他脚本,关闭脚本等。

+

engines.execScript(name, script[, config])#

+
+

在新线程中运行脚本script。返回一个ScriptExectuion对象。

+

engines.execScriptFile(path[, config])#

+
+

在新线程中运行脚本文件path。返回一个ScriptExecution对象。

+

engines.execAutoFile(path[, config])#

+
+

在新线程中运行录制文件path。返回一个ScriptExecution对象。

+

engines.stopAll()#

+

停止所有正在运行的脚本。包括当前脚本自身。

+

engines.stopAllAndToast()#

+

停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。

+

engines.myEngine()#

+

返回当前脚本的脚本引擎对象(ScriptEngine)

+

ScriptExecution#

+

执行脚本时返回的对象,可以通过他获取执行的引擎、配置、源码等。

+

ScriptExecution.getEngine()#

+

返回执行该脚本的脚本引擎对象(ScriptEngine)

+

ScriptExecution.getConfig()#

+

返回该脚本的运行配置(ScriptConfig)

+

ScriptExecution.getSource()#

+

返回该脚本的源码对象(ScriptSource)

+

ScriptEngine#

+

ScriptEngine.forceStop()#

+

停止脚本引擎的执行。

+

ScriptEngine.getTag(tagName)#

+
+

返回对应于tagName的附加在该脚本引擎上的额外信息。tagName包括:

+ +

停止脚本引擎的执行。

+

ScriptConfig#

+

脚本执行时的配置。

+

delay#

+

延迟执行的毫秒数

+

interval#

+

循环运行时两次运行之间的时间间隔

+

loopTimes#

+

循环运行次数

+

getPath()#

+

返回一个字符串数组表示脚本运行时模块寻找的路径。

+

ScriptSource#

+

脚本执行时的源码对象。可以是字符串源码、文件源码等。

+

如果该源码是文件脚本,则可以通过toString()得到该文件的路径。

+

getName()#

+

返回该源码的名称。

+

getEngineName()#

+

返回执行该源码的脚本引擎的名称。

+ + +

Events#

+
Stability: 2 - Stable

events模块提供了监听手机通知、按键、触摸的接口。您可以用他配合自动操作函数完成自动化工作。

+

events本身是一个EventEmiiter, 但内置了一些事件、包括按键事件、通知事件、Toast事件等。

+

events.emitter()#

+

返回一个新的[EventEmitter][]。这个EventEmitter没有内置任何事件。

+

events.observeKey()#

+

启用按键监听,例如音量键、Home键。此函数使用无障碍服务实现,因此此函数会调用auto()确保无障碍服务启用。

+

只有这个函数成功执行后, [onKeyDown][], [onKeyUp][]等按键事件的监听才有效。

+

该函数在安卓4.3以上才能使用。

+

events.onKeyDown(keyName, listener)#

+
+

注册一个按键监听函数,当有keyName对应的按键被按下会调用该函数。可用的按键名称参见[Keys][]。

+

例如:

+
//启用按键监听
+events.observeKey();
+//监听音量上键按下
+events.onKeyDown("volume_up", function(event){
+    toast("音量上键被按下了");
+});
+//监听菜单键按下
+events.onKeyDown("menu", function(event){
+    toast("菜单键被按下了");
+    exit();
+});
+

events.onKeyUp(keyName, listener)#

+
+

注册一个按键监听函数,当有keyName对应的按键弹起会调用该函数。可用的按键名称参见Keys

+

一次完整的按键动作包括了按键按下和弹起。按下事件会在手指按下一个按键的"瞬间"触发, 弹起事件则在手指放开这个按键时触发。

+

例如:

+
//启用按键监听
+events.observeKey();
+//监听音量下键弹起
+events.onKeyDown("volume_down", function(event){
+    toast("音量上键弹起");
+});
+//监听Home键弹起
+events.onKeyDown("home", function(event){
+    toast("Home键弹起");
+    exit();
+});
+

events.onceKeyDown(keyName, listener)#

+
+

注册一个按键监听函数,当有keyName对应的按键被按下时会调用该函数,之后会注销该按键监听器。

+

也就是listener只有在onceKeyDown调用后的第一次按键事件被调用一次。

+

events.onceKeyUp(keyName, listener)#

+
+

注册一个按键监听函数,当有keyName对应的按键弹起时会调用该函数,之后会注销该按键监听器。

+

也就是listener只有在onceKeyUp调用后的第一次按键事件被调用一次。

+

events.removeAllKeyDownListeners(keyName)#

+
+

删除该按键的KeyDown(按下)事件的所有监听。

+

events.removeAllKeyUpListeners(keyName)#

+
+

删除该按键的KeyUp(弹起)事件的所有监听。

+

events.observeTouch()#

+

启用屏幕触摸监听。(需要root权限)

+

只有这个函数被成功执行后, 触摸事件的监听才有效。

+

没有root权限调用该函数则什么也不会发生。(注意: 这个行为未来可能会更改为抛出异常)

+

events.setTouchEventTimeout(timeout)#

+
+

设置两个触摸事件分发的最小时间间隔。

+

例如间隔为10毫秒的话,前一个触摸事件发生并被注册的监听器处理后,至少要过10毫秒才能分发和处理下一个触摸事件,这10毫秒之间的触摸将会被忽略。

+

建议在满足需要的情况下尽量提高这个间隔。一个简单滑动动作可能会连续触发上百个触摸事件,如果timeout设置过低可能造成事件拥堵。强烈建议不要设置timeout为0。

+

events.getTouchEventTimeout()#

+

返回触摸事件的最小时间间隔。

+

events.onTouch(listener)#

+
+

注册一个触摸监听函数。相当于on("touch", listener)

+

例如:

+
//启用触摸监听
+events.observeTouch();
+//注册触摸监听器
+events.onTouch(function(p){
+    //触摸事件发生时, 打印出触摸的点的坐标
+    log(p.x + ", " + p.y);
+});
+

events.removeAllTouchListeners()#

+

删除所有事件监听函数。

+

事件: 'key'#

+
+

当有按键被按下或弹起时会触发该事件。 +例如:

+
auto();
+events.observeKey();
+events.on("key", function(keyCode, event){
+    //处理按键事件
+});
+

其中监听器的参数KeyCode包括:

+ +

事件: 'key_down'#

+
+

当有按键被按下时会触发该事件。

+
auto();
+events.observeKey();
+events.on("key_down", function(keyCode, event){
+    //处理按键按下事件
+});
+

事件: 'key_up'#

+
+

当有按键弹起时会触发该事件。

+
auto();
+events.observeKey();
+events.on("key_up", function(keyCode, event){
+    //处理按键弹起事件
+});
+

事件: 'exit`#

+

当脚本正常或者异常退出时会触发该事件。事件处理中如果有异常抛出,则立即中止exit事件的处理(即使exit事件有多个处理函数)并在控制台和日志中打印该异常。

+

一个脚本停止运行时,会关闭该脚本的所有悬浮窗,触发exit事件,之后再回收资源。如果exit事件的处理中有死循环,则后续资源无法得到及时回收。 +此时脚本会停留在任务列表,如果在任务列表中关闭,则会强制结束exit事件的处理并回收后续资源。

+
log("开始运行")
+events.on("exit", function(){
+    log("结束运行");
+});
+log("即将结束运行");
+

obverseNotification()#

+

开启通知(包括Toast)监听。

+

通知与Toast监听依赖于无障碍服务,因此这个函数会调用auto()来确保无障碍服务启用。

+

例如:

+
events.obverseNotification();
+events.onNotification(function(notification){
+    log(notification.getText());
+});
+events.onToast(function(toast){
+    log(toast.getText());
+});
+

事件: 'toast'#

+
+

当有应用发出toast(气泡消息)时会触发该事件。但Auto.js软件本身的toast除外。 +例如,要记录发出所有toast的应用:

+
events.obverseNotification();
+events.onToast(function(toast){
+    log("Toast内容: " + toast.getText() + " 包名: " + toast.getPackageName());
+});
+

事件: 'notification'#

+
+

当有应用发出通知时会触发该事件。

+

例如:

+
events.observeNotification();
+events.on("notification", function(notification){
+    log(notification);
+});
+

注意: 这是一个实验性功能。实测只有某些情况下的通知才能被正确捕捉。

+

EventEmitter#

+
Stability: 2 - Stable

EventEmitter.defaultMaxListeners#

+

每个事件默认可以注册最多 10 个监听器。 单个 EventEmitter 实例的限制可以使用 emitter.setMaxListeners(n) 方法改变。 所有 EventEmitter 实例的默认值可以使用 EventEmitter.defaultMaxListeners 属性改变。

+

设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有 EventEmitter 实例,包括之前创建的。 因而,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners。

+

注意,与Node.js不同,这是一个硬性限制。 EventEmitter 实例不允许添加更多的监听器,监听器超过最大数量时会抛出TooManyListenersException。

+
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
+emitter.once('event', () => {
+  // 做些操作
+  emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
+});
+

EventEmitter.addListener(eventName, listener)#

+
+

emitter.on(eventName, listener) 的别名。

+

EventEmitter.emit(eventName[, ...args])#

+
+

按监听器的注册顺序,同步地调用每个注册到名为 eventName 事件的监听器,并传入提供的参数。

+

如果事件有监听器,则返回 true ,否则返回 false。

+

EventEmitter.eventNames()#

+

返回一个列出触发器已注册监听器的事件的数组。 数组中的值为字符串或符号。

+
const myEE = events.emitter();
+myEE.on('foo', () => {});
+myEE.on('bar', () => {});
+
+const sym = Symbol('symbol');
+myEE.on(sym, () => {});
+
+console.log(myEE.eventNames());
+// 打印: [ 'foo', 'bar', Symbol(symbol) ]
+

EventEmitter.getMaxListeners()#

+

返回 EventEmitter 当前的最大监听器限制值,该值可以通过 emitter.setMaxListeners(n) 设置或默认为 EventEmitter.defaultMaxListeners。

+

EventEmitter.listenerCount(eventName)#

+
+

返回正在监听名为 eventName 的事件的监听器的数量。

+

EventEmitter.listeners(eventName)#

+
+

返回名为 eventName 的事件的监听器数组的副本。

+
server.on('connection', (stream) => {
+  console.log('someone connected!');
+});
+console.log(util.inspect(server.listeners('connection')));
+// 打印: [ [Function] ]
+

EventEmitter.on(eventName, listener)#

+
+

添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。

+
server.on('connection', (stream) => {
+  console.log('有连接!');
+});
+

返回一个 EventEmitter 引用,可以链式调用。

+

默认情况下,事件监听器会按照添加的顺序依次调用。 emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头。

+
const myEE = events.emitter();
+myEE.on('foo', () => console.log('a'));
+myEE.prependListener('foo', () => console.log('b'));
+myEE.emit('foo');
+// 打印:
+//   b
+//   a
+

EventEmitter.once(eventName, listener)#

+
+

添加一个单次 listener 函数到名为 eventName 的事件。 下次触发 eventName 事件时,监听器会被移除,然后调用。

+
server.once('connection', (stream) => {
+  console.log('首次调用!');
+});
+

返回一个 EventEmitter 引用,可以链式调用。

+

默认情况下,事件监听器会按照添加的顺序依次调用。 emitter.prependOnceListener() 方法可用于将事件监听器添加到监听器数组的开头。

+
const myEE = events.emitter();
+myEE.once('foo', () => console.log('a'));
+myEE.prependOnceListener('foo', () => console.log('b'));
+myEE.emit('foo');
+// 打印:
+//   b
+//   a
+

EventEmitter.prependListener(eventName, listener)#

+
+

添加 listener 函数到名为 eventName 的事件的监听器数组的开头。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。

+
server.prependListener('connection', (stream) => {
+  console.log('有连接!');
+});
+

返回一个 EventEmitter 引用,可以链式调用。

+

EventEmitter.prependOnceListener(eventName, listener)#

+
+

添加一个单次 listener 函数到名为 eventName 的事件的监听器数组的开头。 下次触发 eventName 事件时,监听器会被移除,然后调用。

+
server.prependOnceListener('connection', (stream) => {
+  console.log('首次调用!');
+});
+

返回一个 EventEmitter 引用,可以链式调用。

+

EventEmitter.removeAllListeners([eventName])#

+
+

移除全部或指定 eventName 的监听器。

+

注意,在代码中移除其他地方添加的监听器是一个不好的做法,尤其是当 EventEmitter 实例是其他组件或模块创建的。

+

返回一个 EventEmitter 引用,可以链式调用。

+

EventEmitter.removeListener(eventName, listener)#

+
+

从名为 eventName 的事件的监听器数组中移除指定的 listener。

+
const callback = (stream) => {
+  console.log('有连接!');
+};
+server.on('connection', callback);
+// ...
+server.removeListener('connection', callback);
+

removeListener 最多只会从监听器数组里移除一个监听器实例。 如果任何单一的监听器被多次添加到指定 eventName 的监听器数组中,则必须多次调用 removeListener 才能移除每个实例。

+

注意,一旦一个事件被触发,所有绑定到它的监听器都会按顺序依次触发。 这意味着,在事件触发后、最后一个监听器完成执行前,任何 removeListener() 或 removeAllListeners() 调用都不会从 emit() 中移除它们。 随后的事件会像预期的那样发生。

+
const myEmitter = events.emitter();
+
+const callbackA = () => {
+  console.log('A');
+  myEmitter.removeListener('event', callbackB);
+};
+
+const callbackB = () => {
+  console.log('B');
+};
+
+myEmitter.on('event', callbackA);
+
+myEmitter.on('event', callbackB);
+
+// callbackA 移除了监听器 callbackB,但它依然会被调用。
+// 触发是内部的监听器数组为 [callbackA, callbackB]
+myEmitter.emit('event');
+// 打印:
+//   A
+//   B
+
+// callbackB 被移除了。
+// 内部监听器数组为 [callbackA]
+myEmitter.emit('event');
+// 打印:
+//   A
+

因为监听器是使用内部数组进行管理的,所以调用它会改变在监听器被移除后注册的任何监听器的位置索引。 虽然这不会影响监听器的调用顺序,但意味着由 emitter.listeners() 方法返回的监听器数组副本需要被重新创建。

+

返回一个 EventEmitter 引用,可以链式调用。

+

EventEmitter.setMaxListeners(n)#

+
+

默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告。 此限制有助于寻找内存泄露。 但是,并不是所有的事件都要被限为 10 个。 emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制。 值设为 Infinity(或 0)表明不限制监听器的数量。

+

返回一个 EventEmitter 引用,可以链式调用。

+

KeyEvent#

+
Stability: 2 - Stable

KeyEvent.getAction()#

+

返回事件的动作。包括:

+ +

KeyEvent.getKeyCode()#

+

返回按键的键值。包括:

+ +

KeyEvent.getEventTime()#

+

返回事件发生的时间戳。返回值的类型是number。

+

KeyEvent.getDownTime()#

+

返回最近一次按下事件的时间戳。如果本身是按下事件,则与getEventTime()相同。

+

KeyEvent.keyCodeToString(keyCode)#

+

把键值转换为字符串。例如KEYCODE_HOME转换为"KEYCODE_HOME"。

+

Keys#

+
Stability: 2 - Stable

按键事件中所有可用的按键名称为:

+ + + +

Floaty#

+

floaty模块提供了悬浮窗的相关函数,可以在屏幕上显示自定义悬浮窗,控制悬浮窗大小、位置等。

+

悬浮窗在脚本停止运行时会自动关闭,因此,要保持悬浮窗不被关闭,可以用一个空的setInterval来实现,例如:

+
setInterval(()=>{}, 1000);
+

floaty.window(layout)#

+
+

指定悬浮窗的布局,创建并显示一个悬浮窗,返回一个FloatyWindow对象。

+

其中layout参数可以是xml布局或者一个View,更多信息参见ui模块的说明。

+

例子:

+
var w = floaty.window(
+    <frame gravity="center">
+        <text id="text">悬浮文字</text>
+    </frame>
+);
+setTimeout(()=>{
+    w.close();
+}, 2000);
+

这段代码运行后将会在屏幕上显示悬浮文字,并在两秒后消失。

+

另外,因为脚本运行的线程不是UI线程,而所有对控件的修改操作需要在UI线程执行,此时需要用ui.run,例如:

+
ui.run(function(){
+    w.text.setText("文本");
+});
+

floaty.expandableWindow(collapsedLayout, expandedLayout)#

+
+

指定悬浮窗的布局,创建并显示一个可展开悬浮窗,返回一个ExpandableFloatyWindow对象。

+

所谓可展开的悬浮窗,以Auto.js的控制台悬浮窗为例,点击右上角的最小化即为悬浮窗折叠状态,再点击悬浮窗则为展开状态。

+

其中layout参数可以是xml布局或者一个View,更多信息参见ui模块的说明。

+

例子:

+
var w = floaty.expandableWindow(
+    <img id="logo" src="file:///sdcard/logo.png" w="100" h="100" circle="true"/>
+    ,
+    <vertical>
+        <radiogroup bg="#ffffff">
+            <radio text="选项1">
+            <radio text="选项2">
+            <radio text="选项3">
+        </radiogroup>
+        <button id="minimize" text="折叠"/>
+        <button id="exit" text="关闭悬浮窗"/>
+    </vertical>
+
+);
+
+
+w.logo.click(()=> w.expand());
+w.minimize.click(()=> w.collapse());
+w.exit.click(()=> w.close());
+

这个例子运行后将会显示一个图片的图标,点击后显示三个选项和折叠、关闭按键。

+

floaty.closeAll()#

+

关闭所有本脚本的悬浮窗。

+

FloatyWindow#

+

悬浮窗对象,可通过FloatyWindow.{id}获取悬浮窗界面上的元素。例如, 悬浮窗window上一个控件的id为aaa, 那么window.aaa即可获取到该控件,类似于ui。

+

FloatyWindow.setAdjustEnabled(enabled)#

+
+

如果enabled为true,则在悬浮窗左上角、右上角显示可供位置、大小调整的标示,就像控制台一样; +如果enabled为false,则隐藏上述标示。

+

FloatyWindow.setPosition(x, y)#

+
+

设置悬浮窗位置。

+

FloatyWindow.getX()#

+

返回悬浮窗位置的X坐标。

+

FloatyWindow.getY()#

+

返回悬浮窗位置的Y坐标。

+

FloatyWindow.setSize(width, height)#

+
+

设置悬浮窗宽高。

+

FloatyWindow.getWidht()#

+

返回悬浮窗宽度。

+

FloatyWindow.getHeight()#

+

返回悬浮窗高度。

+

FloatyWindow.close()#

+

关闭悬浮窗。如果悬浮窗已经是关闭状态,则此函数将不执行任何操作。

+

被关闭后的悬浮窗不能再显示。

+

ExpandableFloatyWindow#

+

可展开悬浮窗。ExpandableFloatyWindow拥有FloatyWindow的所有函数,同时还有以下函数。

+

ExpandableFloatyWindow.expand();#

+

展开悬浮窗。

+

ExpandableFloatyWindow.collapse();#

+

折叠悬浮窗。

+

ExpandableFloatyWindow.toggle();#

+

如果悬浮窗是折叠状态,则展开悬浮窗;如果是展开状态,则折叠悬浮窗。

+

ExpandableFloatyWindow.isExpanded();#

+

返回悬浮窗是否是展开状态。 +

+ +

Files#

+
Stability: 2 - Stable

files模块提供了一些常见的文件处理,包括文件读写、移动、复制、删掉等。

+

files.isFile(path)#

+
+

返回路径path是否是文件。

+

files.isDir(path)#

+
+

返回路径path是否是文件夹。

+

files.isEmptyDir(path)#

+
+

返回文件夹path是否为空文件夹。如果该路径并非文件夹,则直接返回false。

+

files.join(parent, child)#

+
+

连接两个路径并返回,例如files.join("/sdcard/", "1.txt")返回"/sdcard/1.txt"。

+

files.create(path)#

+
+

创建一个文件并返回是否创建成功。

+

files.createIfNotExists(path)#

+
+

创建一个文件并返回是否创建成功。

+

files.exists(path)#

+
+

返回在路径path处的文件是否存在。

+

files.ensureDir(path)#

+
+

确保路径path所在的文件夹存在。

+

例如对于路径"/sdcard/Download/ABC/1.txt",如果/Download/文件夹不存在,则会先创建Download,再创建ABC文件夹。

+

files.read(path[, encoding = "utf-8"])#

+
+

读取文本文件path的所有内容并返回一个字符串。

+

files.readBytes(path)#

+
+

读取文件path的所有内容并返回一个字节数组。

+

注意,该数组是Java的数组,不具有JavaScript数组的函数。

+

files.write(path, text[, encoding = "utf-8"])#

+
+

把text写入到文件path中。如果文件存在则覆盖,不存在则创建。

+

files.writeBytes(path, bytes)#

+
+

把bytes写入到文件path中。如果文件存在则覆盖,不存在则创建。

+

files.append(path, text[, encoding = 'utf-8'])#

+
+

把text追加到文件path的末尾。如果文件不存在则创建。

+

files.appendBytes(path, text[, encoding = 'utf-8'])#

+
+

把bytes追加到文件path的末尾。如果文件不存在则创建。

+

files.copy(fromPath, toPath)#

+
+

复制文件。例如files.copy("/sdcard/1.txt", "/sdcard/Download/1.txt")

+

files.move(fromPath, toPath)#

+
+

移动文件,返回是否移动成功。例如files.move("/sdcard/1.txt", "/sdcard/Download/1.txt")会把1.txt文件从sd卡根目录移动到Download文件夹。

+

files.rename(path, newName)#

+
+

重命名文件,并返回是否重命名成功。例如files.rename("/sdcard/1.txt", "2.txt")

+

files.renameWithoutExtension(path, newName)#

+
+

重命名文件,不包含拓展名,并返回是否重命名成功。例如files.rename("/sdcard/1.txt", "2")会把1.txt重命名为2.txt。

+

files.getName(path)#

+
+

返回文件的文件名。例如files.getName("/sdcard/1.txt")返回"1.txt"。

+

files.getNameWithoutExtension(path)#

+
+

返回不含拓展名的文件的文件名。例如files.getName("/sdcard/1.txt")返回"1"。

+

files.getExtension(path)#

+
+

返回文件的拓展名。例如files.getExtension("/sdcard/1.txt")返回"txt"。

+

files.remove(path)#

+
+

删除文件或空文件夹,返回是否删除成功。

+

files.removeDir(path)#

+
+

删除文件夹,如果文件夹不为空,则删除该文件夹的所有内容再删除该文件夹,返回是否全部删除成功。

+

files.getSdcardPath()#

+

返回SD卡路径。所谓SD卡,即外部存储器。

+

files.listDir(path[, filter])#

+
+

列出文件夹path下的满足条件的文件和文件夹的名称的数组。如果不加filter参数,则返回所有文件和文件夹。

+

例如,获取sdcard目录下的txt文件为

+
var txtFiles = files.listDir("/sdcard/", function(name){
+    return name.endsWith(".txt") && files.isFile("/sdcard/" + name);
+});
+

open(path[, mode = "r", encoding = "utf-8", bufferSize = 8192])#

+
+

打开一个文件。根据打开模式返回不同的文件对象。包括:

+ +

对于"w"模式,如果文件并不存在,则会创建一个,已存在则会清空该文件内容;其他模式文件不存在会抛出FileNotFoundException。

+

ReadableTextFile#

+

可读文件对象。

+

ReadableTextFile.read()#

+

返回该文件剩余的所有内容的字符串。

+

ReadableTextFile.read(maxCount)#

+
+

读取该文件接下来最长为maxCount的字符串并返回。即使文件剩余内容不足maxCount也不会出错。

+

ReadableTextFile.readline()#

+

读取一行并返回(不包含换行符)。

+

ReadableTextFile.readlines()#

+

读取剩余的所有行,并返回它们按顺序组成的字符串数组。

+

close()#

+

关闭该文件。

+

打开一个文件不再使用时务必关闭

+

PWritableTextFile#

+

可写文件对象。

+

PWritableTextFile.write(text)#

+
+

把文本内容text写入到文件中。

+

PWritableTextFile.writeline(line)#

+
+

把文本line写入到文件中并写入一个换行符。

+

PWritableTextFile.writelines(lines)#

+
+

把很多行写入到文件中....

+

PWritableTextFile.flush()#

+

把缓冲区内容输出到文件中。

+

PWritableTextFile.close()#

+

关闭文件。同时会被缓冲区内容输出到文件。

+

打开一个文件写入后,不再使用时务必关闭,否则文件可能会丢失

+ + +

全局变量与函数#

+

全局变量和函数在所有模块中均可使用。 但以下变量的作用域只在模块内,详见 module文档:

+ +

一些模块中的函数为了使用方便也可以直接全局使用,这些函数在此不再赘述。例如timers模块的setInterval等函数。

+

sleep([n])#

+
+

暂停运行n毫秒的时间。1秒等于1000毫秒。

+

launchPackage(packageName)#

+
+

运行包名为packageName的应用主界面(Launcher)。例如,打开微信为:

+
launchPackage("com.tencent.mm");
+

如果存在多个应用包名相同的情况(如双开应用),如何处理取决于操作系统。在MIUI中会弹出多开应用的选择界面。

+

launchApp(appName)#

+
+

运行应用名称为appName的应用主界面。当有应用名称相同时只运行其中某一个。
例如,打开微信为:

+
launchApp("微信");
+

currentPackage()#

+

返回最近一次监测到的正在运行的应用的包名,一般可以认为就是当前正在运行的应用的包名。

+

currentActivity()#

+

返回最近一次监测到的正在运行的Activity的名称,一般可以认为就是当前正在运行的Activity的名称。

+

getPackageName(appName)#

+
+

获取应用的包名。例如getPackageName("QQ")为"com.tencent.mobileqq"。如果有相同名称的应用,只返回其中某一个的包名。如果不存在这个名称的应用,会返回null。

+

getAppName(packageName)#

+
+

返回对应包名的应用的名称。如果应用不存在,返回null。

+

openAppSetting(packageName)#

+
+

打开某个应用的应用详情页,也就是管理应用权限和可以停止其运行的页面。如果应用包名不存在,则返回false;否则返回true。

+

setClip(text)#

+
+

设置剪贴板内容。此剪贴板即系统剪贴板,在一般应用的输入框中"粘贴"既可使用。

+

getClip()#

+

返回系统剪贴板的内容。

+

toast(message)#

+
+

以气泡显示信息message几秒。(具体时间取决于安卓系统,一般都是2秒)

+

注意,信息的显示是"异步"执行的(不属于Looper循环),并且,不会等待信息消失程序才继续执行。如果在循环中执行该命令,可能出现脚本停止运行后仍然有不断的气泡信息出现的情况。 +例如:

+
for(var i = 0; i < 100; i++){
+  toast(i);
+}
+

运行这段程序以后,会很快执行完成,且不断弹出消息,在任务管理中关闭所有脚本也无法停止。 +要保证气泡消息才继续执行可以用:

+
for(var i = 0; i < 100; i++){
+  toast(i);
+  sleep(2000);
+}
+

或者修改toast函数:

+
var _toast_ = toast;
+toast = function(message){
+  _toast_(message);
+  sleep(2000);
+}
+for(var i = 0; i < 100; i++){
+  toast(i);
+  sleep(2000);
+}
+

toastLog(message)#

+
+

相当于toast(message);log(message)。显示信息message并在控制台中输出。参见console.log。

+

waitForActivity(activity[, period = 200])#

+
+

等待指定的Activity出现,period为检查Activity的间隔。

+

waitForPackage(package[, period = 200])#

+
+

等待指定的应用出现。例如waitForPackage("com.tencent.mm")为等待当前界面为微信。

+

exit()#

+

立即停止脚本运行。

+

random(min, max)#

+
+

返回一个在[min...max]之间的随机数。例如random(0, 2)可能产生0, 1, 2.

+

random()#

+

返回在[0, 1)的随机浮点数。

+

context#

+

全局变量。一个android.content.Context对象。

+

注意该对象为ApplicationContext,因此不能用于界面、对话框等的创建。 +

+ +

HTTP#

+
Stability: 2 - Stable

http模块提供一些进行http请求的函数。

+

http.get(url[, options, callback])#

+
+

对地址url进行一次HTTP GET 请求。如果没有回调函数,则在请求完成或失败时返回此次请求的响应(参见[Response][])。

+

最简单GET请求如下:

+
console.show();
+var r = http.get("www.baidu.com");
+log("code = " + r.statusCode);
+log("html = " + r.body.string());
+

采用回调形式的GET请求如下:

+
console.show();
+http.get("www.baidu.com", {}, function(res, err){
+    if(err){
+        console.error(err);
+        return;
+    }
+    log("code = " + r.statusCode);
+    log("html = " + r.body.string());
+});
+

如果要增加HTTP头部信息,则在options参数中添加,例如:

+
console.show();
+var r = http.get("www.baidu.com", {
+    headers: {
+        "Accept-Language": "zh-cn,zh;q=0.5",
+        "User-Agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X
+10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56
+Safari/535.11"
+    }
+});
+log("code = " + r.statusCode);
+log("html = " + r.body.string());
+

一个请求天气并解析返回的天气JSON结果的例子如下:

+
var city = "广州";
+var res = http.get("http://www.sojson.com/open/api/weather/json.shtml?city=" + city);
+if(res.statusCode != 200){
+    toast("请求失败: " + res.statusCode + " " + res.statusMessage);
+}else{
+    var weather = res.body.json();
+    log(weather);
+    toast(util.format("温度: %s 湿度: %s 空气质量: %s", weather.data.wendu,
+        weather.data.shidu, weather.quality));
+}
+

http.post(url, data[, options, callback])#

+
+

对地址url进行一次HTTP POST 请求。如果没有回调函数,则在请求完成或失败时返回此次请求的响应(参见[Response][])。

+

其中POST数据可以是字符串或键值对。具体含义取决于options.contentType的值。默认为"application/x-www-form-urlencoded"(表单提交), 这种方式是JQuery的ajax函数的默认方式。

+

一个模拟表单提交登录淘宝的例子如下:

+
var url = "https://login.taobao.com/member/login.jhtml";
+var username = "你的用户名";
+var password = "你的密码";
+var res = http.post(url, {
+    "TPL_username": username,
+    "TPL_password": password
+});
+var html = res.body.string();
+if(html.contains("页面跳转中")){
+    toast("登录成功");
+}else{
+    toast("登录失败");
+}
+

http.postJson(url[, data, options, callback])#

+
+

以JSON格式向目标Url发起POST请求。如果没有回调函数,则在请求完成或失败时返回此次请求的响应(参见[Response][])。

+

JSON格式指的是,将会调用JSON.stringify()把data对象转换为JSON字符串,并在HTTP头部信息中把"Content-Type"属性置为"application/json"。这种方式是AngularJS的ajax函数的默认方式。

+

一个调用图灵机器人接口的例子如下:

+

http.postMultipart(url, files[, options, callback])#

+
+

向目标地址发起类型为multipart/form-data的请求(通常用于文件上传等), 其中files参数是<name1: value1, name2: value2, ...>的键值对,value的格式可以是以下几种情况:

+
    +
  1. string
  2. +
  3. 文件类型,即open()返回的类型
  4. +
  5. [fileName, filePath]
  6. +
  7. [fileName, mimeType, filePath]
  8. +
+

其中1属于非文件参数,2、3、4为文件参数。举个例子,最简单的文件上传的请求为:

+
var res = http.postMultipart(url, {
+    file: open("/sdcard/1.txt")
+});
+log(res.body.string());
+

如果使用格式2,则代码为

+
var res = http.postMultipart(url, {
+    file: ["1.txt", "/sdcard/1.txt"]
+});
+log(res.body.string());
+

如果使用格式3,则代码为

+
var res = http.postMultipart(url, {
+    file: ["1.txt", "text/plain", "/sdcard/1.txt"]
+});
+log(res.body.string());
+

如果使用格式2的同时要附带非文件参数"appId=abcdefghijk",则为:

+
var res = http.postMultipart(url, {
+    appId: "adcdefghijk",
+    file: open("/sdcard/1.txt")
+});
+log(res.body.string());
+

http.request(url[, options, callback])#

+
+

对目标地址url发起一次HTTP请求。如果没有回调函数,则在请求完成或失败时返回此次请求的响应(参见[Response][])。

+

选项options可以包含以下属性:

+ +

该函数是get, post, postJson等函数的基础函数。因此除非是PUT, DELET等请求,或者需要更高定制的HTTP请求,否则直接使用get, post, postJson等函数会更加方便。

+

Response#

+

HTTP请求的响应。

+

Response.statusCode#

+
+

当前响应的HTTP状态码。例如200(OK), 404(Not Found)等。

+

有关HTTP状态码的信息,参见菜鸟教程:HTTP状态码

+

Response.statusMessage#

+
+

当前响应的HTTP状态信息。例如"OK", "Bad Request", "Forbidden"。

+

有关HTTP状态码的信息,参见菜鸟教程:HTTP状态码

+

例子:

+
var res = http.get("www.baidu.com");
+if(res.statusCode >= 200 && res.statusCode < 300){
+    toast("页面获取成功!");
+}else if(res.statusCode == 404){
+    toast("页面没找到哦...");
+}else{
+    toast("错误: " + res.statusCode + " " + res.statusMessage);
+}
+

Response.headers#

+
+

当前响应的HTTP头部信息。该对象的键是响应头名称,值是各自的响应头值。 所有响应头名称都是小写的(吗)。

+

有关HTTP头部信息,参见菜鸟教程:HTTP响应头信息

+

例子:

+
console.show();
+var res = http.get("www.qq.com");
+console.log("HTTP Headers:")
+for(var headerName in res.headers){
+    console.log("%s: %s", headerName, res.headers[headerName]);
+}
+

Response.body#

+
+

当前响应的内容。他有以下属性和函数:

+ +

Response.request#

+
+

Response.url#

+
+

Response.method#

+
+
+ +

Images#

+
Stability: 2 - Stable

images模块提供了一些手机设备中常见的图片处理函数,包括截图、读写图片、图片剪裁、找色、找图等。

+

images.requestScreenCapture([landscape])#

+
+

向系统申请屏幕截图权限,返回是否请求成功。

+

第一次使用该函数会弹出截图权限请求,建议选择“总是允许”。

+

这个函数只是申请截图权限,并不会真正执行截图,真正的截图函数是[captureScreen][]。

+

该函数在截图脚本中只需执行一次,而无需每次调用[captureScreen][]都调用一次。

+

如果不指定landscape值,则截图方向由当前设备屏幕方向决定,因此务必注意执行该函数时的屏幕方向。

+

建议在本软件界面运行该函数,在其他软件界面运行时容易出现一闪而过的黑屏现象。

+

示例:

+
//请求截图
+if(!requestScreenCapture()){
+    toast("请求截图失败");
+    exit();
+}
+//连续截图10张图片(间隔1秒)并保存到存储卡目录
+for(var i = 0; i < 10; i++){
+    captureScreen("/sdcard/screencapture" + i + ".png");
+    sleep(1000);
+}
+

该函数也可以作为全局函数使用。

+

images.captureScreen()#

+

截取当前屏幕并返回一个Image对象。

+

没有截图权限时执行该函数会抛出SecurityException。

+

该函数不会返回null,两次调用可能返回相同的Image对象。这是因为设备截图的更新需要一定的时间,短时间内(一般来说是16ms)连续调用则会返回同一张截图。

+

截图需要转换为Bitmap格式,从而该函数执行需要一定的时间(0~20ms)。

+

另外在requestScreenCapture()执行成功后需要一定时间后才有截图可用,因此如果立即调用captureScreen(),会等待一定时间后(一般为几百ms)才返回截图。

+

例子:

+
//请求横屏截图
+requestScreenCapture(true);
+//截图
+var img = captureScreen();
+//获取在点(100, 100)的颜色值
+var color = images.pixel(img, 100, 100);
+//显示该颜色值
+toast(colors.toString(color));
+

该函数也可以作为全局函数使用。

+

images.captureScreen(path)#

+
+

截取当前屏幕并以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

+

该函数不会返回任何值。该函数也可以作为全局函数使用。

+

images.pixel(image, x, y)#

+
+

返回图片image在点(x, y)处的像素的ARGB值。

+

该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

+

坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

+

images.save(image, path)#

+
+

把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

+

images.read(path)#

+
+

读取在路径path的图片文件并返回一个Image对象。如果文件不存在或者文件无法解码则返回null。

+

images.load(url)#

+
+

加载在地址URL的网络图片并返回一个Image对象。如果地址不存在或者图片无法解码则返回null。

+

images.findColor(image, color, options)#

+
+

在图片中寻找颜色color。找到时返回找到的点Point,找不到时返回null。

+

选项包括:

+ +

该函数也可以作为全局函数使用。

+

一个循环找色的例子如下:

+
requestScreenCapture();
+
+//循环找色,找到红色(#ff0000)时停止并报告坐标
+while(true){
+    var img = captureScreen();
+    var point = findColor(img, "#ff0000");
+    if(point){
+        toast("找到红色,坐标为(" + point.x + ", " + point.y + ")");
+    }
+}
+

一个区域找色的例子如下:

+
//读取本地图片/sdcard/1.png
+var img = images.read("/sdcard/1.png");
+//判断图片是否加载成功
+if(!img){
+    toast("没有该图片");
+    exit();
+}
+//在该图片中找色,指定找色区域为在位置(400, 500)的宽为300长为200的区域,指定找色临界值为4
+var point = findColor(img, "#00ff00", {
+     region: [400, 500, 300, 200],
+     threshold: 4
+ });
+if(point){
+    toast("找到啦:" + point);
+}else{
+    toast("没找到");
+}
+

images.findColorInRegion(img, color, x, y[, width, height, threshold])#

+

区域找色的简便方法。

+

相当于

+
images.findColor(img, color, {
+     region: [x, y, width, height],
+     threshold: threshold
+});
+

该函数也可以作为全局函数使用。

+

images.findColorEquals(img, color[, x, y, width, height])#

+

严格找色的简便方法。找色时要求颜色完全相等才匹配。

+

相当于

+
images.findColor(img, color, {
+   region: [x, y, width, height],
+   threshold: 0
+});
+

该函数也可以作为全局函数使用。

+

示例: +(通过找QQ红点的颜色来判断是否有未读消息)

+
requestScreenCapture();
+launchApp("QQ");
+sleep(1200);
+var p = findColorEquals(captureScreen(), "#f64d30");
+if(p){
+    toast("有未读消息");
+}else{
+    toast("没有未读消息");
+}
+

images.detectsColor(image, color, x, y[, threshold = 16, algorithm = "diff"])#

+
+

返回图片image在位置(x, y)处是否匹配到颜色color。用于检测图片中某个位置是否是特定颜色。

+

一个判断微博客户端的某个微博是否被点赞过的例子:

+
requestScreenCapture();
+//找到点赞控件
+var like = id("ly_feed_like_icon").findOne();
+//获取该控件中点坐标
+var x = like.bounds().centerX();
+var y = like.bounds().centerY();
+//截图
+var img = captureScreen();
+//判断在该坐标的颜色是否为橙红色
+if(images.detectsColor(img, "#fed9a8", x, y)){
+    //是的话则已经是点赞过的了,不做任何动作
+}else{
+    //否则点击点赞按钮
+    like.click();
+}
+

images.findImage(img, template[, options])#

+
+

找图。在大图片img中查找小图片template的位置(模块匹配),找到时返回位置坐标(Point),找不到时返回null。

+

选项包括:

+ +

该函数也可以作为全局函数使用。

+

一个最简单的找图例子如下:

+
var img = images.read("/sdcard/大图.png");
+var templ = images.read("/sdcard/小图.png");
+var p = findImage(img, templ);
+if(p){
+    toast("找到啦:" + p);
+}else{
+    toast("没找到");
+}
+

稍微复杂点的区域找图例子如下:

+
auto();
+requestScreenCapture();
+var wx = images.read("/sdcard/微信图标.png");
+//返回桌面
+home();
+//截图并找图
+var p = findImage(captureScreen(), wx, {
+    region: [0, 50],
+    threshold: 0.8
+});
+if(p){
+    toast("在桌面找到了微信图标啦: " + p);
+}else{
+    toast("在桌面没有找到微信图标");
+}
+

images.findImageInRegion(img, template, x, y[, width, height, threshold])#

+

区域找图的简便方法。相当于:

+
images.findImage(img, template, {
+    region: [x, y, width, height],
+    threshold: threshold
+})
+

该函数也可以作为全局函数使用。

+

colors#

+
Stability: 2 - Stable

colors是颜色处理的工具对象。包含一些常用方法,包括android.graphics.Color的所有方法以及toString方法。

+

colors.toString(color)#

+
+

返回颜色值的字符串,格式为 #AARRGGBB。

+

colors.red(color)#

+
+

返回颜色color的R通道的值,范围0~255.

+

colors.green(color)#

+
+

返回颜色color的G通道的值,范围0~255.

+

colors.blue(color)#

+
+

返回颜色color的B通道的值,范围0~255.

+

colors.alpha(color)#

+
+

返回颜色color的Alpha通道的值,范围0~255.

+

colors.rgb(red, green, blue)#

+
+

返回这些颜色通道构成的整数颜色值。Alpha通道将是255(不透明)。

+

colors.argb(alpha, red, green, blue)#

+
+

返回这些颜色通道构成的整数颜色值。

+

Image#

+

表示一张图片,可以是截图的图片,或者本地读取的图片,或者从网络获取的图片。

+

Image.getWidth()#

+

返回以像素为单位图片宽度。

+

Image.getHeight()#

+

返回以像素为单位的图片高度。

+

Image.saveTo(path)#

+
+

把图片保存到路径path。(如果文件存在则覆盖)

+

Image.pixel(x, y)#

+
+

返回图片image在点(x, y)处的像素的ARGB值。

+

该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

+

坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

+

Point#

+

findColor, findImage返回的对象。表示一个点(坐标)。

+

Point.x#

+

横坐标。

+

Point.y#

+

纵坐标。

+ + +

Keys#

+

按键模拟部分提供了一些模拟物理按键的全局函数,包括Home、音量键、照相键等,有的函数依赖于无障碍服务,有的函数依赖于root权限。

+

back()#

+

模拟按下返回键。返回是否执行成功。 +此函数依赖于无障碍服务。

+

home()#

+

模拟按下Home键。返回是否执行成功。 +此函数依赖于无障碍服务。

+

powerDialog()#

+

弹出电源键菜单。返回是否执行成功。 +此函数依赖于无障碍服务。

+

notifications()#

+

弹出通知栏。返回是否执行成功。 +此函数依赖于无障碍服务。

+

quickSettings()#

+

显示快速设置(下拉通知栏到底)。返回是否执行成功。 +此函数依赖于无障碍服务。

+

recents()#

+

显示最近任务。返回是否执行成功。 +此函数依赖于无障碍服务。

+

splitScreen()#

+

分屏。返回是否执行成功。 +此函数依赖于无障碍服务。

+

Home()#

+

模拟按下Home键。 +此函数依赖于root权限。

+

Back()#

+

模拟按下返回键。 +此函数依赖于root权限。

+

Power()#

+

模拟按下电源键。 +此函数依赖于root权限。

+

Menu()#

+

模拟按下菜单键。 +此函数依赖于root权限。

+

VolumeUp()#

+

按下音量上键。 +此函数依赖于root权限。

+

VolumeDown()#

+

按键音量上键。 +此函数依赖于root权限。

+

Camera()#

+

模拟按下照相键。

+

Up()#

+

模拟按下物理按键上。 +此函数依赖于root权限。

+

Down()#

+

模拟按下物理按键下。 +此函数依赖于root权限。

+

Left()#

+

模拟按下物理按键左。 +此函数依赖于root权限。

+

Right()#

+

模拟按下物理按键右。 +此函数依赖于root权限。

+

OK()#

+

模拟按下物理按键确定。 +此函数依赖于root权限。

+

Text(text)#

+
+

KeyCode(code)#

+
+

附录: KeyCode对照表#

+

KeyCode KeyEvent Value

+ + + +

module (模块)#

+
Stability: 2 - Stable

Auto.js 有一个简单的模块加载系统。 在 Auto.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)。

+

例子,假设有一个名为 foo.js 的文件:

+
const circle = require('./circle.js');
+console.log("半径为 4 的圆的面积是 %d", circle.area(4));
+

在第一行中,foo.js 加载了同一目录下的 circle.js 模块。

+

circle.js 文件的内容为:

+
const PI = Math.PI;
+
+var circle = {};
+
+circle.area = (r) => PI * r ** 2;
+
+circle.circumference = (r) => 2 * PI * r;
+
+module.exports = circle;
+

circle.js 模块导出了 area() 和 circumference() 两个函数。 通过在特殊的 exports 对象上指定额外的属性,函数和对象可以被添加到模块的根部。

+

模块内的本地变量是私有的,因为模块被 Node.js 包装在一个函数中(详见模块包装器)。 在这个例子中,变量 PI 是 circle.js 私有的。

+

module.exports属性可以被赋予一个新的值(例如函数或对象)。

+

如下,bar.js 会用到 square 模块,square 导出一个构造函数:

+
const square = require('./square.js');
+const mySquare = square(2);
+console.log(`正方形的面积是 ${mySquare.area()}`);
+square 模块定义在 square.js 中:
+
+// 赋值给 `exports` 不会修改模块,必须使用 `module.exports`
+module.exports = function(width) {
+  return {
+    area: () => width ** 2
+  };
+};
+
+ +

SimpleActionAutomator#

+
Stability: 2 - Stable

SimpleActionAutomator提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。

+

click(text[, i])#

+
+

返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。

+

该函数可以点击大部分包含文字的按钮。例如微信主界面下方的"微信", "联系人", "发现", "我"的按钮。
通常与while同时使用以便点击按钮直至成功。例如:

+
while(!click("扫一扫"));
+

当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部点击成功。

+

i是从0开始计算的, 也就是, click("啦啦啦", 0)表示点击屏幕上第一个"啦啦啦", click("啦啦啦", 1)表示点击屏幕上第二个"啦啦啦"。

+
+

文本所在区域指的是,从文本处向其父视图寻找,直至发现一个可点击的部件为止。

+
+

click(left, top, bottom, right)#

+
+

注意,该函数一般只用于录制的脚本中使用,在自己写的代码中使用该函数一般不要使用该函数。

+

点击在指定区域的控件。当屏幕中并未包含与该区域严格匹配的区域,或者该区域不能点击时返回false,否则返回true。

+

有些按钮或者部件是图标而不是文字(例如发送朋友圈的照相机图标以及QQ下方的消息、联系人、动态图标),这时不能通过click(text, i)来点击,可以通过描述图标所在的区域来点击。left, bottom, top, right描述的就是点击的区域。

+

至于要定位点击的区域,可以在悬浮窗使用布局分析工具查看控件的bounds属性。

+

通过无障碍服务录制脚本会生成该语句。

+

longClick(text[, i]))#

+
+

返回是否点击成功。当屏幕中并未包含该文本,或者该文本所在区域不能点击时返回false,否则返回true。

+

当不指定参数i时则会尝试点击屏幕上出现的所有文字text并返回是否全部长按成功。

+

scrollUp([i])#

+
+

找到第i+1个可滑动控件上滑或左滑。返回是否操作成功。屏幕上没有可滑动的控件时返回false。

+

另外不加参数时scrollUp()会寻找面积最大的可滑动的控件上滑或左滑,例如微信消息列表等。

+

参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如scrollUp(0)为滑动第一个可滑动控件。

+

scrollDown([i])#

+
+

找到第i+1个可滑动控件下滑或右滑。返回是否操作成功。屏幕上没有可滑动的控件时返回false。

+

另外不加参数时scrollUp()会寻找面积最大的可滑动的控件下滑或右滑。

+

参数为一个整数i时会找到第i + 1个可滑动控件滑动。例如scrollUp(0)为滑动第一个可滑动控件。

+

setText([i, ]text)#

+
+

返回是否输入成功。当找不到对应的文本框时返回false。

+

不加参数i则会把所有输入框的文本都置为text。例如setText("测试")

+

这里的输入文本的意思是,把输入框的文本置为text,而不是在原来的文本上追加。

+

input([i, ]text)#

+
+

返回是否输入成功。当找不到对应的文本框时返回false。

+

不加参数i则会把所有输入框的文本追加内容text。例如input("测试")

+

UiSelector#

+

选择器(UiSelector)是稍微复杂的自动操作脚本所必须。使用选择器的一般步骤是:

+
    +
  1. 用各种筛选条件找出想要的控件,如某个文本控件、列表控件、图片控件
  2. +
  3. 对找出的控件执行想要的操作,如点击、滑动、设置文字、长按
  4. +
+

问题的关键在于如何找出想要的控件。对于文本控件一般通过他的文字来定位他,图片控件则通过id或者图片描述(desc)。选择器所做的就是提供这些筛选条件并给出筛选结果。

+

选择器提供了更强大的定位界面控件与对其进行操作的功能,可以用他们完成更多的自动操作和提取界面信息。
选择器通过附加筛选条件,筛选出符合条件的控件或控件集合,之后可以对这些控件这些操作。
可供选择的筛选条件包括:

+ +

要对选择器所确定的筛选条件,对屏幕上的控件进行筛选,调用方法find(), findOne(), untilFind()。其中find(), untilFind()返回控件的集合,findOne()返回一个控件。untilFind和findOne函数会一直寻找直到屏幕上出现满足条件的控件为止。
一个完整的选择器示例如下:

+
var emoj = id("name").packageName("com.tencent.mobileqq").clickable()
+        .className("ImageView").drawingOrder(5).findOne();
+emoj.click();
+

上述代码是找到QQ聊天界面下面的表情按钮(第5个按钮)并点击。也可以简化为:

+
id("name").packageName("com.tencent.mobileqq").clickable()
+       .className("ImageView").click();
+

这段代码意思是,找出id为"name", 包名为"com.tentcent.mobileqq",类名为ImageView的所有可点击控件,对他们执行点击动作。

+

最后的click()函数相当于untilFind().click()。也就是如果只需要在找到控件以后立即进行操作,只需要调用相应的操作函数,而不需要先调用find等函数等到控件再操作。
要获取屏幕上的控件的信息(例如id, text, desc, bounds等),可以开启悬浮窗,使用界面层次查看和界面范围查看。

+

选择器部分内容如果有安卓开发经验会更容易掌握。

+

id(resId)#

+
+

附加id严格匹配筛选条件。

+

控件的id属性通常是可以用来确定控件的唯一标识,如果一个控件有id,那么使用id来找到他是最好的方法。要查看屏幕上的控件的id,可以开启悬浮窗并使用界面工具,点击相应控件即可查看。若查看到的控件id为null, 表示该控件没有id。另外,在列表中会出现多个控件的id相同的情况。例如微信的联系人列表,每个头像的id都是一样的。此时不能用id来唯一确定控件。

+

在QQ界面经常会出现多个id为"name"的控件,在微信上则每个版本的id都会变化。对于这些软件而言比较难用id定位控件。

+

idContains(str)#

+
+

附加控件id包含字符串str的筛选条件。

+

idStartsWith(prefix)#

+
+

附加id需要以prefix开头的筛选条件。

+

idEndsWith(suffix)#

+
+

附加id需要以suffix结束的筛选条件。

+

idMatches(String)#

+
+

附加id需要满足正则表达式。有关正则表达式,可以查看菜鸟教程

+

这里的正则表达式是Java的正则表达式,不能直接使用JavaScript的正则表达式。

+
idMatches("[a-zA-Z]+")
+

text(str)#

+
+

附加控件文本等于字符串str的筛选条件。

+

控件的text(文本)属性是控件上的显示的文字,例如微信左上角的"微信"文本。对于图片或者其他控件通常text属性为null。

+

textContains(str)#

+
+

附加控件文本需要以prefix开头的筛选条件。

+

textStartsWith(prefix)#

+
+

附加控件文本需要以prefix开头的筛选条件。

+

textEndsWith(suffix)#

+
+

附加控件文本需要以suffix结束的筛选条件。

+

textMatches(str)#

+
+

附加控件文本需要满足正则表达式的条件。

+

desc(str)#

+
+

附加控件描述等于字符串str的筛选条件。

+

控件的desc(描述,全称为Content-Description)属性是对一个控件的描述,例如网易云音乐右上角的放大镜图标的描述为搜索。要查看一个控件的描述,同样地可以借助悬浮窗查看。

+

desc属性同样是定位控件的利器。

+

descContains(str)#

+
+

附加控件描述需要以prefix开头的筛选条件。

+

descStartsWith(prefix)#

+
+

附加控件描述需要以prefix开头的筛选条件。

+

descEndsWith(suffix)#

+
+

附加控件描述需要以suffix结束的筛选条件。

+

descMatches(str)#

+
+

附加控件描述需要满足正则表达式的条件。

+

className(str)#

+
+

附加控件类名等于字符串str的筛选条件。

+

控件的className属性是一个控件的具体类型,例如图片控件通常为ImageView,文本控件通常为TextView, 输入框通常为EditText。(若一个控件是在android.widget包里的,那么android.widget可以省略。但除此之外的其他控件必须是类的全名,例如"com.stardust.theme.ThemeColorImageView")。

+

classNameContains(str)#

+
+

附加控件类名需要以prefix开头的筛选条件。

+

classNameStartsWith(prefix)#

+
+

附加控件类名需要以prefix开头的筛选条件。

+

classNameEndsWith(suffix)#

+
+

附加控件类名需要以suffix结束的筛选条件。

+

classNameMatches(str)#

+
+

附加控件类名需要满足正则表达式的条件。

+

packageName(str)#

+
+

附加包名等于字符串str的筛选条件。

+

packageName属性也即控件所属的应用的包名(参见《shell命令:应用包名》),通常用来保证当前运行的应用是想要的应用。

+

packageNameContains(str)#

+
+

附加包名需要以prefix开头的筛选条件。

+

packageNameStartsWith(prefix)#

+
+

附加包名需要以prefix开头的筛选条件。

+

packageNameEndsWith(suffix)#

+
+

附加包名需要以suffix结束的筛选条件。

+

packageNameMatches(str)#

+
+

附加包名需要满足正则表达式的条件。

+

bounds(l, t, r, b)#

+
+

boundsInside(l, t, r, b)#

+

boundsContains(l, t, r, b)#

+

drawingOrder(order)#

+
+

checkable([b = true])#

+
+

附加控件是否可勾选的条件。可勾选指的是,例如QQ和微信发送图片时图片的勾选。

+

selected([b = true])#

+
+

附加控件是否被选中的条件。被选中指的是,例如QQ聊天界面点击下方的表情按钮时,会出现自己收藏的表情,这时表情按钮便处于选中状态。

+

clickable([b = true])#

+
+

附加控件是否可点击的条件。但并非所有clickable为false的控件都真的不能点击,这取决于控件的实现。因而要确定一个控件的clickable属性,可以开启悬浮窗工具。

+

longClickable([b = true])#

+
+

附加控件是否可长按的条件。

+

enabled([b = true])#

+
+

附加控件是否已启用的条件。大多数控件都是启用的状态,处于“禁用”状态通常是灰色并且不可点击。

+

scrollable([b = true])#

+
+

附加控件是否可滑动的条件。

+

editable([b = true])#

+
+

附加控件是否可编辑的条件。一般来说可编辑的控件为输入框(EditText)。

+

contentInvalid([b = true])#

+
+

我也不知道是什么,下次再补充吧。

+

contextClickable([b = true])#

+
+

我也不知道是什么,下次再补充吧。

+

multiLine([b = true])#

+
+

附加控件是否文本或输入框控件是否是多行显示的条件。

+

findOne()#

+

根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到屏幕上出现满足条件的一个控件为止,并返回该控件。如果找不到控件,当屏幕内容发生变化时会重新寻找,直至找到。参见控件

+

find()#

+

根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,找到所有满足条件的控件集合并返回。这个搜索只进行一次,并不保证一直会找到,因而会出现返回的控件集合为空的情况。参见控件集合

+

可以通过empty()或nonEmpty()函数判断找到的是否为空。例如:

+
var c = className("AbsListView").find();
+if(c.empty()){
+    toast("找到啦");
+}else{
+    toast("没找到╭(╯^╰)╮");
+}
+

untilFind()#

+

根据当前的选择器所确定的筛选条件,对屏幕上的控件进行搜索,直到找到至少一个满足条件的控件为止,并返回所有满足条件的控件集合。参见控件集合

+

exists()#

+

判断屏幕上是否存在控件符合选择器所确定的条件。例如要判断某个文本出现就执行某个动作,可以用:

+
if(text("嘿嘿嘿").exists()){
+    //嘿嘿嘿
+}
+

waitFor()#

+

等待屏幕上出现符合条件的控件。

+
text("嘿嘿嘿").waitFor();
+

click()#

+

找到所有符合条件的控件并点击。相当于untilFind().click()。参见click)。

+

longClick()#

+

找到所有符合条件的控件并长按。相当于untilFind().longClick()。参见longClick)。

+

copy()#

+

找到所有符合条件的控件并复制其内容,只对文本框或输入框控件有文字选中时有效。相当于untilFind().copy()。参见copy)。

+

paste()#

+

找到所有符合条件的控件并粘贴,只对输入框控件有效。相当于untilFind().paste()。参见paste)。

+

select()#

+

找到所有符合条件的控件并选中。相当于untilFind().select()。参见select)。

+

cut()#

+

找到所有符合条件的控件并剪切其内容,只对文本框或输入框控件有文字选中时有效。相当于untilFind().cut()。参见cut)。

+

collapse()#

+

找到所有符合条件的控件并折叠。相当于untilFind().collapse()。参见collapse)。

+

expand()#

+

找到所有符合条件的控件并展开。相当于untilFind().expand()。参见expand)。

+

show()#

+

找到所有符合条件的控件并使其出现在屏幕上。相当于untilFind().show()。参见show)。

+

scrollForward()#

+

找到所有符合条件的控件并向前滑。相当于untilFind().scrollForward()。参见scrollForward)。
向前滑指的是,对于左右滑动的控件向右滑,上下滑动的控件向下滑。

+

scrollBackward()#

+

找到所有符合条件的控件并向后滑。相当于untilFind().scrollBackward()。参见scrollBackward)。
向后滑指的是,对于左右滑动的控件向左滑,上下滑动的控件向上滑。

+

scrollUp()#

+

找到所有符合条件的控件并向上滑。相当于untilFind().scrollUp()。参见scrollUp)。

+

scrollDown()#

+

找到所有符合条件的控件并向下滑。相当于untilFind().scrollDown()。参见scrollDown)。

+

scrollLeft()#

+

找到所有符合条件的控件并向左滑。相当于untilFind().scrollLeft()。参见scrollLeft)。

+

scrollRight()#

+

找到所有符合条件的控件并向右滑。相当于untilFind().scrollRight()。参见scrollRight)。

+

contextClick()#

+

文档缺失

+

setSelection(start, end)#

+
+

找到所有符合条件的控件并设置文字选中区域,只对文本控件和输入框有效。相当于untilFind().setSelection()。参见setSelection

+

setText(text)#

+
+

UiCollection#

+

UiCollection, 控件集合, 通过选择器的find(), untilFind()方法返回的对象。可以对其进行操作或者获取其信息。

+

UiCollection.size()#

+

返回集合中的控件数。

+

UiCollection.get(i)#

+
+

返回集合中第i+1个控件(UiObject)。

+

UiCollection.each(func)#

+
+

遍历集合。例如:

+
var c = clickable();
+c.each(function(o){
+    log(o.text());
+});
+

empty()#

+

返回控件集合是否为空。

+

nonEmpty()#

+

返回控件集合是否非空。

+

UiCollection.filter(filter)#

+
+

过滤出控件集合中符合条件的子控件。例如要过滤出所有子控件数目为1的控件为:

+
var newCollection = collection.filter(function(obj){
+    return obj.childCount() == 1;
+});
+

UiCollection.find(selector)#

+
+

根据selector所确定的条件在该控件集合的控件和子控件找到所有符合条件的控件并返回控件集合。

+

注意这会递归地遍历控件集合里所有的控件以及他们的子控件。和filter函数不同。

+

例如:

+
var names = id("name");
+var clickableNames = names.find(clickable());
+

UiCollection.findOne(selector)#

+
+

根据selector所确定的条件在该控件集合中找到一个符合条件的控件并返回控件。若找不到则返回null。

+

UiCollection.click()#

+

点击集合中所有控件,并返回是否全部点击成功。

+

UiCollection.longClick()#

+

长按集合中所有控件,并返回是否全部操作成功。

+

UiCollection.copy()#

+

对集合中所有控件执行复制操作,并返回是否全部操作成功。

+

UiCollection.paste()#

+

对集合中所有控件执行粘贴操作,并返回是否全部操作成功。

+

UiCollection.select()#

+

对集合中所有控件执行选中操作,并返回是否全部操作成功。

+

UiCollection.cut()#

+

对集合中所有控件执行剪切操作,并返回是否全部操作成功。

+

UiCollection.collapse()#

+

对集合中所有控件执行折叠操作,并返回是否全部操作成功。

+

UiCollection.expand()#

+

对集合中所有控件执行展开操作,并返回是否全部操作成功。

+

UiCollection.show()#

+

对集合中所有控件执行显示操作,并返回是否全部操作成功。

+

UiCollection.scrollForward()#

+

对集合中所有控件执行向前滑的操作,并返回是否全部操作成功。

+

UiCollection.scrollBackward()#

+

对集合中所有控件执行向后滑的操作,并返回是否全部操作成功。

+

UiCollection.scrollUp()#

+

对集合中所有控件执行向上滑的操作,并返回是否全部操作成功。

+

UiCollection.scrollDown()#

+

对集合中所有控件执行向下滑的操作,并返回是否全部操作成功。

+

UiCollection.scrollLeft()#

+

对集合中所有控件执行向左滑的操作,并返回是否全部操作成功。

+

UiCollection.scrollRight()#

+

对集合中所有控件执行向右滑的操作,并返回是否全部操作成功。

+

UiCollection.contextClick()#

+

UiCollection.setSelection(start, end)#

+
+

对集合中所有控件设置文字选中区域,并返回是否全部操作成功。

+

UiCollection.setText(text)#

+
+

UiObject#

+

控件, 选择器的findOne方法返回的对象。和UiCollection有相似的方法,不再赘述。除此之外还有以下方法。

+

child(i)#

+
+

返回第i+1个子控件(UiObject)。

+

parent()#

+

返回父控件(UiObject)。

+

children()#

+

返回该控件的所有子控件组成的控件集合。

+

childCount()#

+

返回子控件数目。

+

bounds()#

+

返回控件在屏幕上的范围,其值是一个[Rect]对象。

+

boundsInParent()#

+

返回控件在父控件中的范围,其值是一个[Rect]对象。

+

drawingOrder()#

+

返回控件的绘制次序。

+

id()#

+

返回控件的id,可能为null。

+

text()#

+

返回控件的文本,如果控件没有文本,返回""。

+

findByText(text)#

+
+

根据文本text在子控件中递归地寻找并返回文本或描述(desc)包含这段文本text的控件,返回它们组成的集合。。

+

find(selector)#

+
+

根据选择器selector在子控件中递归地寻找符合条件的控件,返回它们组成的集合。

+

findOne#

+

find(selector)#

+
+

根据选择器selector在子控件中递归地寻找一个符合条件的控件。找不到则返回null。

+

Rect#

+

UiObject.bounds(), UiObject.boundsInParent()返回的对象。表示一个长方形。

+

Rect.left#

+

长方形左边界的x坐标、

+

Rect.right#

+

长方形左边界的x坐标、

+

Rect.top#

+

长方形上边界的y坐标、

+

Rect.bottom#

+

长方形下边界的y坐标、

+

Rect.centerX()#

+

长方形中点x坐标。

+

Rect.centerY()#

+

长方形中点y坐标。

+

Rect.width()#

+

长方形宽度。通常可以作为控件宽度。

+

Rect.height()#

+

长方形高度。通常可以作为控件高度。

+

Rect.contains(r)#

+
+

返回是否包含另一个长方形r。

+

Rect.intersect(r)#

+
+

返回是否和另一个长方形相交。

+ + +

shell即Unix Shell,在类Unix系统提供与操作系统交互的一系列命令。

+

很多程序可以用来执行shell命令,例如终端模拟器。

+

在Auto.js大致等同于用adb执行命令"adb shell"。其实现包括两种方式:

+ +

shell函数#

+
Stability: 2 - Stable

shell(cmd[, root = false])#

+
+

返回运行一个对象表示命令的执行结果。其属性如下:

+ +

示例(强制停止微信) :

+
var result = shell("am force-stop com.tencent.mm", true);
+log(result);
+console.show();
+if(result.code == 0){
+  toast("执行成功");
+}else{
+  toast("执行失败!请到控制台查看错误信息");
+}
+

Shell#

+
Stability: 2 - Stable

shell函数通过用来一次性执行单条命令并获取结果。如果有多条命令需要执行,用Shell对象的效率更高。这是因为,每次运行shell函数都会打开一个单独的shell进程并在运行结束后关闭他,这个过程需要一定的时间;而Shell对象自始至终使用同一个shell进程。

+

Shell(root = false)#

+
+

Shell对象的"构造函数"。

+
var sh = new Shell(true);
+sh.exec("am force-stop com.tencent.mm");
+sh.exit();
+

Shell.exec(cmd)#

+
+

执行命令cmd。该函数不会返回任何值。

+

注意,命令执行是"异步"的、非阻塞的。也就是不会等待命令完成后才继续向下执行。

+

尽管这样的设计使用起来有很多不便之处,但受限于终端模拟器,暂时没有解决方式;如果后续能找到解决方案,则将提供Shell.execAndWaitFor函数。

+

Shell.exit()#

+

直接退出shell。这意味着正在执行的命令会被强制退出。

+

Shell.exitAndWaitFor()#

+

执行"exit"命令并等待执行命令执行完成、退出shell。

+

此函数会执行exit命令来正常退出shell。

+

Shell.setCallback(callback)#

+
+

设置该Shell的回调函数,以便监听Shell的输出。可以包括以下属性:

+ +

例如:

+
var sh = new Shell();
+sh.setCallback({
+    onNewLine: function(line){
+        log(line);
+    }
+})
+while(true){
+    var cmd = dialogs.rawInput("请输入要执行的命令,输入exit退出");
+    if(cmd == "exit"){
+        break;
+    }
+    sh.exec(cmd);
+}
+sh.exit();
+

附录: shell命令简介#

+

以下关于shell命令的资料来自AndroidStudio用户指南:Shell命令

+

am命令#

+

am命令即Activity Manager命令,用于管理应用程序活动、服务等。

+

以下命令均以"am "开头,例如"shell(\"am start -p com.tencent.mm\");"(启动微信)

+

start [options] intent#

+

启动 intent 指定的 Activity(应用程序活动)。
请参阅 intent 参数的规范

+

选项包括:

+ +

startservice [options] intent#

+

启动 intent 指定的 Service(服务)。
请参阅 intent 参数的规范
选项包括:

+ +

force-stop package#

+

强行停止与 package(应用包名)关联的所有应用。

+

kill [options] package#

+

终止与 package(应用包名)关联的所有进程。此命令仅终止可安全终止且不会影响用户体验的进程。
选项包括:

+ +

kill-all#

+

终止所有后台进程。

+

broadcast [options] intent#

+

发出广播 intent。 +请参阅 intent 参数的规范

+

选项包括:

+ +

instrument [options] component#

+

使用 Instrumentation 实例启动监控。通常,目标 component 是表单 test_package/runner_class。
选项包括:

+ +

dumpheap [options] process file#

+

转储 process 的堆,写入 file。

+

选项包括:

+ +

选项包括:

+ +

monitor [options] 启动对崩溃或 ANR 的监控。#

+

选项包括:

+ +

display-size [reset|widthxheight]#

+

替换模拟器/设备显示尺寸。此命令对于在不同尺寸的屏幕上测试您的应用非常有用,它支持使用大屏设备模仿小屏幕分辨率(反之亦然)。
示例:

+
shell("am display-size 1280x800", true);
+

display-density dpi#

+

替换模拟器/设备显示密度。此命令对于在不同密度的屏幕上测试您的应用非常有用,它支持使用低密度屏幕在高密度环境环境上进行测试(反之亦然)。
示例:

+
shell("am display-density 480", true);
+

to-uri intent#

+

将给定的 intent 规范以 URI 的形式输出。 +请参阅 intent 参数的规范

+

to-intent-uri intent#

+

将给定的 intent 规范以 intent:URI 的形式输出。 +请参阅 intent 参数的规范。

+

intent参数的规范#

+

对于采用 intent 参数的 am 命令,您可以使用以下选项指定 intent:

+ +

应用包名#

+

所谓应用包名,是唯一确定应用的标识。例如微信的包名是"com.tencent.mm", QQ的包名是"com.tencent.mobileqq"。
要获取一个应用的包名,可以通过函数getPackageName(appName)获取。参见帮助->其他一般函数。

+

pm命令#

+

pm命令用于管理应用程序,例如卸载应用、冻结应用等。
以下命令均以"pm "开头,例如"shell(\"pm disable com.tencent.mm\");"(冻结微信)

+

list packages [options] filter#

+

输出所有软件包,或者,仅输出包名称包含 filter 中的文本的软件包。
选项:

+ +

list permission-groups#

+

输出所有已知的权限组。

+

list permissions [options] group#

+

输出所有已知权限,或者,仅输出 group 中的权限。
选项:

+ +

list instrumentation [options]#

+

列出所有测试软件包。
选项:

+ +

list features#

+

输出系统的所有功能。

+

list libraries#

+

输出当前设备支持的所有库。

+

list users#

+

输出系统上的所有用户。

+

path package#

+

输出给定 package 的 APK 的路径。

+

install [options] path#

+

将软件包(通过 path 指定)安装到系统。
选项:

+ +

uninstall [options] package#

+

从系统中卸载软件包。
选项:

+ +

enable package_or_component#

+

启用给定软件包或组件(作为“package/class”写入)。

+

disable package_or_component#

+

停用给定软件包或组件(作为“package/class”写入)。

+

disable-user [options] package_or_component#

+

选项:

+ +

revoke package_name permission#

+

从应用中撤销权限。在运行 Android 6.0(API 级别 23)及更高版本的设备上,可以是应用清单中声明的任何权限。在运行 Android 5.1(API 级别 22)和更低版本的设备上,必须是应用定义的可选权限。

+

set-install-location location#

+

更改默认安装位置。位置值:

+ +
+

注:此命令仅用于调试目的;使用此命令会导致应用中断和其他意外行为。

+
+

get-install-location#

+

返回当前安装位置。返回值:

+ +

set-permission-enforced permission [true|false]#

+

指定是否应强制执行给定的权限。

+

trim-caches desired_free_space#

+

减少缓存文件以达到给定的可用空间。

+

create-user user_name#

+

使用给定的 user_name 创建新用户,输出新用户的标识符。

+

remove-user user_id#

+

移除具有给定的 user_id 的用户,删除与该用户关联的所有数据。

+

get-max-users#

+

输出设备支持的最大用户数。

+

其他命令#

+

进行屏幕截图#

+

screencap 命令是一个用于对设备显示屏进行屏幕截图的 shell 实用程序。在 shell 中,此语法为:

+
screencap filename
+

例如:

+
$ shell("screencap /sdcard/screen.png");
+

列表文件#

+
ls filepath
+

例如:

+
log(shell("ls /system/bin").result);
+
+ +

Storages#

+
Stability: 2 - Stable

storages模块提供了保存简单数据、用户配置等的支持。保存的数据除非应用被卸载或者被主动删除,否则会一直保留。

+

storages支持number, boolean, string等数据类型以及把Object, ArrayJSON.stringify序列化存取。

+

storages保存的数据在脚本之间是共享的,任何脚本只要知道storage名称便可以获取到相应的数据,因此它不能用于敏感数据的储存。 +storages无法像Web开发中LocalStorage一样提供根据域名独立的存储,因为脚本的路径随时可能改变。

+

storages.create(name)#

+
+

创建一个本地存储并返回一个Storage对象。不同名称的本地存储的数据是隔开的,而相同名称的本地存储的数据是共享的。

+

例如在一个脚本中,创建名称为ABC的存储并存入a=123:

+
var storage = stroages.create("ABC");
+storage.put("a", 123);
+

而在另一个脚本中是可以获取到ABC以及a的值的:

+
var storage = storages.create("ABC");
+log("a = " + storage.get("a"));
+

因此,本地存储的名称比较重要,尽量使用含有域名、作者邮箱等信息的名称来避免冲突,例如:

+
var storage = storages.create("2732014414@qq.com:ABC");
+

storages.remove(name)#

+
+

删除一个本地存储以及他的全部数据。如果该存储不存在,返回false;否则返回true。

+

Storages#

+

Storage.get(key[, defaultValue])#

+
+

从本地存储中取出键值为key的数据并返回。

+

如果该存储中不包含该数据,这时若指定了默认值参数则返回默认值,否则返回undefined。

+

返回的数据可能是任意数据类型,这取决于使用Storage.put保存该键值的数据时的数据类型。

+

Storage.put(key, value)#

+
+

把值value保存到本地存储中。value可以是undefined以外的任意数据类型。如果value为undefined则抛出TypeError。

+

存储的过程实际上是使用JSON.stringify把value转换为字符串再保存,因此value必须是可JSON化的才能被接受。

+

Storage.remove(key)#

+
+

移除键值为key的数据。不返回任何值。

+

Storage.contains(key)#

+
+

返回该本地存储是否包含键值为key的数据。是则返回true,否则返回false。

+

Storage.clear()#

+

移除该本地存储的所有数据。不返回任何值。 +

+ +

Threads#

+
Stability: 1 - Experiment

threads模块提供了多线程支持。可以启动新线程来运行脚本。新线程会在脚本停止时也自动停止。

+

但是,在新线程中暂时不能使用timers模块的函数,包括setTimeout, setInterval等。而且目前在新线程调用exit()函数时只会退出当前线程。

+

threads.start(action)#

+
+

启动一个新线程并执行action。

+

例如:

+
threads.start(function(){
+    while(true){
+        log("线程2");
+    }
+});
+while(true){
+    log("线程1");
+}
+
+ +

Timers#

+
Stability: 2 - Stable

timers 模块暴露了一个全局的 API,用于在某个未来时间段调用调度函数。 因为定时器函数是全局的,所以使用该 API 无需调用 timers.*

+

Auto.js 中的计时器函数实现了与 Web 浏览器提供的定时器类似的 API,除了它使用了一个不同的内部实现,它是基于 Android Looper-Handler消息循环机制构建的。其实现机制与Node.js比较相似。

+

setImmediate(callback[, ...args])#

+
+

预定立即执行的 callback,它是在 I/O 事件的回调之后被触发。 返回一个用于 clearImmediate() 的 id。

+

当多次调用 setImmediate() 时,callback 函数会按照它们被创建的顺序依次执行。 每次事件循环迭代都会处理整个回调队列。 如果一个立即定时器是被一个正在执行的回调排入队列的,则该定时器直到下一次事件循环迭代才会被触发。

+

setInterval(callback, delay[, ...args])#

+
+

预定每隔 delay 毫秒重复执行的 callback。 返回一个用于 clearInterval() 的 id。

+

当 delay 小于 0 时,delay 会被设为 0。

+

setTimeout(callback, delay[, ...args])#

+
+

预定在 delay 毫秒之后执行的单次 callback。 返回一个用于 clearTimeout() 的 id。

+

callback 可能不会精确地在 delay 毫秒被调用。 Auto.js 不能保证回调被触发的确切时间,也不能保证它们的顺序。 回调会在尽可能接近所指定的时间上调用。

+

当 delay 小于 0 时,delay 会被设为 0。

+

setImmediate()、setInterval() 和 setTimeout() 方法每次都会返回表示预定的计时器的id。 它们可用于取消定时器并防止触发。

+

clearImmediate(id)#

+
+

取消一个由 setImmediate() 创建的 Immediate 对象。

+

clearInterval(id)#

+
+

取消一个由 setInterval() 创建的 Timeout 对象。

+

clearTimeout(id)#

+
+

取消一个由 setTimeout() 创建的 Timeout 对象。

+ + +
diff --git a/app/src/main/assets/docs/app.html b/app/src/main/assets/docs/app.html index b5742798..3246ab92 100644 --- a/app/src/main/assets/docs/app.html +++ b/app/src/main/assets/docs/app.html @@ -25,24 +25,27 @@
diff --git a/app/src/main/assets/docs/console.html b/app/src/main/assets/docs/console.html index 617a84c8..8d85f9c2 100644 --- a/app/src/main/assets/docs/console.html +++ b/app/src/main/assets/docs/console.html @@ -25,24 +25,27 @@
@@ -70,6 +73,7 @@ @@ -170,7 +174,42 @@ if(html.contains("页面跳转中")){

以JSON格式向目标Url发起POST请求。如果没有回调函数,则在请求完成或失败时返回此次请求的响应(参见[Response][])。

JSON格式指的是,将会调用JSON.stringify()把data对象转换为JSON字符串,并在HTTP头部信息中把"Content-Type"属性置为"application/json"。这种方式是AngularJS的ajax函数的默认方式。

一个调用图灵机器人接口的例子如下:

-

http.request(url[, options, callback])#

+

http.postMultipart(url, files[, options, callback])#

+
+

向目标地址发起类型为multipart/form-data的请求(通常用于文件上传等), 其中files参数是<name1: value1, name2: value2, ...>的键值对,value的格式可以是以下几种情况:

+
    +
  1. string
  2. +
  3. 文件类型,即open()返回的类型
  4. +
  5. [fileName, filePath]
  6. +
  7. [fileName, mimeType, filePath]
  8. +
+

其中1属于非文件参数,2、3、4为文件参数。举个例子,最简单的文件上传的请求为:

+
var res = http.postMultipart(url, {
+    file: open("/sdcard/1.txt")
+});
+log(res.body.string());
+

如果使用格式2,则代码为

+
var res = http.postMultipart(url, {
+    file: ["1.txt", "/sdcard/1.txt"]
+});
+log(res.body.string());
+

如果使用格式3,则代码为

+
var res = http.postMultipart(url, {
+    file: ["1.txt", "text/plain", "/sdcard/1.txt"]
+});
+log(res.body.string());
+

如果使用格式2的同时要附带非文件参数"appId=abcdefghijk",则为:

+
var res = http.postMultipart(url, {
+    appId: "adcdefghijk",
+    file: open("/sdcard/1.txt")
+});
+log(res.body.string());
+

http.request(url[, options, callback])#

返回图片image在点(x, y)处的像素的ARGB值。

该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

-

images.saveImage(image, path)#

+

images.save(image, path)#