- Global - 全局对象
- Automator - 自动化
- AutoJs6 - 本体应用
- App - 通用应用
- Color - 颜色
- Image - 图像
- Keys - 按键
- Device - 设备
- Storage - 储存
- File - 文件
- Engine - 引擎
- Task - 任务
- Module - 模块
- Plugins - 插件
- Console - 控制台
- Shell
- Media - 多媒体
- Sensor - 传感器
- Recorder - 记录器
- Timer - 定时器
- Thread - 线程
- Continuation - 协程
- Event - 事件监听
- Dialog - 对话框
- Floaty - 悬浮窗
- Canvas - 画布
- UI - 用户界面
- Web - 万维网
- HTTP
- Base64
- Crypto - 密文
- Internationalization - 国际化
- E4X
AutoJs6 文档 - 6.2.0
目录
- 综述 (Overview)
- 关于文档 (About)
- 疑难解答 (Q & A)
- 全局对象 (Global)
- 覆写保护
- [@] global
- [m] sleep
- [m+] toast
- [m] toastLog
- [m] random
- [m] wait
- [m] waitForActivity
- [m] waitForPackage
- [m] exit
- [m] stop
- [m] isStopped
- [m] isShuttingDown
- [m] isRunning
- [m] notStopped
- [m] requiresApi
- [m] requiresAutojsVersion
- [m] importPackage
- [m] importClass
- [m] currentPackage
- [m] currentActivity
- [m] setClip
- [m] getClip
- [m] selector
- [m] pickup
- [m] detect
- [m] existsAll
- [m] existsOne
- [m] cX
- [m] cY
- [m] cYx
- [m] cXy
- [p] WIDTH
- [p] HEIGHT
- [p+] R
- 自动化 (Automator)
- 基于坐标的触摸模拟
- 安卓7.0以上的触摸和手势模拟
- RootAutomator
- 使用root权限点击和滑动的简单命令
- 基于控件的操作
- SimpleActionAutomator
- AutoJs6 本体应用
- 通用应用 (App)
- app.versionCode
- app.versionName
- app.autojs.versionCode
- app.autojs.versionName
- app.launchApp(appName)
- app.launch(packageName)
- app.launchPackage(packageName)
- app.getPackageName(appName)
- app.getAppName(packageName)
- app.openAppSetting(packageName)
- app.viewFile(path)
- app.editFile(path)
- app.uninstall(packageName)
- app.openUrl(url)
- app.sendEmail(options)
- app.startActivity(name)
- app.intent(options)
- app.startActivity(options)
- app.sendBroadcast(options)
- app.startService(options)
- app.sendBroadcast(name)
- app.intentToShell(options)
- app.parseUri(uri)
- app.getUriForFile(path)
- app.getInstalledApps([options])
- 颜色 (Colors)
- 颜色表示
- [m] toInt
- [m] toHex
- [m] toFullHex
- [m] parseColor
- [m] toString
- [m] alpha
- [m] alphaDouble
- [m] red
- [m] green
- [m] blue
- [m] rgb
- [m] argb
- [m] rgba
- [m] hsva
- [m] hsl
- [m] hsla
- [m] toRgb
- [m] toRgba
- [m] toArgb
- [m] toHsv
- [m] toHsva
- [m] toHsl
- [m] toHsla
- [m] isSimilar
- [m] equals
- [m] luminance
- [p+] android
- [p+] css
- [p+] web
- [p+] material
- [p] BLACK
- [p] BLUE
- [p] CYAN
- [p] AQUA
- [p] DARK_GRAY
- [p] DARK_GREY
- [p] DKGRAY
- [p] GRAY
- [p] GREY
- [p] GREEN
- [p] LIME
- [p] LIGHT_GRAY
- [p] LIGHT_GREY
- [p] LTGRAY
- [p] MAGENTA
- [p] FUCHSIA
- [p] MAROON
- [p] NAVY
- [p] OLIVE
- [p] PURPLE
- [p] RED
- [p] SILVER
- [p] TEAL
- [p] WHITE
- [p] YELLOW
- [p] TRANSPARENT
- 图像 (Images)
- 图片处理
- images.read(path)
- images.load(url)
- images.copy(img)
- images.save(image, path[, format = "png", quality = 100])
- images.fromBase64(base64)
- images.toBase64(img[, format = "png", quality = 100])
- images.fromBytes(bytes)
- images.toBytes(img[, format = "png", quality = 100])
- images.clip(img, x, y, w, h)
- images.resize(img, size[, interpolation])
- images.scale(img, fx, fy[, interpolation])
- images.rotate(img, degress[, x, y])
- images.concat(img1, image2[, direction])
- images.grayscale(img)
- image.threshold(img, threshold, maxVal[, type])
- images.adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C)
- images.cvtColor(img, code[, dstCn])
- images.inRange(img, lowerBound, upperBound)
- images.interval(img, color, interval)
- images.blur(img, size[, anchor, type])
- images.medianBlur(img, size)
- images.gaussianBlur(img, size[, sigmaX, sigmaY, type])
- images.matToImage(mat)
- 找图找色
- images.requestScreenCapture([landscape])
- images.captureScreen()
- images.captureScreen(path)
- images.pixel(image, x, y)
- images.findColor(image, color, options)
- images.findColorInRegion(img, color, x, y[, width, height, threshold])
- images.findColorEquals(img, color[, x, y, width, height])
- images.findMultiColors(img, firstColor, colors[, options])
- images.detectsColor(image, color, x, y[, threshold = 16, algorithm = "diff"])
- images.findImage(img, template[, options])
- images.findImageInRegion(img, template, x, y[, width, height, threshold])
- images.matchTemplate(img, template, options)
- MatchingResult
- Image
- Point
- 按键 (Keys)
- 附录: KeyCode对照表
- 设备 (Device)
- device.width
- device.height
- device.buildId
- device.broad
- device.brand
- device.device
- device.model
- device.product
- device.bootloader
- device.hardware
- device.fingerprint
- device.serial
- device.sdkInt
- device.incremental
- device.release
- device.baseOS
- device.securityPatch
- device.codename
- device.getIMEI()
- device.getAndroidId()
- device.getMacAddress()
- device.getBrightness()
- device.getBrightnessMode()
- device.setBrightness(b)
- device.setBrightnessMode(mode)
- device.getMusicVolume()
- device.getNotificationVolume()
- device.getAlarmVolume()
- device.getMusicMaxVolume()
- device.getNotificationMaxVolume()
- device.getAlarmMaxVolume()
- device.setMusicVolume(volume)
- device.setNotificationVolume(volume)
- device.setAlarmVolume(volume)
- device.getBattery()
- device.isCharging()
- device.getTotalMem()
- device.getAvailMem()
- device.isScreenOn()
- device.wakeUp()
- device.wakeUpIfNeeded()
- device.keepScreenOn([timeout])
- device.keepScreenDim([timeout])
- device.cancelKeepingAwake()
- device.vibrate(millis)
- device.cancelVibration()
- 存储 (Storages)
- Storages
- 文件 (Files)
- files.isFile(path)
- files.isDir(path)
- files.isEmptyDir(path)
- files.join(parent, child)
- files.create(path)
- files.createWithDirs(path)
- files.exists(path)
- files.ensureDir(path)
- files.read(path[, encoding = "utf-8"])
- files.readBytes(path)
- files.write(path, text[, encoding = "utf-8"])
- files.writeBytes(path, bytes)
- files.append(path, text[, encoding = 'utf-8'])
- files.appendBytes(path, text[, encoding = 'utf-8'])
- files.copy(fromPath, toPath)
- files.move(fromPath, toPath)
- files.rename(path, newName)
- files.renameWithoutExtension(path, newName)
- files.getName(path)
- files.getNameWithoutExtension(path)
- files.getExtension(path)
- files.remove(path)
- files.removeDir(path)
- files.getSdcardPath()
- files.cwd()
- files.path(relativePath)
- files.listDir(path[, filter])
- open(path[, mode = "r", encoding = "utf-8", bufferSize = 8192])
- ReadableTextFile
- PWritableTextFile
- 引擎 (Engines)
- ScriptExecution
- ScriptEngine
- ScriptConfig
- 任务 (Tasks)
- 模块 (Module)
- 插件 (Plugins)
- 协程 (Continuation)
- 控制台 (Console)
- console.show()
- console.hide()
- console.clear()
- console.log([data][, ...args])
- console.verbose([data][, ...args])
- console.info([data][, ...args])
- console.warn([data][, ...args])
- console.error([data][, ...args])
- console.assert(value, message)
- console.time([label])
- console.timeEnd(label)
- console.trace([data][, ...args])
- console.input(data[, ...args])
- console.rawInput(data[, ...args])
- console.setSize(w, h)
- console.setPosition(x, y)
- console.setGlobalLogConfig(config)
- print(text)
- Shell
- shell函数
- Shell
- 附录: shell命令简介
- am命令
- start [options] intent
- startservice [options] intent
- force-stop package
- kill [options] package
- kill-all
- broadcast [options] intent
- instrument [options] component
- dumpheap [options] process file
- monitor [options] 启动对崩溃或 ANR 的监控.
- screen-compat { on | off } package
- display-size [reset|widthxheight]
- display-density dpi
- to-uri intent
- to-intent-uri intent
- intent参数的规范
- 应用包名
- pm命令
- list packages [options] filter
- list permission-groups
- list permissions [options] group
- list instrumentation [options]
- list features
- list libraries
- list users
- path package
- install [options] path
- uninstall [options] package
- clear package
- enable package_or_component
- disable package_or_component
- disable-user [options] package_or_component
- grant package_name permission
- revoke package_name permission
- set-install-location location
- get-install-location
- set-permission-enforced permission [true|false]
- trim-caches desired_free_space
- create-user user_name
- remove-user user_id
- get-max-users
- 其他命令
- am命令
- 多媒体 (Media)
- 传感器 (Sensors)
- SensorEventEmitter
- 记录器 (Recorder)
- 定时器 (Timers)
- 线程 (Threads)
- Thread
- 线程安全
- 线程通信
- 事件监听 (Events)
- events.emitter()
- events.observeKey()
- events.onKeyDown(keyName, listener)
- events.onKeyUp(keyName, listener)
- events.onceKeyDown(keyName, listener)
- events.onceKeyUp(keyName, listener)
- events.removeAllKeyDownListeners(keyName)
- events.removeAllKeyUpListeners(keyName)
- events.setKeyInterceptionEnabled([key, ]enabled)
- events.observeTouch()
- events.setTouchEventTimeout(timeout)
- events.getTouchEventTimeout()
- events.onTouch(listener)
- events.removeAllTouchListeners()
- 事件: 'key'
- 事件: 'key_down'
- 事件: 'key_up'
- 事件: 'exit`
- events.observeNotification()
- events.observeToast()
- 事件: 'toast'
- 事件: 'notification'
- Notification
- KeyEvent
- keys
- EventEmitter
- EventEmitter.defaultMaxListeners
- EventEmitter.addListener(eventName, listener)
- EventEmitter.emit(eventName[, ...args])
- EventEmitter.eventNames()
- EventEmitter.getMaxListeners()
- EventEmitter.listenerCount(eventName)
- EventEmitter.listeners(eventName)
- EventEmitter.on(eventName, listener)
- EventEmitter.once(eventName, listener)
- EventEmitter.prependListener(eventName, listener)
- EventEmitter.prependOnceListener(eventName, listener)
- EventEmitter.removeAllListeners([eventName])
- EventEmitter.removeListener(eventName, listener)
- EventEmitter.setMaxListeners(n)
- events.broadcast: 脚本间广播
- 对话框 (Dialogs)
- dialogs.alert(title[, content, callback])
- dialogs.confirm(title[, content, callback])
- dialogs.rawInput(title[, prefill, callback])
- dialogs.input(title[, prefill, callback])
- dialogs.prompt(title[, prefill, callback])
- dialogs.select(title, items, callback)
- dialogs.singleChoice(title, items[, index, callback])
- dialogs.multiChoice(title, items[, indices, callback])
- dialogs.build(properties)
- Dialog
- 悬浮窗 (Floaty)
- FloatyWindow
- FloatyRawWindow
- 画布 (Canvas)
- canvas.getWidth()
- canvas.getHeight()
- canvas.drawRGB(r, int g, int b)
- canvas.drawARGB(a, r, g, b)
- canvas.drawColor(color)
- canvas.drawColor(color, mode)
- canvas.drawPaint(paint)
- canvas.drawPoint(x, y, paint)
- canvas.drawPoints(pts, paint)
- canvas.drawLine(startX, startY, stopX, stopY, paint)
- canvas.drawRect(r, paint)
- canvas.drawRect(left, top, right, bottom, android.graphics.Paint paint)
- canvas.drawOval(android.graphics.RectF oval, android.graphics.Paint paint)
- canvas.drawOval(float left, float top, float right, float bottom, android.graphics.Paint paint)
- canvas.drawCircle(float cx, float cy, float radius, android.graphics.Paint paint)
- canvas.drawArc(android.graphics.RectF oval, float startAngle, float sweepAngle, boolean useCenter, android.graphics.Paint paint)
- canvas.drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, android.graphics.Paint paint)
- canvas.drawRoundRect(android.graphics.RectF rect, float rx, float ry, android.graphics.Paint paint)
- canvas.drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, android.graphics.Paint paint)
- canvas.drawPath(android.graphics.Path path, android.graphics.Paint paint)
- canvas.drawBitmap(android.graphics.Bitmap bitmap, float left, float top, android.graphics.Paint paint)
- canvas.drawText(java.lang.String text, float x, float y, android.graphics.Paint paint)
- canvas.drawTextOnPath(java.lang.String text, android.graphics.Path path, float hOffset, float vOffset, android.graphics.Paint paint)
- canvas.translate(dx, dy)
- canvas.scale(sx, sy)
- canvas.scale(float sx, float sy, float px, float py)
- canvas.rotate(float degrees)
- canvas.rotate(float degrees, float px, float py)
- canvas.skew(float sx, float sy)
- 画笔
- 变换矩阵
- 路径
- Porter-Duff操作
- 着色器
- 遮罩过滤器
- 颜色过滤器
- 路径特效
- 区域
- 用户界面 (UI)
- 视图: View
- 文本控件: text
- 按钮控件: button
- 输入框控件: input
- 图片控件: img
- 垂直布局: vertical
- 水平布局: horizontal
- 线性布局: linear
- 帧布局: frame
- 相对布局: relative
- 勾选框控件: checkbox
- 选择框控件: radio
- 选择框布局: radiogroup
- 开关控件: Switch
- 进度条控件: progressbar
- 拖动条控件: seekbar
- 下来菜单控件: spinner
- 时间选择控件: timepicker
- 日期选择控件: datepicker
- 浮动按钮控件: fab
- 标题栏控件: toolbar
- 卡片: card
- 抽屉布局: drawer
- 列表: list
- Tab: tab
- ui
- ui.registerWidget(name, widget)
- ui.isUiThread()
- 尺寸的单位: Dimension
- Drawables
- 颜色
- 万维网 (Web)
- HTTP
- Response
- Base64
- 密文 (Crypto)
- 国际化 (Internationalization)
- E4X
综述 (Overview)#
AutoJs6: 安卓平台 JavaScript 自动化工具.
- 脚本语言: JavaScript
- 脚本引擎: Rhino
- 支持特性: ES5 (全部), ES6 (部分)
扩展阅读:
- 了解 JavaScript
- 查看 Rhino 引擎兼容性列表
- 使用 PC (个人计算机) 开发
- 使用 Node.js 开发
- 使用 TypeScript 开发
阅读文档:
- 宽屏设备网页阅读
- 点击左侧边栏条目 - 阅读相关章节
- 移动设备网页阅读
- 点击左下方抽屉按钮 - 展开侧边栏并点击条目 - 阅读相关章节
- AutoJs6 阅读
- 点击首页 "文档" 标签 - 点击条目 - 阅读相关章节
- 点击首页右上方 "搜索" 图标 - 在当前页面检索内容
- 文档页面左上方的导航链接可实现页面跳转:
- 点击 "索引" - 跳转至章节索引页面
- 点击 "查看全部" - 所有章节内容在同一页面列出
- 阅读文档时, "文档" 标签可作为快捷按钮使用:
- 点击 "文档" 标签 - 返回至当前页面顶部
- 长按 "文档" 标签 - 跳转至章节索引页面
注: 初次阅读文档或首次使用 AutoJs6 建议从 关于文档 开始.
关于文档 (About)#
AutoJs6 文档, 包含模块 API 使用方法及用例.
项目复刻 (Fork) 自 hyb1996/AutoJs-Docs (GitHub).
项目地址: SuperMonster003/AutoJs6-Documentation (GitHub).
文档阅读示例#
基础#
device.height#
device 表示全局对象 (这里同时也是一个模块).
".height" 表示访问 device 对象的 height 成员变量.
如 console.log(device.height) 表示在控制台打印当前设备的高度数值.
colors.rgb(red, green, blue)#
colors 与 device 类似, 表示全局对象.
"rgb" 表示方法名称, ".rgb()" 表示调用 colors 的 rgb 方法, 括号内的 red 等表示方法参数.
如 console.log(colors.rgb(255, 128, 64)) 表示在控制台打印一个 RGB 分别为 255, 128 和 64 的颜色数值.
临时作用域对象#
通常每个章节都以某个对象作为主题.
例如上述 colors.rgb(red, green, blue) 位于 Color - 颜色 这个章节.
其中 colors 称为此章节的 "临时作用域对象",
它可能是一个对象, 函数, 甚至 "类", 在文档中使用 橙色粗体 表示.
列举其后续的相关方法及属性时, 将不再重复书写对象本身:
colors
[m] rgb
rgb(red, green, blue)
... ...
上述 rgb 表示 colors.rgb.
参数类型#
colors.rgb(red, green, blue)#
参数后的 "{}" 内包含其类型.
上述示例表示需要传入三个 number 类型的参数.
如 colors.rgb(255, 128, 64) 合法, 而 colors.rgb("abc", 128, 64) 将可能导致非预期结果或出现异常.
注: 点击类型对应的超链接 (如有) 可跳转至类型详情页面.
返回值类型#
colors.rgb(red, green, blue)#
returns 后的 "{}" 内包含返回值类型.
上述示例表示 colors.rgb 方法调用后将返回 number 类型数据.
属性类型#
colors.RED#
- { number }
属性类型包裹在一对花括号中.
上述示例表示 colors 的 RED 属性是 number 类型数据.
对象字面量形式的类型则用一对双花括号表示:
多行形式:
一个符合上述示例期望的变量:
let o = { name: "David", age: 13 };
可存取的属性在读取时如果有非 undefined 默认值, 则以一对方括号表示:
- [ 1200 ] { number }
上述示例表示一个默认值为 1200 的可存取属性.
以一对双方括号表示常量:
- [[ 0.5 ]] { number }
上述示例表示一个值为 0.5 的常量属性.
方法签名#
形如上述 返回值类型 小节的示例,
包含 [ 方法名称 + 参数类型 + 返回值类型 ] 的标志符, 称为 "方法签名".
注: 上述 "方法签名" 定义只用于辅助读者对文档的理解, 并不保证名词解释的合理性.
方法描述#
colors.rgb(red, green, blue)#
- red - R (红色) 通道数值 [ A ]
- green - G (绿色) 通道数值 [ A ]
- blue - B (蓝色) 通道数值 [ A ]
- @return - 颜色数值 [ B ]
获取 R/G/B 通道组合后的颜色数值. [ C ]
[ D ]
colors.rgb(255, 128, 64); // -32704
colors.rgb(255, 128, 64) === 0xFFFF8040 - Math.pow(2, 32); // true
colors.rgb(255, 128, 64) === colors.toInt("#FFFF8040"); // true
colors.rgb(255, 128, 64) === colors.toInt("#FF8040"); // true
上述示例包含的字母标注含义:
- [ A ] - 参数描述
- [ B ] - 方法返回值描述
- [ C ] - 方法描述
- [ D ] - 方法使用示例
可变参数#
files.join(parent, ...child)#
上述示例的 child 参数是 "可变参数", 也称为 "可变长参数" 或 "变长参数".
可变参数可传入任意个 (包括 0 个) 参数:
let p = files.getSdcardPath();
files.join(p); /* 0 个可变参数 */
files.join(p, 'a'); /* 1 个可变参数 */
files.join(p, 'a', 'b', 'c', 'd'); /* 4 个可变参数 */
文档采用 JSDoc 标准标注可变参数, 需额外注意 JSDoc 的尾数组标识代表容器, 用于容纳展开后的参数:
/**
* @param {number} x
* @param {number} y
* @param {...number[]} others
*/
function sum(x, y, others) {
/* ... */
}
上述示例 others 参数为可变参数, 其中 "...number[]" 代表 others 期望的参数类型为 number, 而非 number[], 最后的 "[]" 代表 "..." 的容器, "..." 与 "[]" 是配对出现的.
/**
* @param {number} x
* @param {number} y
* @param {...number[][]} others
*/
function sum(x, y, others) {
/* ... */
}
上述示例 others 期望的参数类型为 number[], 而非 number[][], 同样最后的 "[]" 代表 "..." 的容器.
/**
* @param {number} x
* @param {number} y
* @param {...number} others
*/
function sum(x, y, others) {
/* ... */
}
上述示例 others 的参数类型标识方法 "...number" 也是合法的, 它其实是 "...number[]" 的省略形式.
文档为了避免歧义, 将全部采用完整写法.
作为强调, "...(SomeType)[]" 这样的可变参数表示方法, 需要把 "..." 和 "[]" 视为一个整体, 中间部分才是期望的参数类型.
可选参数#
device.vibrate(text, delay?)#
上述示例的 delay 参数是可选的 (以 "?" 标注).
因此以下调用方式均被支持:
device.vibrate("hello", 2e3); /* 两秒钟延迟. */
device.vibrate("hello"); /* 无延迟. */
可选参数描述时会以 "[]" 标注:
- [ delay ] { number }
如果可选参数包含默认值, 则会以 "=" 标注:
- [ delay = 0 ] { number }
详见下述 参数默认值
参数默认值#
device.vibrate(text, delay?)#
上述示例的 delay 参数是可选的 (以 "?" 标注) 且包含默认值 (以 "=" 标注).
因此以下两种调用方式等效:
device.vibrate("hello");
device.vibrate("hello", 0);
注: 上述示例的方法签名 (含默认值标注) 在 TypeScript 中并不合法, 此类签名仅限在文档中使用.
注: 以 "=" 标注的参数一定是可选的, 此时参数的 "?" 标注可能被省略, 尤其在重载签名拆写的情况下.
详情参阅下文的 "方法重载".
方法重载#
Overload 1/17
pickup(selector, compass, resultType)#
Overload 2/17
pickup(selector, compass)#
Overload 3/17
pickup(selector, resultType)#
... ...
Overload 16/17
pickup(root, selector)#
Overload 17/17
pickup()#
包含 "Overload m/n" 标签的方法, 表示重载方法的序数及总量.
如 "Overload 2/3" 表示当前方法签名描述第 2 个重载方法, 总计 3 个,
而 "Overload 5-6/17" 表示当前方法签名涵盖第 5 及 第 6 个重载方法, 总计 17 个.
重载方法可被简化:
/* 拆写. */
device.vibrate(text)
device.vibrate(text, delay)
/* 合写 (简化). */
device.vibrate(text, delay?)
/* 可选参数通常会标注默认值. */
device.vibrate(text, delay?)
· [ delay = 0 ] { number }
/* 即使没有 "?" 标注 (针对拆写). */
device.vibrate(text, delay)
· [ delay = 0 ] { number }
多数情况下, 文档采用拆写的方式描述重载方法.
方法全局化#
Global
images.requestScreenCapture(landscape)#
包含 "Global" 标签的方法, 表示支持全局化使用, 可省略模块对象调用.
因此以下两种调用方式等效:
images.requestScreenCapture(false);
requestScreenCapture(false);
方法标签#
用于简便表示方法的特性:
Global: 方法全局化 (可省略模块对象直接调用).Overload 2/3: 方法重载 [ 第 2 个, 共 3 个 ].Non-UI: 方法不能在 UI 模式下调用.6.2.0: 方法对 AutoJs6 的版本要求 [ 不低于 6.2.0 ].[6.2.0]: 与原同名方法相比, 方法的功能, 结果, 签名或使用方式发生变更的起始版本.API>=29: 方法对 API 级别 的要求 [ 不低于 29 ], 当不满足时不抛出异常.API>=29!: 方法对 API 级别 的要求 [ 不低于 29 ], 当不满足时将抛出异常.A11Y: 方法依赖无障碍服务.A11Y?: 方法可能会依赖无障碍服务.Async: 异步执行的方法.Async?: 可能异步执行的方法 (通过参数控制).Getter: 仅取值属性, 即使用 Getter 定义的对象属性.Setter: 仅存值属性, 即使用 Setter 定义的对象属性.Getter/Setter: 可存值且可取值属性, 即同时使用 Setter 及 Getter 定义的对象属性.Enum: 枚举类.CONSTANT: 常量.DEPRECATED: 已弃用的属性或方法.xProto: 针对原型的内置对象扩展.xObject: 针对对象的内置对象扩展.xAlias: 内置对象扩展时使用不同的方法或属性名称 (别名).
对象标签#
用于简便表示对象的属性:
- [m]: 普通对象方法或类静态成员方法.
- 例如在
images作为 临时作用域对象 时: [m] captureScreen代表images.captureScreen方法.
- 例如在
- [m+]: 具有扩展属性的对象方法.
- 如 auto 本身是一个方法 (或称函数), waitFor 是 auto 的一个扩展方法.
- 以下两种调用方式均可用:
auto()及auto.waitFor().
- [p]: 属性.
- 例如在
device作为 临时作用域对象 时: [p] height代表device.height属性, 而非方法.- 此标签对 [ Getter / Setter / "类" 属性 / 对象属性 / 方法扩展属性 ] 等不作区分.
- 例如在
- [p+]: 具有扩展属性的对象属性.
- 如 autojs 是一个对象, version 是 autojs 的扩展属性,
- 支持
autojs.version.xxx这样的访问方式, - 因此 version 属性将被标记为
[p+].
- [I]: Java 接口.
- [C]: Java 类或 JavaScript 构造函数.
- [c]: Java 类的构造方法.
- [m!]: 抽象方法 (针对接口及抽象类).
- [m=]: 包含默认实现的抽象方法 (针对接口).
- [m#]: 类的实例成员方法.
- 类的静态成员方法用 [m] 标签标记.
- 例如对于类
B, 它有一个实例b(可能通过new B()等方式获得), [m#] foo和[m] bar的调用方式分别为b.foo()和B.bar().
- [p#]: 类的实例成员属性.
- 类的静态成员属性依然用 [p] 标签标记.
- 例如对于类
F, 它有一个实例f(可能通过new F()等方式获得), [p#] foo和[p] bar的调用方式分别为f.foo和F.bar.
- [@]: 代表 临时作用域对象 自身.
- 例如在同一个章节中
[@] apple[1]apple(c)[2][m] getColor[3]getColor()[4][@] banana[5][m] banana[6]banana(x)[7]banana(x, y)[8]
- 这个章节有两个 临时作用域对象, apple 和 banana, 对应
[1]和[5]. [2]代表 apple 自身可被调用, 且调用方式为apple(c), 其中 "c" 为参数.[3]代表 apple 的一个方法, 名称为 "getColor",- 由
[4]得知, 其调用方式为apple.getColor(). - 注意
[6]与[2]不同: - [
6] 代表 banana 的一个方法, 名称为 "banana", - 由
[7]和[8]得知, 其调用方式有两种, banana.banana(x)和banana.banana(x, y).
- 例如在同一个章节中
成员访问#
成员访问用 "." 表示调用关系, 包括 "类" 静态成员访问, 对象成员访问等.
而实例成员访问则需要 "类" 的实例才能访问, 用 "#" 表示调用关系.
例如 JavaScript 的 Number 本身是一个 "类", 可用的成员访问方式如下:
Number(2); /* 作为普通函数使用, 无成员访问. */
Number.EPSILON; /* "类" 静态成员访问, 用 "Number.EPSILON" 标识, 标签为 "[p]". */
new Number(2); /* 创建 "类" 实例, 无成员访问. */
new Number(2).toFixed(0); /* 实例成员访问, 用 "Number#toFixed(number)" 标识, 标签为 "[m#]". */
实例成员访问示例:
UiObject
[m#] bounds()
/* 正确访问示例 */
let w = pickup(/.+/); /* w 是 UiObject 的实例. */
if (w !== null) {
console.log(w.bounds()); /* 访问 UiObject 实例的 bounds 方法. */
}
/* 错误访问示例 */
importClass(org.autojs.autojs.core.automator.UiObject);
console.log(UiObject.bounds()); /* 访问的是类 UiObject 的静态方法 bounds. */
模板参数#
foo.bar(a, b)#
returns 后的 "{}" 内包含返回值类型.
上述示例表示 colors.rgb 方法调用后将返回 number 类型数据.
参阅: 泛型
声明#
当前项目 (文档) 及 AutoJs6 (App) 均为二次开发.
相对于 原始 App, 二次开发的 App 中会增加或修改部分模块功能.
相对于 原始文档, 二次开发的文档将进行部分增删或重新编写.
开发者无法保证对 API 的完全理解及文档的无纰漏撰写.
如有任何不当之处, 欢迎提交 Issue 或 PR.
疑难解答 (Q & A)#
图像#
区域截图#
AutoJs6 不支持区域截图.
只能通过 images.captureScreen 截取屏幕后使用 images.clip 等方式做进一步处理.
定时任务#
定时运行脚本#
脚本右侧菜单 -> 定时任务, 即可定时运行脚本.
需保持 AutoJs6 后台运行, 包括 [ 自启动白名单 / 忽略电池优化 / 忽略后台活动限制 / 系统多任务保留 ] 等.
在设备关屏情况下, 可使用 device.wakeUp() 唤醒屏幕.
但 AutoJs6 暂未提供解锁功能, 因此可能需要根据设备自行设计解锁代码.
定时任务获取外部参数#
若脚本由 intent (如网络状态变化等特定事件) 触发启动, 可通过 engines.myEngine().execArgv.intent 获取 intent, 进而获取外部参数.
打包应用#
图片等资源共同打包及多脚本打包#
上述需求需使用 "项目" 功能.
点击 AutoJs6 主页面 "+" 图标, 选择项目, 填写信息后可新建一个项目.
项目支持存放多个 [ 脚本 / 模块 / 资源文件 ].
项目工具栏的 APK 打包图标, 点击可打包一个项目.
例如:
脚本读取同目录 1.png: images.read("./1.png").
UI 脚本图片控件引用同目录 2.png: <img src="file://2.png"/>.
AutoJs6 内置模块支持相对路径引用, 其他情况可能需借助 files.path() 转换为绝对路径.
打包应用不显示主界面#
需使用 "项目" 功能.
新建项目后, 在项目目录 project.json 文件中增加以下条目:
{
"launchConfig": {
"hideLogs": true
}
}
例如:
{
"name": "First-Project",
"versionName": "1.0.0",
"versionCode": 1,
"packageName": "org.autojs.example.first",
"main": "main.js",
"launchConfig": {
"hideLogs": true
}
}
功能扩展#
AutoJs6 支持直接调用 [ Java / Android / 扩展库 ] 等 API.
对于 AutoJs6 没有内置的功能, 可进行 Java 脚本化, 即直接参照 Java (或 Kotlin 等) 源码, 转换为 JavaScript 代码.
例如:
import android.graphics.Bitmap;
import android.graphics.Matrix;
public static Bitmap rotate(Bitmap src, int degrees, float px, float py) {
if (degrees == 0) return src;
Matrix matrix = new Matrix();
matrix.setRotate(degrees, px, py);
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
return ret;
}
转换为 JavaScript 代码:
importClass(android.graphics.Bitmap);
importClass(android.graphics.Matrix);
function rotate(src, degrees, px, py) {
if (degrees == 0) return src;
let matrix = new Matrix();
matrix.setRotate(degrees, px, py);
let ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
return ret;
}
关于脚本化 Java 的更多信息, 参阅 Scripting Java - 脚本化 Java 章节.
全局对象 (Global)#
在 JavaScript 中, 几乎一切都是对象.
此处的全局 "对象" 包括 [ 变量 / 方法 / 构造器 ] 等.
全局对象随处可用, 包括 ECMA 标准内置对象 (如 [ Number / RegExp / String ] 等).
AutoJs6 的内置模块均支持全局使用, 如 app, images, device 等.
为便于使用, 一些 AutoJs6 模块中的方法也被全局化,
如 images.captureScreen(), dialogs.alert(), app.launch() 等.
全局化方法均以 Global 标签标注.
脚本文件可直接运行使用, 也可作为模块被导入使用 (require 方法).
当作为模块使用时, exports 和 module 可作为全局对象使用.
另在 UI 模式下也有一些专属全局对象, 如 activity.
覆写保护#
AutoJs6 对部分全局对象及内置模块增加了覆写保护.
以下全局声明或赋值将导致异常或非预期结果:
/* 以全局对象 selector 为例. */
/* 声明无效. */
let selector = 1; /* 异常: 变量 selector 重复声明. */
const selector = 1; /* 同上. */
var selector = 1; /* 同上. */
/* 覆写无效 (非严格模式). */
selector = 1;
typeof selector; // "function" - 静默失败, 覆写未生效.
/* 覆写无效 (严格模式). */
"use strict";
selector = 1; /* 异常: 无法修改只读属性: selector. */
局部作用域不受上述情况影响:
(function () {
let selector = 1;
return typeof selector;
})(); // "number"
截至目前 (2022/10) 受覆写保护的对象有:
selector
continuation
global
[@] global#
global 为 AutoJs6 的默认顶级作用域对象, 可作为全局对象使用:
typeof global; // "object"
typeof global.sleep; // "function"
另, 访问顶级作用域对象也可通过以下代码:
runtime.topLevelScope;
runtime.topLevelScope 本身有 "global" 属性, 因此全局对象 global 也一样拥有:
typeof runtime.topLevelScope.global; // "object"
global.global === global; // true
global.global.global.global === global; // true
global 对象可以增加属性, 也可以覆写甚至删除属性 (部分被保护):
global.hello = "hello";
delete global.hello;
global 对象本身是可被覆写的:
typeof global; // "object"
global = 3;
typeof global; // "number"
如果 global 对象被意外重写 (虽然概率很低),
可通过 runtime.topLevelScope 访问或还原:
global = 3; /* 覆写 global 对象. */
typeof global; // "number"
typeof global.sleep; // "undefined"
typeof runtime.topLevelScope.sleep; // "function"
global = runtime.topLevelScope; /* 还原 global 对象. */
typeof global; // "object"
typeof global.sleep; // "function"
[m] sleep#
sleep(millis)#
Global Overload 1/3 Non-UI
使当前线程休眠一段时间.
/* 休眠 9 秒钟. */
sleep(9000);
/* 休眠 9 秒钟 (使用科学计数法). */
sleep(9e3);
sleep(millisMin, millisMax)#
6.2.0 Global Overload 2/3 Non-UI
使当前线程休眠一段时间, 该时间随机落在 millisMin 和 millisMax 之间.
/* 随机休眠 3 - 5 秒钟. */
sleep(3e3, 5e3);
sleep(millis, bounds)#
6.2.0 Global Overload 3/3 Non-UI
- millis { number } - 休眠时间 (毫秒)
- bounds { NumberString | string } - 浮动值
- returns { void }
使当前线程休眠一段时间, 该时间随机落在 millis ± bounds 之间.
bounds 参数为 数字字符串 类型 (如 "12"), 或在字符串开头附加 "±" 明确参数含义 (如 "±12").
/* 随机休眠 3 - 5 秒钟 (即 4 ± 1 秒钟). */
sleep(4e3, "1e3");
sleep(4e3, "±1e3"); /* 同上. */
[m+] toast#
toast(text)#
Global Overload 1/4 Async
显示一个 消息浮动框.
消息框的显示默认是依次进行的:
/* 显示消息框 2 秒钟. */
toast("hello");
/* 显示消息框 2 秒钟, 且在前一个消息框消失后才显示. */
toast("world");
/* 显示消息框 2 秒钟, 且在前一个消息框消失后才显示. */
toast("hello world");
toast(text, isLong)#
Global Overload 2/4 Async
- text { string } - 消息内容
- isLong = false { "long" | "l" | "short" | "s" | boolean } - 是否以较长时间显示
- returns { void }
控制单个消息框显示时长:
toast("hello", 'long'); /* 显示消息框 3.5 秒钟. */
toast("hello", true); /* 同上. */
注: 仅有 [ 长 / 短 ] 两种时长, 此时长由安卓系统决定.
通常, 短时为 2 秒, 长时为 3.5 秒.
toast(text, isLong, isForcible)#
Global Overload 3/4 Async
- text { string } - 消息内容
- isLong = false { "long" | "l" | "short" | "s" | boolean } - 是否以较长时间显示
- isForcible = false { "forcible" | "f" | boolean } - 是否强制覆盖显示
- returns { void }
使用 "强制覆盖显示" 参数可立即显示消息框:
toast("hello");
/* 显示消息框 2 秒钟, 且立即显示, 前一个消息框 "hello" 被 "覆盖". */
toast("world", "short", "forcible");
注: 强制覆盖仅对当前脚本有效, 对其他脚本及应用程序无效.
toast(text, isForcible)#
Global Overload 4/4 Async
此方法相当于忽略 isLong 参数:
toast("hello");
/* 显示消息框 2 秒钟, 且立即显示, 前一个消息框 "hello" 被 "覆盖". */
toast("world", "forcible");
注: 此方法的 isForcible 参数只能为具有明确意义的字符标识, 不能为 boolean 类型或其他类型, 否则 isForcible 将被视为 isLong.
toast.dismissAll()#
Global - returns { void }
强制取消显示所有消息框.
toast("hello");
toast("world");
toast("of");
toast("JavaScript");
sleep(1e3);
/* "hello" 显示 1 秒后消失, "world" 及其他消息框均不再显示. */
/* 若无 sleep 语句, 由于 toast 是异步的, 上述消息框均不会显示. */
toast.dismissAll();
/* dismissAll 仅对已在队列中的消息框有效, 因此下述消息框正常显示. */
toast("forcibly dismissed");
注: 强制取消显示仅对当前脚本有效, 对其他脚本及应用程序无效.
[m] toastLog#
显示消息浮动框并在控制台打印消息.
相当于以下代码组合:
toast(text, ...args);
console.log(text);
因此, 方法重载与 toast 完全一致.
注: 虽然 toast 方法异步, 但 console.log 方法同步, 因此 toastLog 方法也为同步.
toastLog(text)#
Global Overload 1/4
参阅: toast(text)
toastLog(text, isLong)#
Global Overload 2/4
- text { string } - 消息内容
- isLong = false { "long" | "l" | "short" | "s" | boolean } - 是否以较长时间显示
- returns { void }
toastLog(text, isLong, isForcible)#
Global Overload 3/4
- text { string } - 消息内容
- isLong = false { "long" | "l" | "short" | "s" | boolean } - 是否以较长时间显示
- isForcible = false { "forcible" | "f" | boolean } - 是否强制覆盖显示
- returns { void }
toastLog(text, isForcible)#
Global Overload 4/4
[m] random#
random()#
Global Overload 1/2
- returns { number }
与 Math.random() 相同, 返回落在 [0, 1) 区间的随机数字.
random(min, max)#
Global Overload 2/2
返回落在 [min, max] 区间的随机数字.
注: random(min, max) 右边界闭合, 而 random() 右边界开放.
[m] wait#
wait(condition)#
6.2.0 Global Overload 1/6 A11Y? Non-UI
- condition { (() => any) | PickupSelector } - 结束等待条件
- returns { boolean }
阻塞等待, 直到条件满足.
默认等待时间为 10 秒, 条件检查间隔为 200 毫秒.
若超时, 放弃等待, 并返回特定的条件超时结果 (如 false).
若超时之前条件得以满足, 结束等待, 并返回特定的条件满足结果 (如 true).
注: 不同于 while 和 for 等循环语句的 "条件",
该方法的条件是结束等待条件, 只要不满足条件, 就一直等待.
而循环语句的条件, 是只要满足条件, 就一直循环.
等待条件支持函数及选择器.
函数示例, 等待设备屏幕关闭:
wait(function () {
return device.isScreenOff();
});
/* 使用箭头函数. */
wait(() => device.isScreenOff());
/* 使用 bind. */
wait(device.isScreenOff.bind(device));
/* 对结果分支处理. */
if (wait(() => device.isScreenOff())) {
console.log("等待屏幕关闭成功");
} else {
console.log("等待屏幕关闭超时");
}
选择器示例, 等待文本为 "立即开始" 的控件出现:
/* 以下三种方式为 Pickup 选择器的不同格式, 效果相同. */
wait('立即开始');
wait(content('立即开始')); /* 同上. */
wait({ content: '立即开始' }); /* 同上. */
/* 函数方式. */
wait(() => content('立即开始').exists());
wait(() => pickup('立即开始', '?')); /* 同上. */
/* wait 返回结果的简单应用. */
wait('立即开始') && toast('OK');
wait('立即开始') ? toast('√') : toast('×');
等待条件的满足与否, 与函数返回值有关.
例如当函数返回 true 时, 等待条件即满足.
下面列出不满足条件的几种返回值:
[ false / null / undefined / NaN ]
除此之外的返回值均视为满足条件 (包括空字符串和数字 0 等).
一种常见的错误用例, 即函数条件缺少返回值:
wait(() => {
if (device.isScreenOff()) {
console.log("屏幕已成功关闭");
}
});
上述示例中, 等待条件永远无法满足, 因函数一直返回 undefined.
添加合适的返回值即可修正:
wait(() => {
if (device.isScreenOff()) {
console.log("屏幕已成功关闭");
return true;
}
});
参阅: pickup
wait(condition, limit)#
6.2.0 Global Overload 2/6 A11Y? Non-UI
- condition { (() => any) | PickupSelector } - 结束等待条件
- limit { number } - 等待条件检测限制
- returns { boolean }
wait(condition) 增加条件检测限制.
达到限制后, 表示等待超时, 并放弃等待.
限制分为 "次数限制" (limit < 100) 和 "时间限制" (limit >= 100).
/* 等待屏幕关闭, 最多检测屏幕状态 20 次. */
wait(() => device.isScreenOff(), 20); /* limit < 100, 视为次数限制. */
/* 等待屏幕关闭, 最多检测屏幕状态 5 秒钟. */
wait(() => device.isScreenOff(), 5e3); /* limit >= 100, 视为时间限制. */
wait(condition, limit, interval)#
6.2.0 Global Overload 3/6 A11Y? Non-UI
- condition { (() => any) | PickupSelector } - 结束等待条件
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- returns { boolean }
wait(condition, limit) 增加条件检测间隔.
只要条件不满足, wait() 方法会持续检测, 直到条件满足或达到检测限制.
interval 参数用于设置条件检测之间的间歇时长, 默认为 200 毫秒.
检查条件 (不满足) - 间歇 - 检查条件 (不满足) - 间歇 - 检查条件...
/* 等待屏幕关闭, 最多检测屏幕状态 20 次, 每次检查间歇 3 秒钟. */
wait(() => device.isScreenOff(), 20, 3e3);
/* 等待屏幕关闭, 最多检测屏幕状态 20 次, 并采用不间断检测 (无间歇). */
wait(() => device.isScreenOff(), 20, 0);
注: 在最后一次条件检查之后, 将不再发生间歇.
包括条件满足或达到检测限制.例如在第三次检查时, 条件满足:
检查 (×) - 间歇 - 检查 (×) - 间歇 - 检查 (√) - 立即结束 wait()
wait(condition, callback)#
6.2.0 Global Overload 4/6 A11Y? Non-UI
- condition { (() => T) | PickupSelector } - 结束等待条件
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
wait(condition) 增加回调对象.
回调对象集合了两个方法, then 与 else 分别对应等待成功与等待失败的情况:
wait(() => device.isScreenOff(), {
then: () => console.log("等待屏幕关闭成功"),
else: () => console.log("等待屏幕关闭超时"),
});
两种方法都将最后一次检查结果作为实参, 可在方法体内直接使用:
/* 等待一个落在 99.99 到 100 区间的随机数. */
wait(() => {
let num = Math.random() * 100;
return num > 99.99 && num;
}, {
then(o) {
console.log(`获取随机数成功, 数字是: ${o}`);
},
else() {
console.log("获取 99.99 到 100 的随机数超时");
},
});
注: else 回调方法的参数只能是 [ false / null / undefined / NaN ],
因此 else 的参数几乎不会用到.
需特别注意, 回调方法的返回值具有穿透性.
在回调方法内使用 return 语句, 将直接影响 wait() 的返回值 (undefined 除外).
上述示例中, then 和 else 回调都没有返回值, 因此 wait() 返回值是 boolean 类型, 表示等待条件是否满足.
下述示例在回调函数中增加了返回值 (非 undefined), 则 wait() 也将返回这个值.
let result = wait(() => {
let num = Math.random() * 100;
return num > 99.99 && num;
}, {
then(o) {
console.log(`获取随机数成功`);
return o;
},
else() {
console.log("获取 99.99 到 100 的随机数超时");
return NaN;
},
});
result; /* 一个数字 (如 99.99732126036437) 或 NaN. */
上述示例如果等待条件满足, 则返回 then 的返回值 (number 类型),
等待条件超时, 则返回 else 的返回值 (NaN, 也为 number 类型).
如果去掉 else 的返回语句, 则等待条件超时后, wait() 将返回 false (boolean 类型).
如需对 wait() 的返回值做进一步处理, 则建议两个回调方法的返回值类型一致:
wait(() => {
let num = Math.random() * 100;
return num > 99.99 && num;
}, {
then(o) {
return [ o - 1, o, o + 1 ];
},
else() {
/* 即使等待条件超时, 也可调用 forEach 方法. */
return [];
},
}).forEach(x => console.log(x));
wait(condition, limit, callback)#
6.2.0 Global Overload 5/6 A11Y? Non-UI
- condition { (() => T) | PickupSelector } - 结束等待条件
- limit { number } - 等待条件检测限制
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
wait(condition, callback) 增加条件检测限制.
wait(condition, limit, interval, callback)#
6.2.0 Global Overload 6/6 A11Y? Non-UI
- condition { (() => T) | PickupSelector } - 结束等待条件
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
wait(condition, limit, callback) 增加条件检测间隔.
[m] waitForActivity#
等待指定名称的 Activity 出现 (前置).
此方法相当于 wait(() => currentActivity() === activityName, ...args),
因此其所有重载方法的结构与 wait 一致.
为节约篇幅, 将仅列出方法签名等重要信息.
waitForActivity(activityName)#
6.2.0 Global Overload 1/6 A11Y? Non-UI
waitForActivity(activityName, limit)#
6.2.0 Global Overload 2/6 A11Y? Non-UI
waitForActivity(activityName, limit, interval)#
6.2.0 Global Overload 3/6 A11Y? Non-UI
- activityName { string } - 目标活动名称
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- returns { boolean }
waitForActivity(activityName, callback)#
6.2.0 Global Overload 4/6 A11Y? Non-UI
- activityName { string } - 目标活动名称
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
waitForActivity(activityName, limit, callback)#
6.2.0 Global Overload 5/6 A11Y? Non-UI
- activityName { string } - 目标活动名称
- limit { number } - 等待条件检测限制
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
waitForActivity(activityName, limit, interval, callback)#
6.2.0 Global Overload 6/6 A11Y? Non-UI
- activityName { string } - 目标活动名称
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
[m] waitForPackage#
等待指定包名的应用出现 (前置).
此方法相当于 wait(() => currentPackage() === packageName, ...args),
因此其所有重载方法的结构与 wait 一致.
为节约篇幅, 将仅列出方法签名等重要信息.
waitForPackage(packageName)#
6.2.0 Global Overload 1/6 A11Y? Non-UI
waitForPackage(packageName, limit)#
6.2.0 Global Overload 2/6 A11Y? Non-UI
waitForPackage(packageName, limit, interval)#
6.2.0 Global Overload 3/6 A11Y? Non-UI
- packageName { string } - 目标应用包名
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- returns { boolean }
waitForPackage(packageName, callback)#
6.2.0 Global Overload 4/6 A11Y? Non-UI
- packageName { string } - 目标应用包名
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
waitForPackage(packageName, limit, callback)#
6.2.0 Global Overload 5/6 A11Y? Non-UI
- packageName { string } - 目标应用包名
- limit { number } - 等待条件检测限制
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
waitForPackage(packageName, limit, interval, callback)#
6.2.0 Global Overload 6/6 A11Y? Non-UI
- packageName { string } - 目标应用包名
- limit { number } - 等待条件检测限制
- interval { number } - 等待条件检测间隔
- callback {{
- }} - 等待结束回调对象
- returns { R extends void ? boolean : R }
- template T, R
[m] exit#
停止脚本运行.
exit()#
Global Overload 1/3
- returns { void }
通过抛出 ScriptInterruptedException 异常实现脚本停止.
因此用 try 包裹 exit() 语句将会使脚本继续运行片刻:
try {
log('exit now');
exit();
log("after"); /* 控制台不会打印 "after". */
} catch (e) {
e.javaException instanceof ScriptInterruptedException; // true
}
while (true) log("hello"); /* 控制台将打印一定数量的 "hello". */
如果编写的脚本对 "是否停止" 的状态十分敏感,
即要求 exit() 之后的代码一定不被执行,
则可通过附加状态判断实现上述需求:
if (!isStopped()) {
// 其他代码...
}
因此上述示例如果加上状态判断, "hello" 将不会被打印:
try {
log('exit now');
exit();
} catch (_) {
// Ignored.
}
if (!isStopped()) {
while (true) {
/* 控制台不会打印 "hello". */
log("hello");
}
}
除了 isStopped, 还可通过 threads 或 engines 获取停止状态:
/* threads. */
if (!threads.currentThread().isInterrupted()) {
// 其他代码...
}
/* engines. */
if (!engines.myEngine().isStopped()) {
// 其他代码...
}
exit(e)#
Global Overload 2/3
- e { JavaException } - 异常参数
- returns { void }
停止脚本运行并抛出异常参数指定的异常.
此方法通常不会在脚本中使用, 因 e 参数通常需要手动实例化.
如需自动完成实例化操作, 可使用 exit(errorMessage) 方法, 可支持直接传入字符串类型的异常消息参数.
let arg = 'hello';
try {
if (typeof arg !== "number") {
throw Error('arg 参数非 number 类型');
}
} catch (e) {
exit(new java.lang.Throwable(e))
}
需额外留意上述示例的异常参数使用了 Throwable 重新包装, 因为异常参数类型为 Java 的 Exception, 而非 JavaScript 的 Error.
关于异常相关的内容, 可参阅 异常 章节.
exit(errorMessage)#
6.2.0 Global Overload 3/3
停止脚本运行并抛出异常参数指定的异常.
相当于 exit(new java.lang.Exception(errorMessage)).
let buttonText = '点此开始';
if (!pickup(buttonText)) {
exit(`"${buttonText}" 按钮不存在.`);
}
[m] stop#
stop()#
Global - returns { void }
停止脚本运行.
exit() 的别名方法.
注: stop 方法不存在 exit(e) 对应的重载方法.
[m] isStopped#
isStopped()#
Global DEPRECATED
- returns { boolean }
检测脚本主线程是否已中断.
即 runtime.isInterrupted().
[m] isShuttingDown#
isShuttingDown()#
Global DEPRECATED
- returns { boolean }
检测脚本主线程是否已中断.
因方法名称易造成歧义及混淆, 因此被弃用, 建议使用 isStopped() 或 runtime.isInterrupted() 替代.
[m] isRunning#
isRunning()#
Global - returns { boolean }
检测脚本主线程是否未被中断.
即 !runtime.isInterrupted().
[m] notStopped#
notStopped()#
Global DEPRECATED
- returns { boolean }
检测脚本主线程是否未被中断.
因方法名称易造成歧义及混淆, 因此被弃用, 建议使用 isRunning() 或 !runtime.isInterrupted() 替代.
[m] requiresApi#
requiresApi(api)#
Global - api { number } - 安卓 API 级别
- returns { void }
脚本运行的最低 API 级别要求.
例如要求脚本运行不低于 Android API 30 (11) [R]:
requiresApi(30);
requiresApi(util.versionCodes.R.apiLevel); /* 同上. */
requiresApi(android.os.Build.VERSION_CODES.R); /* 同上. */
若 API 级别不符合要求, 脚本抛出异常并停止继续执行.
参阅:
[m] requiresAutojsVersion#
requiresAutojsVersion(versionName)#
Global Overload 1/2
脚本运行的最低 AutoJs6 版本要求 (版本名称).
requiresAutojsVersion("6.2.0");
可通过 autojs.versionName 查看 AutoJs6 版本名称.
requiresAutojsVersion(versionCode)#
Global Overload 2/2
脚本运行的最低 AutoJs6 版本要求 (版本号).
requiresAutojsVersion(1024);
可通过 autojs.versionCode 查看 AutoJs6 版本号.
[m] importPackage#
importPackage(...pkg)#
Global - pkg { ...( string | object ) } - 需导入的 Java 包
- returns { void }
/* 导入一个 Java 包. */
importPackage(java.lang);
importPackage('java.lang'); /* 同上. */
/* 导入多个 Java 包. */
importPackage(java.io);
importPackage(java.lang);
importPackage(java.util);
importPackage(java.io, java.lang, java.util); /* 同上. */
参阅: 访问 Java 包和类
[m] importClass#
importClass(...cls)#
Global - cls { ...( string | object ) } - 需导入的 Java 类
- returns { void }
/* 导入一个 Java 类. */
importClass(java.lang.Integer);
importClass('java.lang.Integer'); /* 同上. */
/* 导入多个 Java 类. */
importClass(java.io.File);
importClass(java.lang.Integer);
importClass(java.util.HashMap);
importClass(
java.io.File,
java.lang.Integer,
java.util.HashMap,
); /* 同上. */
参阅: 访问 Java 包和类
[m] currentPackage#
currentPackage()#
Global A11Y
- returns { string }
获取最近一次监测到的应用包名, 并视为当前正在运行的应用包名.
[m] currentActivity#
currentActivity()#
Global A11Y
- returns { string }
获取最近一次监测到的活动名称, 并视为当前正在运行的活动名称.
[m] setClip#
setClip(text)#
Global - text { string } - 剪贴板内容
- returns { void }
设置系统剪贴板内容.
参阅: getClip
[m] getClip#
getClip()#
Global - returns { string } - 系统剪贴板内容
需额外留意, 自 Android API 29 (10) [Q] 起, 剪贴板数据的访问将受到限制:
为更好地保护用户隐私权, 除默认输入法及当前获取焦点的前置应用外, 均无法访问剪贴板数据.
setClip("test");
/* 安卓 10 以下: 打印 "test". */
/* 安卓 10 及以上: 若 AutoJs6 前置, 打印 "test", 否则打印空字符串. */
console.log(getClip());
参阅: setClip
参阅: Android Docs
[m] selector#
selector()#
Global - returns { UiSelector }
构建一个 "空" 选择器.
[m] pickup#
拾取选择器, 简称拾取器, 是高度封装的混合形式选择器, 用于在筛选控件及处理结果过程中实现快捷操作.
支持 [ 选择器多形式混合 / 控件罗盘 / 结果筛选 / 参化调用 ] 等.
[m] detect#
控件探测.
探测相当于对控件进行一系列组合操作 (罗盘定位, 结果筛选, 参化调用, 回调处理).
参阅 UiObject#detect.
[m] existsAll#
existsAll(...selectors)#
Global - selectors { ...PickupSelector[] } - 混合选择器参数
- returns { boolean } - 选择器全部满足 "存在" 条件
提供的选择器参数全部满足 "存在" 条件, 即 selector.exists() === true.
例如要求当前活动窗口中同时存在以下三个选择器对应的控件:
- contentMatch(/^开始.*/)
- descMatch(/descriptions?/)
- content('点击继续')
console.log(existsAll(contentMatch(/^开始.*/), descMatch(/descriptions?/), content('点击继续'))); /* e.g. true */
因混合选择器参数支持对 content 系列选择器的简化, 因此上述示例也可改写为以下形式:
console.log(existsAll(/^开始.*/, descMatch(/descriptions?/), '点击继续')); /* e.g. true */
此方法对应的传统的逻辑判断形式:
console.log(contentMatch(/^开始.*/).exists()
&& descMatch(/descriptions?/).exists()
&& content('点击继续').exists()); /* e.g. true */
[m] existsOne#
existsOne(...selectors)#
Global - selectors { ...PickupSelector[] } - 混合选择器参数
- returns { boolean } - 选择器任一满足 "存在" 条件
提供的选择器参数任一满足 "存在" 条件, 即 selector.exists() === true.
例如要求当前活动窗口中存在任意一个以下选择器对应的控件:
- contentMatch(/^开始.*/)
- descMatch(/descriptions?/)
- content('点击继续')
console.log(existsOne(contentMatch(/^开始.*/), descMatch(/descriptions?/), content('点击继续'))); /* e.g. true */
因混合选择器参数支持对 content 系列选择器的简化, 因此上述示例也可改写为以下形式:
console.log(existsOne(/^开始.*/, descMatch(/descriptions?/), '点击继续')); /* e.g. true */
此方法对应的传统的逻辑判断形式:
console.log(contentMatch(/^开始.*/).exists()
|| descMatch(/descriptions?/).exists()
|| content('点击继续').exists()); /* e.g. true */
[m] cX#
横坐标标度.
cX()#
6.2.0 Global Overload 1/5
- returns { number }
无参时, 返回当前设备宽度.
console.log(cX() === device.width); // true
cX(x, base)#
6.2.0 Global Overload 2/4
由基数换算后得到的横坐标值.
例如在一个设备宽度为 1096 的设备上的 100 像素, 在其他不同宽度的设备上将转换为不同的值:
/* 在宽度为 1096 像素的设备上. */
cX(100, 1096); // 100
/* 在宽度为 1080 像素的设备上. */
cX(100, 1096); // 99
/* 在宽度为 720 像素的设备上. */
cX(100, 1096); // 66
/* 在宽度为 540 像素的设备上. */
cX(100, 1096); // 49
上述示例的 1096 为基数, 默认基数为 720, 如需设置默认基数, 可使用以下方法:
cX(100); /* 相当于 cX(100, 720) . */
setScaleBaseX(1096);
cX(100); /* 相当于 cX(100, 1096) . */
默认基数只能修改最多一次.
cX(x, isRatio)#
6.2.0 Global Overload 3/4
- x { number } - 绝对坐标值或屏幕宽度百分比
- [ isRatio = 'auto' ] {
'auto'| boolean } - 是否将x参数强制作为百分比 - returns { number }
isRatio 参数默认为 auto, 即由 x 参数的范围自动决定 x 是否视为百分比,
即当参数 x 满足 -1 < x < 1 时, x 将视为屏幕宽度百分比, 否则将视为绝对坐标值.
isRatio 参数为 true 时, x 参数将强制视为百分比, 如 cX(2, true) 意味着两倍屏幕宽度, 2 的意义不再是像素值.
isRatio 参数为 false 时, x 参数将强制视为绝对坐标值, 如 cX(0.5, false) 意味着 0.5 像素值, 其意义不再是百分比.
cX(x)#
6.2.0 Global Overload 4/4
当参数 x 满足 -1 < x < 1 时, 相当于 cX(x, /* isRatio = */ true), 即 x 将视为屏幕宽度百分比.
当参数 x 满足 x <= -1 | x >= 1 时, 相当于 cX(x, /* base = */ 720), 即 x 将视为绝对坐标值, 另 base 参数可能由 setScaleBaseX 等方法修改, 720 为其默认值.
[m] cY#
横坐标标度.
cY()#
6.2.0 Global Overload 1/5
- returns { number }
无参时, 返回当前设备高度.
console.log(cY() === device.width); // true
cY(y, base)#
6.2.0 Global Overload 2/4
由基数换算后得到的纵坐标值.
例如在一个设备高度为 2560 的设备上的 100 像素, 在其他不同高度的设备上将转换为不同的值:
/* 在高度为 2560 像素的设备上. */
cY(100, 2560); // 100
/* 在高度为 1920 像素的设备上. */
cY(100, 2560); // 75
/* 在高度为 1280 像素的设备上. */
cY(100, 2560); // 50
/* 在高度为 960 像素的设备上. */
cY(100, 2560); // 38
上述示例的 2560 为基数, 默认基数为 1280, 如需设置默认基数, 可使用以下方法:
cY(100); /* 相当于 cY(100, 1280) . */
setScaleBaseY(2560);
cY(100); /* 相当于 cY(100, 2560) . */
默认基数只能修改最多一次.
cY(y, isRatio)#
6.2.0 Global Overload 3/4
- y { number } - 绝对坐标值或屏幕高度百分比
- [ isRatio = 'auto' ] {
'auto'| boolean } - 是否将y参数强制作为百分比 - returns { number }
isRatio 参数默认为 auto, 即由 y 参数的范围自动决定 y 是否视为百分比,
即当参数 y 满足 -1 < y < 1 时, y 将视为屏幕高度百分比, 否则将视为绝对坐标值.
isRatio 参数为 true 时, y 参数将强制视为百分比, 如 cY(2, true) 意味着两倍屏幕高度, 2 的意义不再是像素值.
isRatio 参数为 false 时, y 参数将强制视为绝对坐标值, 如 cY(0.5, false) 意味着 0.5 像素值, 其意义不再是百分比.
cY(y)#
6.2.0 Global Overload 4/4
当参数 y 满足 -1 < y < 1 时, 相当于 cY(y, /* isRatio = */ true), 即 y 将视为屏幕高度百分比.
当参数 y 满足 y <= -1 | y >= 1 时, 相当于 cY(y, /* base = */ 1280), 即 y 将视为绝对坐标值, 另 base 参数可能由 setScaleBaseY 等方法修改, 1280 为其默认值.
[m] cYx#
以横坐标度量的纵坐标标度.
与设备高度无关, 与设备宽度相关的坐标标度.
如 cYx(0.5, '9:16') 对于以下 5 个设备 (以分辨率区分) 得到的结果是完全一致的:
1. 1080 × 1920
4. 1080 × 2160
5. 1080 × 2340
3. 1080 × 2520
2. 1080 × 2560
因为所有设备宽度相同, cYx 的结果是高度无关的.
计算结果:
1080 * 0.5 * 16 / 9; // 960
设想如下场景, 某个应用页面是可以向下滚动窗口显示更多内容的, 在屏幕上半部分有一个按钮 BTN, 距离屏幕上边缘 H 距离, 另一台设备与当前设备屏幕宽度相同, 但高度更大, 相当于屏幕纵向变长, 此时按钮 BTN 距离屏幕上边缘依然是 H 距离, 仅仅是屏幕下方显示了更多内容.
因此可使用 cYx 标度表示按钮 BTN 的位置, 如 cYx(0.2, 1080 / 1920) 或 cYx(0.2, 9 / 16) 或 cYx(0.2, '9:16').
上述示例的 0.2 是一个相对值, 是相对于当前设备屏幕高度的, 因此第 2 个参数对应设备宽高比例值.
如果使用绝对坐标值 (Y 坐标值), 如 384, 则第 2 个参数对应的是设备屏幕宽度值:
| 第 1 个参数 | 第 2 个参数 | 示例 |
|---|---|---|
| Y 坐标百分比 | 设备宽高比 | cYx(0.2, '9:16') |
| Y 坐标值 | 设备宽度值 | cYx(384, 1096) |
cYx(coordinateY, baseX)#
6.2.0 Global Overload [1(A)]/3
由横坐标基数换算后得到的纵坐标值.
例如在一个设备宽度为 1096 设备上的 512 像素高度, 在其他不同宽度的设备上将转换为不同的值:
/* 在宽度为 1096 像素的设备上. */
cYx(512, 1096); // 512
/* 在宽度为 1080 像素的设备上. */
cYx(512, 1096); // 505
/* 在宽度为 720 像素的设备上. */
cYx(512, 1096); // 336
/* 在宽度为 540 像素的设备上. */
cYx(512, 1096); // 252
上述示例的 1096 为基数, 默认基数为 720, 如需设置默认基数, 可使用以下方法:
cYx(512); /* 相当于 cYx(512, 720) . */
setScaleBaseX(1096);
cYx(512); /* 相当于 cYx(512, 1096) . */
默认基数只能修改最多一次.
cYx(percentY, ratio)#
6.2.0 Global Overload [1(B)]/3
由设备宽高比换算后得到的新纵坐标值.
例如在一个设备宽度与高度分别为 1096 和 2560 的设备上的 512 像素高度, 即 0.2 倍的屏幕高度, 在其他不同宽度的设备上将转换为不同的值:
/* 在宽度为 1096 像素的设备上. */
cYx(0.2, 1096 / 2560); // 512
/* 在宽度为 1080 像素的设备上. */
cYx(0.2, 1096 / 2560); // 505
/* 在宽度为 720 像素的设备上. */
cYx(0.2, 1096 / 2560); // 336
/* 在宽度为 540 像素的设备上. */
cYx(0.2, 1096 / 2560); // 252
上述示例的 1096 / 2560 为基数, 默认基数为 720 / 1280, 如需设置默认基数, 可使用以下方法:
cYx(0.2); /* 相当于 cYx(0.2, 720 / 1280) . */
setScaleBases(1096, 2560);
cYx(0.2); /* 相当于 cYx(0.2, 1096 / 2560) . */
默认基数只能修改最多一次.
cYx(y, isRatio)#
6.2.0 Global Overload 2/3
- y { number } - 绝对坐标值或屏幕高度百分比
- [ isRatio = 'auto' ] {
'auto'| boolean } - 是否将y参数强制作为百分比 - returns { number }
isRatio 参数默认为 auto, 即由 y 参数的范围自动决定 y 是否视为百分比,
即当参数 y 满足 -1 < y < 1 时, y 将视为屏幕高度百分比, 否则将视为绝对坐标值.
isRatio 参数为 true 时, y 参数将强制视为百分比, 如 cYx(2, true) 意味着两倍屏幕高度, 2 的意义不再是像素值.
isRatio 参数为 false 时, y 参数将强制视为绝对坐标值, 如 cYx(0.5, false) 意味着 0.5 像素值, 其意义不再是百分比.
cYx(y)#
6.2.0 Global Overload 3/3
当参数 y 满足 -1 < y < 1 时, 相当于 cY(y, /* isRatio = */ true), 即 y 将视为屏幕高度百分比.
当参数 y 满足 y <= -1 | y >= 1 时, 相当于 cY(y, /* base = */ 720), 即 y 将视为绝对坐标值, 另 base 参数可能由 setScaleBaseX 等方法修改, 720 为其默认值.
cYx(0.3); /* 相当于 cYx(0.3, '9:16') . */
cYx(384); /* 相当于 cYx(384, 720) . */
[m] cXy#
以纵坐标度量的横坐标标度.
与设备宽度无关, 与设备高度相关的坐标标度.
如 cXy(0.5, '9:16') 对于以下 5 个设备 (以分辨率区分) 得到的结果是完全一致的:
1. 1080 × 1920
4. 1096 × 1920
5. 720 × 1920
3. 540 × 1920
2. 960 × 1920
因为所有设备高度相同, cXy 的结果是宽度无关的.
计算结果:
1920 * 0.5 * 9 / 16; // 540
设想如下场景, 某个应用页面是可以向右滚动窗口显示更多内容的, 在屏幕左半部分有一个按钮 BTN, 距离屏幕左边缘 W 距离, 另一台设备与当前设备屏幕高度相同, 但宽度更大, 相当于屏幕横向变长, 此时按钮 BTN 距离屏幕左边缘依然是 W 距离, 仅仅是屏幕右方显示了更多内容.
因此可使用 cXy 标度表示按钮 BTN 的位置, 如 cXy(0.2, 1080 / 1920) 或 cXy(0.2, 9 / 16) 或 cXy(0.2, '9:16').
上述示例的 0.2 是一个相对值, 是相对于当前设备屏幕宽度的, 因此第 2 个参数对应设备宽高比例值.
如果使用绝对坐标值 (X 坐标值), 如 384, 则第 2 个参数对应的是设备屏幕高度值:
| 第 1 个参数 | 第 2 个参数 | 示例 |
|---|---|---|
| X 坐标百分比 | 设备宽高比 | cXy(0.2, '9:16') |
| X 坐标值 | 设备高度值 | cXy(384, 2560) |
cXy(coordinateX, baseY)#
6.2.0 Global Overload [1(A)]/3
由纵坐标基数换算后得到的横坐标值.
例如在一个设备高度为 2560 设备上的 512 像素宽度, 在其他不同高度的设备上将转换为不同的值:
/* 在高度为 2560 像素的设备上. */
cXy(512, 2560); // 512
/* 在高度为 1920 像素的设备上. */
cXy(512, 2560); // 384
/* 在高度为 1280 像素的设备上. */
cXy(512, 2560); // 256
/* 在高度为 960 像素的设备上. */
cXy(512, 2560); // 192
上述示例的 2560 为基数, 默认基数为 1280, 如需设置默认基数, 可使用以下方法:
cXy(512); /* 相当于 cXy(512, 1280) . */
setScaleBaseY(2560);
cXy(512); /* 相当于 cXy(512, 2560) . */
默认基数只能修改最多一次.
cXy(percentX, ratio)#
6.2.0 Global Overload [1(B)]/3
由设备宽高比换算后得到的新横坐标值.
例如在一个设备高度与宽度分别为 1096 和 2560 的设备上的 548 像素宽度, 即 0.5 倍的屏幕宽度, 在其他不同高度的设备上将转换为不同的值:
/* 在高度为 2560 像素的设备上. */
cXy(0.5, 1096 / 2560); // 548
/* 在高度为 1920 像素的设备上. */
cXy(0.5, 1096 / 2560); // 411
/* 在高度为 1280 像素的设备上. */
cXy(0.5, 1096 / 2560); // 274
/* 在高度为 960 像素的设备上. */
cXy(0.5, 1096 / 2560); // 206
上述示例的 1096 / 2560 为基数, 默认基数为 720 / 1280, 如需设置默认基数, 可使用以下方法:
cXy(0.5); /* 相当于 cXy(0.5, 720 / 1280) . */
setScaleBases(1096, 2560);
cXy(0.5); /* 相当于 cXy(0.5, 1096 / 2560) . */
默认基数只能修改最多一次.
cXy(x, isRatio)#
6.2.0 Global Overload 2/3
- x { number } - 绝对坐标值或屏幕宽度百分比
- [ isRatio = 'auto' ] {
'auto'| boolean } - 是否将x参数强制作为百分比 - returns { number }
isRatio 参数默认为 auto, 即由 x 参数的范围自动决定 x 是否视为百分比,
即当参数 x 满足 -1 < x < 1 时, x 将视为屏幕宽度百分比, 否则将视为绝对坐标值.
isRatio 参数为 true 时, x 参数将强制视为百分比, 如 cXy(2, true) 意味着两倍屏幕宽度, 2 的意义不再是像素值.
isRatio 参数为 false 时, x 参数将强制视为绝对坐标值, 如 cXy(0.5, false) 意味着 0.5 像素值, 其意义不再是百分比.
cXy(x)#
6.2.0 Global Overload 3/3
当参数 x 满足 -1 < x < 1 时, 相当于 cY(x, /* isRatio = */ true), 即 x 将视为屏幕宽度百分比.
当参数 x 满足 x <= -1 | x >= 1 时, 相当于 cY(x, /* base = */ 720), 即 x 将视为绝对坐标值, 另 base 参数可能由 setScaleBaseX 等方法修改, 720 为其默认值.
cXy(0.3); /* 相当于 cXy(0.3, '9:16') . */
cXy(384); /* 相当于 cXy(384, 720) . */
[p] WIDTH#
6.2.0 Global Getter
- { number }
device.width 的别名属性.
[p] HEIGHT#
6.2.0 Global Getter
- { number }
device.height 的别名属性.
[p+] R#
在代码中使用 R 类的子类中的静态整数可访问 应用资源, 详情参阅 资源 ID 术语.
[p+] anim#
6.2.0 Global
动画资源.
定义预先了确定的动画.
补间动画保存在 res/anim/ 中, 可通过 R.anim 属性访问.
帧动画保存在 res/drawable/ 中, 可通过 R.drawable 属性访问.
'ui';
ui.layout(<vertical id="main">
<vertical width="100" height="100" bg="#00695C"></vertical>
</vertical>);
const AnimationUtils = android.view.animation.AnimationUtils;
const mContentContainer = ui.main;
const mSlideDownAnimation = AnimationUtils.loadAnimation(context, R.anim.slide_down);
mSlideDownAnimation.setDuration(2000);
mContentContainer.startAnimation(mSlideDownAnimation);
[p+] array#
6.2.0 Global
静态资源.
提供数组的 XML 资源.
dialogs.build({
title: R.string.text_pinch_to_zoom,
items: R.array.values_editor_pinch_to_zoom_strategy,
itemsSelectMode: 'single',
itemsSelectedIndex: defSelectedIndex,
positive: 'OK',
}).on('single_choice', function (idx, item) {
toastLog(`${idx}: ${item}`);
}).show();
[p+] bool#
6.2.0 Global
静态资源.
包含布尔值的 XML 资源.
console.log(context.getResources().getBoolean(R.bool.pref_auto_check_for_updates));
[p+] color#
6.2.0 Global
静态资源.
包含颜色值 (十六进制颜色) 的 XML 资源.
console.log(colors.toString(context.getColor(R.color.console_view_warn), 6)); // #1976D2
[p+] dimen#
6.2.0 Global
静态资源.
包含尺寸值 (及度量单位) 的 XML 资源.
console.log(context.getResources().getDimensionPixelSize(R.dimen.textSize_item_property)); // e.g. 28
[p+] drawable#
6.2.0 Global
可绘制资源.
使用位图或 XML 定义各种图形.
保存在 res/drawable/ 中,可通过 R.drawable 属性访问.
/* 绘制一个淡绿色的铃铛图标. */
'ui';
ui.layout(<vertical bg="#FFFFFF">
<img id="img" tint="#9CCC65"/>
</vertical>);
ui.img.setImageResource(R.drawable.ic_ali_notification);
[p+] id#
6.2.0 Global
静态资源.
为应用资源和组件提供唯一标识符的 XML 资源.
'ui';
ui.layout(<vertical bg="#FFFFFF">
<text id="txt" size="30"/>
</vertical>);
let childCount = ui.txt.getRootView().findViewById(R.id.action_bar_root).getChildCount(); // e.g 2
ui.txt.setText(`Child count is ${childCount}`);
[p+] integer#
6.2.0 Global
静态资源.
包含整数值的 XML 资源.
console.log(context.getResources().getInteger(R.integer.layout_node_info_view_decoration_line)); // 2
[p+] layout#
6.2.0 Global
布局资源.
定义应用界面的布局.
保存在 res/layout/ 中,可通过 R.layout 属性访问.
'ui';
activity.setContentView(R.layout.activity_log);
[p+] menu#
6.2.0 Global
菜单资源.
定义应用菜单的内容.
保存在 res/menu/ 中,可通过 R.menu 属性访问.
'ui';
ui.layout(<vertical bg="#FFFFFF">
<text id="txt" size="30"/>
</vertical>);
const PopupMenu = android.widget.PopupMenu;
let childCount = ui.txt.getRootView().findViewById(R.id.action_bar_root).getChildCount(); // e.g 2
ui.txt.setText(`Child count is ${childCount}`);
let popupMenu = new PopupMenu(context, ui.txt);
popupMenu.inflate(R.menu.menu_script_options);
popupMenu.show();
[p+] plurals#
6.2.0 Global
静态资源.
定义资源复数形式.
console.log(context.getResources().getQuantityString(
R.plurals.text_already_stop_n_scripts,
new java.lang.Integer(1),
new java.lang.Integer(1))); // e.g. 1 script stopped
console.log(context.getResources().getQuantityString(
R.plurals.text_already_stop_n_scripts,
new java.lang.Integer(3),
new java.lang.Integer(3))); // e.g. 3 scripts stopped
[p+] string#
6.2.0 Global
字符串资源.
定义字符串.
保存在 res/values/ 中,可通过 R.string 属性访问.
console.log(context.getString(R.string.app_name)); // AutoJs6
[p+] strings#
6.2.0 Global
字符串资源.
同 R.string.
因 TypeScript Declarations (TS 声明文件) 中, string 为保留关键字, 不能作为类名使用, 为了使 IDE 实现智能补全, 特提供 R.strings 别名类.
console.log(context.getString(R.strings.app_name)); // AutoJs6
console.log(context.getString(R.string.app_name)); /* 同上, 但 IDE 无法智能补全. */
[p+] style#
6.2.0 Global
样式资源.
定义界面元素的外观和格式.
保存在 res/values/ 中,可通过 R.style 属性访问.
'ui';
const MaterialDialog = com.afollestad.materialdialogs.MaterialDialog;
const ContextThemeWrapper = android.view.ContextThemeWrapper;
new MaterialDialog.Builder(new ContextThemeWrapper(activity, R.style.Material3DarkTheme))
.title('Hello')
.positiveText('OK')
.onPositive(() => ui.finish())
.cancelable(false)
.build()
.show();
自动化 (Automator)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
简易自动化 (SimpleActionAutomator)#
待补充...
高权限自动化 (RootAutomator)#
待补充...
自动化配置 (AutomatorConfiguration)#
待补充...
选择器 (UiSelector)#
UiSelector (选择器), 亦可看作是 控件节点 的条件筛选器, 用于通过附加不同的条件, 筛选出一个或一组活动窗口中的 控件节点, 并做进一步处理, 如 [ 执行 控件行为 (点击, 长按, 设置文本等) / 判断位置 / 获取文本内容 / 获取控件特定状态 / 在 控件层级 中进行 罗盘 导航 ] 等.
详情参阅 选择器 (UiSelector) 章节.
控件节点 (UiObject)#
UiObject 通常被称为 [ 控件 / 节点 / 控件节点 ], 可看做是一个通过安卓无障碍服务包装的 AccessibilityNodeInfo 对象, 代表一个当前活动窗口中的节点, 通过此节点可收集控件信息或执行控件行为, 进而实现一系列自动化操作.
详情参阅 控件节点 (UiObject) 章节.
控件集合 (UiObjectCollection)#
UiObjectCollection 代表 控件节点 (UiObject) 的对象集合.
详情参阅 控件集合 (UiObjectCollection) 章节.
控件节点行为 (UiObjectActions)#
UiObjectActions 是一个 Java 接口, 代表 控件节点 (UiObject) 的行为集合.
详情参阅 控件节点行为 (UiObjectActions) 章节.
基于坐标的触摸模拟#
本章节介绍了一些使用坐标进行点击、滑动的函数. 这些函数有的需要安卓7.0以上, 有的需要root权限.
要获取要点击的位置的坐标, 可以在开发者选项中开启"指针位置".
基于坐标的脚本通常会有分辨率的问题, 这时可以通过setScreenMetrics()函数来进行自动坐标放缩. 这个函数会影响本章节的所有点击、长按、滑动等函数. 通过设定脚本设计时的分辨率, 使得脚本在其他分辨率下自动放缩坐标.
控件和坐标也可以相互结合. 一些控件是无法点击的(clickable为false), 无法通过.click()函数来点击, 这时如果安卓版本在7.0以上或者有root权限, 就可以通过以下方式来点击:
//获取这个控件
var widget = id("xxx").findOne();
//获取其中心位置并点击
click(widget.bounds().centerX(), widget.bounds().centerY());
//如果用root权限则用Tap
setScreenMetrics(width, height)#
设置脚本坐标点击所适合的屏幕宽高. 如果脚本运行时, 屏幕宽度不一致会自动放缩坐标.
例如在1920*1080的设备中, 某个操作的代码为
setScreenMetrics(1080, 1920);
click(800, 200);
longClick(300, 500);
那么在其他设备上AutoJs会自动放缩坐标以便脚本仍然有效. 例如在540 * 960的屏幕中click(800, 200)实际上会点击位置(400, 100).
安卓7.0以上的触摸和手势模拟#
注意以下命令只有Android7.0及以上才有效
click(x, y)#
模拟点击坐标(x, y), 并返回是否点击成功. 只有在点击执行完成后脚本才继续执行.
一般而言, 只有点击过程(大约150毫秒)中被其他事件中断(例如用户自行点击)才会点击失败.
使用该函数模拟连续点击时可能有点击速度过慢的问题, 这时可以用press()函数代替.
longClick(x, y)#
模拟长按坐标(x, y), 并返回是否成功. 只有在长按执行完成(大约600毫秒)时脚本才会继续执行.
一般而言, 只有长按过程中被其他事件中断(例如用户自行点击)才会长按失败.
press(x, y, duration)#
模拟按住坐标(x, y), 并返回是否成功. 只有按住操作执行完成时脚本才会继续执行.
如果按住时间过短, 那么会被系统认为是点击;如果时长超过500毫秒, 则认为是长按.
一般而言, 只有按住过程中被其他事件中断才会操作失败.
一个连点器的例子如下:
//循环100次
for(var i = 0; i < 100; i++){
//点击位置(500, 1000), 每次用时1毫秒
press(500, 1000, 1);
}
swipe(x1, y1, x2, y2, duration)#
模拟从坐标(x1, y1)滑动到坐标(x2, y2), 并返回是否成功. 只有滑动操作执行完成时脚本才会继续执行.
一般而言, 只有滑动过程中被其他事件中断才会滑动失败.
gesture(duration, [x1, y1], [x2, y2], ...)#
duration{ number } 手势的时长- [x, y] ... 手势滑动路径的一系列坐标
模拟手势操作. 例如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]]);
RootAutomator#
RootAutomator是一个使用root权限来模拟触摸的对象, 用它可以完成触摸与多点触摸, 并且这些动作的执行没有延迟.
一个脚本中最好只存在一个RootAutomator, 并且保证脚本结束退出他. 可以在exit事件中退出RootAutomator, 例如:
var ra = new RootAutomator();
events.on('exit', function(){
ra.exit();
});
//执行一些点击操作
...
注意以下命令需要root权限
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这个参数. 多点触摸通常用于手势或游戏操作, 例如模拟双指捏合、双指上滑等.
某些情况下可能存在tap点击无反应的情况, 这时可以用RootAutomator.press()函数代替.
RootAutomator.swipe(x1, x2, y1, y2[, duration, id])#
模拟一次从(x1, y1)到(x2, y2)的时间为duration毫秒的滑动.
RootAutomator.press(x, y, duration[, id])#
模拟按下位置(x, y), 时长为duration毫秒.
RootAutomator.longPress(x, y[\, id])#
模拟长按位置(x, y).
以上为简单模拟触摸操作的函数. 如果要模拟一些复杂的手势, 需要更底层的函数.
RootAutomator.touchDown(x, y[, id])#
模拟手指按下位置(x, y).
RootAutomator.touchMove(x, y[, id])#
模拟移动手指到位置(x, y).
RootAutomator.touchUp([id])#
id{ number } 多点触摸id, 可选, 默认为1
模拟手指弹起.
使用root权限点击和滑动的简单命令#
注意:本章节的函数在后续版本很可能有改动!请勿过分依赖本章节函数的副作用. 推荐使用RootAutomator代替本章节的触摸函数.
以下函数均需要root权限, 可以实现任意位置的点击、滑动等.
- 这些函数通常首字母大写以表示其特殊的权限.
- 这些函数均不返回任何值.
- 并且, 这些函数的执行是异步的、非阻塞的, 在不同机型上所用的时间不同. 脚本不会等待动作执行完成才继续执行. 因此最好在每个函数之后加上适当的sleep来达到期望的效果.
例如:
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 { number } 要点击的坐标.
点击位置(x, y), 您可以通过"开发者选项"开启指针位置来确定点击坐标.
Swipe(x1, y1, x2, y2, [duration])#
滑动. 从(x1, y1)位置滑动到(x2, y2)位置.
基于控件的操作#
基于控件的操作指的是选择屏幕上的控件, 获取其信息或对其进行操作. 对于一般软件而言, 基于控件的操作对不同机型有很好的兼容性;但是对于游戏而言, 由于游戏界面并不是由控件构成, 无法采用本章节的方法, 也无法使用本章节的函数. 有关游戏脚本的编写, 请参考《基于坐标的操作》.
基于控件的操作依赖于无障碍服务, 因此最好在脚本开头使用auto()函数来确保无障碍服务已经启用. 如果运行到某个需要权限的语句无障碍服务并没启动, 则会抛出异常并跳转到无障碍服务界面. 这样的用户体验并不好, 因为需要重新运行脚本, 后续会加入等待无障碍服务启动并让脚本继续运行的函数.
您也可以在脚本开头使用"auto";表示这个脚本需要无障碍服务, 但是不推荐这种做法, 因为这个标记必须在脚本的最开头(前面不能有注释或其他语句、空格等), 我们推荐使用auto()函数来确保无障碍服务已启用.
auto([mode])#
mode{ string } 模式
检查无障碍服务是否已经启用, 如果没有启用则抛出异常并跳转到无障碍服务启用界面;同时设置无障碍模式为mode. mode的可选值为:
fast快速模式. 该模式下会启用控件缓存, 从而选择器获取屏幕控件更快. 对于需要快速的控件操作的脚本可以使用该模式, 一般脚本则没有必要使用该函数.normal正常模式, 默认.
如果不加mode参数, 则为正常模式.
建议使用auto.waitFor()和auto.setMode()代替该函数, 因为auto()函数如果无障碍服务未启动会停止脚本;而auto.waitFor()则会在在无障碍服务启动后继续运行.
示例:
auto("fast");
示例2:
auto();
auto.waitFor()#
检查无障碍服务是否已经启用, 如果没有启用则跳转到无障碍服务启用界面, 并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行.
因为该函数是阻塞的, 因此除非是有协程特性, 否则不能在ui模式下运行该函数, 建议在ui模式下使用auto()函数.
auto.setMode(mode)#
mode{ string } 模式
设置无障碍模式为mode. mode的可选值为:
fast快速模式. 该模式下会启用控件缓存, 从而选择器获取屏幕控件更快. 对于需要快速的控件查看和操作的脚本可以使用该模式, 一般脚本则没有必要使用该函数.normal正常模式, 默认.
auto.setFlags(flags)#
[v4.1.0新增]
flags{ string } | { Array } 一些标志, 来启用和禁用某些特性, 包括:findOnUiThread使用该特性后, 选择器搜索时会在主进程进行. 该特性用于解决线程安全问题导致的次生问题, 不过目前貌似已知问题并不是线程安全问题.useUsageStats使用该特性后, 将会以"使用情况统计"服务的结果来检测当前正在运行的应用包名(需要授予"查看使用情况统计"权限). 如果觉得currentPackage()返回的结果不太准确, 可以尝试该特性.useShell使用该特性后, 将使用shell命令获取当前正在运行的应用的包名、活动名称, 但是需要root权限.
启用有关automator的一些特性. 例如:
auto.setFlags(["findOnUiThread", "useShell"]);
auto.service#
[v4.1.0新增]
获取无障碍服务. 如果无障碍服务没有启动, 则返回null.
auto.windows#
[v4.1.0新增]
- { Array }
当前所有窗口(AccessibilityWindowInfo)的数组, 可能包括状态栏、输入法、当前应用窗口, 弹出窗口、悬浮窗、分屏应用窗口等. 可以分别获取每个窗口的布局信息.
该函数需要Android 5.0以上才能运行.
auto.root#
[v4.1.0新增]
- { UiObject }
当前窗口的布局根元素. 如果无障碍服务未启动或者WindowFilter均返回false, 则会返回null.
如果不设置windowFilter, 则当前窗口即为活跃的窗口(获取到焦点、正在触摸的窗口);如果设置了windowFilter, 则获取的是过滤的窗口中的第一个窗口.
如果系统是Android5.0以下, 则始终返回当前活跃的窗口的布局根元素.
auto.rootInActiveWindow#
[v4.1.0新增]
- { UiObject }
当前活跃的窗口(获取到焦点、正在触摸的窗口)的布局根元素. 如果无障碍服务未启动则为null.
auto.setWindowFilter(filter)#
[v4.1.0新增]
filter{ Function } 参数为窗口(AccessibilityWindowInfo), 返回值为Boolean的函数.
设置窗口过滤器. 这个过滤器可以决定哪些窗口是目标窗口, 并影响选择器的搜索. 例如, 如果想要选择器在所有窗口(包括状态栏、输入法等)中搜索, 只需要使用以下代码:
auto.setWindowFilter(function(window){
//不管是如何窗口, 都返回true, 表示在该窗口中搜索
return true;
});
又例如, 当前使用了分屏功能, 屏幕上有Auto.js和QQ两个应用, 但我们只想选择器对QQ界面进行搜索, 则:
auto.setWindowFilter(function(window){
// 对于应用窗口, 他的title属性就是应用的名称, 因此可以通过title属性来判断一个应用
return window.title == "QQ";
});
选择器默认是在当前活跃的窗口中搜索, 不会搜索诸如悬浮窗、状态栏之类的, 使用WindowFilter则可以控制搜索的窗口.
需要注意的是, 如果WindowFilter返回的结果均为false, 则选择器的搜索结果将为空.
另外setWindowFilter函数也会影响auto.windowRoots的结果.
该函数需要Android 5.0以上才有效.
auto.windowRoots#
[v4.1.0新增]
- { Array }
返回当前被WindowFilter过滤的窗口的布局根元素组成的数组.
如果系统是Android5.0以下, 则始终返回当前活跃的窗口的布局根元素的数组.
SimpleActionAutomator#
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{ number } 要滑动的控件序号
找到第i+1个可滑动控件上滑或左滑. 返回是否操作成功. 屏幕上没有可滑动的控件时返回false.
另外不加参数时scrollUp()会寻找面积最大的可滑动的控件上滑或左滑, 例如微信消息列表等.
参数为一个整数i时会找到第i + 1个可滑动控件滑动. 例如scrollUp(0)为滑动第一个可滑动控件.
scrollDown([i])#
i{ number } 要滑动的控件序号
找到第i+1个可滑动控件下滑或右滑. 返回是否操作成功. 屏幕上没有可滑动的控件时返回false.
另外不加参数时scrollUp()会寻找面积最大的可滑动的控件下滑或右滑.
参数为一个整数i时会找到第i + 1个可滑动控件滑动. 例如scrollUp(0)为滑动第一个可滑动控件.
setText([i, ]text)#
返回是否输入成功. 当找不到对应的文本框时返回false.
不加参数i则会把所有输入框的文本都置为text. 例如setText("测试").
这里的输入文本的意思是, 把输入框的文本置为text, 而不是在原来的文本上追加.
input([i, ]text)#
返回是否输入成功. 当找不到对应的文本框时返回false.
不加参数i则会把所有输入框的文本追加内容text. 例如input("测试").
AutoJs6 本体应用#
autojs 全局对象主要包含与 AutoJs6 应用本身相关的属性及方法, 如获取 AutoJs6 的 [ Root 状态 / 语言标签 / 权限状态 ] 等.
autojs
[m] getLanguage#
getLanguage()#
6.2.0
- returns { java.util.Locale }
获取 AutoJs6 语言 设置选项.
此方法返回一个 java.util.Locale 对象, 如需返回其标签名, 如 en-US, zh-CN 等, 可使用 autojs.getLanguage().toLanguageTag() 或直接使用 autojs.getLanguageTag() 方法.
console.log(autojs.getLanguage().getDisplayName()); /* e.g. 日本語 */
[m] getLanguageTag#
getLanguageTag()#
6.2.0
- returns { string }
获取 AutoJs6 语言设置选项.
此方法返回 IETF 语言标签, 相当于 autojs.getLanguage().toLanguageTag():
console.log(autojs.getLanguageTag()); /* e.g. en-US */
此方法可用于设定 i18n 对象的区域:
i18n.setLocale(autojs.getLanguageTag());
[m] isRootAvailable#
isRootAvailable()#
6.2.0
- returns { boolean }
获取 AutoJs6 的 Root 权限有效性.
console.log(autojs.isRootAvailable()); // e.g. true
注意上述示例的检测结果取决于 AutoJs6 的 强制 Root 权限检查 设置.
此设置可通过 AutoJs6 应用设置修改, 或 setRootMode 方法携带 isWriteIntoPreference 参数实现修改.
[m] getRootMode#
getRootMode()#
6.2.0
- returns { RootMode }
获取 AutoJs6 的 Root 权限状态.
/* 是否为 '自动检测 Root 权限' 状态. */
console.log(autojs.getRootMode() === RootMode.AUTO_DETECT);
/* 是否为 '强制 Root 模式' 状态. */
console.log(autojs.getRootMode() === RootMode.FORCE_ROOT);
/* 是否为 '强制非 Root 模式' 状态. */
console.log(autojs.getRootMode() === RootMode.FORCE_NON_ROOT);
[m] setRootMode#
setRootMode(rootMode, isWriteIntoPreference?)#
6.2.0 Overload [1-2]/2
- rootMode { RootMode | number | boolean | 'auto' | 'root' | 'non-root' } - Root 模式参数
- [isWriteIntoPreference = false] { boolean } - 是否写入应用设置
- returns { void }
设置 AutoJs6 的 Root 模式.
默认情况下, AutoJs6 将根据 su 二进制名称特征来判断是否具有 Root 权限.
但有时设备可能使用了非常规 Root 方式或 Root 权限检测结果出现异常, 此时可设置 强制 Root 模式 或 强制非 Root 模式 来改变 AutoJs6 对 Root 权限的检测结果.
以设置 '强制 Root 模式' 为例:
autojs.setRootMode(RootMode.FORCE_ROOT);
autojs.setRootMode('root'); /* 同上. */
autojs.setRootMode(1); /* 同上. */
autojs.setRootMode(true); /* 同上. */
上述示例设置的 Root 模式, 将影响 isRootAvailable 的结果, 使其固定返回 true.
如果设置为 RootMode.FORCE_NON_ROOT, isRootAvailable 将固定返回 false.
如果设置为 RootMode.AUTO_DETECT, isRootAvailable 将根据 AutoJs6 是否具有 su 二进制名称特征决定其返回结果.
在没有特殊需求的情况下, 建议始终保持 Root 模式为 '自动' 模式.
需额外留意, Root 模式修改仅对当前 运行时 (Runtime) 有效, 当脚本结束时, 已设置的 Root 模式将自动还原为 '自动' 模式, 即 RootMode.AUTO_DETECT.
如需将保留修改的 Root 模式, 可使用 isWriteIntoPreference 参数, 修改将立即写入应用设置中:
autojs.setRootMode(RootMode.FORCE_ROOT, true);
上述示例代码的效果, 等效于在 AutoJs6 应用中进行如下设置:
[ AutoJs6 设置 ] - [ 强制 Root 权限检查 ] - [ 强制 Root 模式 ] # [ 选择 ]
[m] canModifySystemSettings#
canModifySystemSettings()#
6.2.0
- returns { boolean }
获取 AutoJs6 的 修改系统设置 权限状态.
console.log(autojs.canModifySystemSettings()); // e.g. true
拥有 修改系统设置 后, AutoJs6 可以通过脚本修改部分系统设置, 如修改屏幕超时参数, 修改媒体音量值等.
[m] canWriteSecureSettings#
canWriteSecureSettings()#
6.2.0
- returns { boolean }
获取 AutoJs6 的 修改安全设置 权限状态.
console.log(autojs.canWriteSecureSettings()); // e.g. true
拥有 修改安全设置 后, AutoJs6 可以通过脚本修改部分安全设置, 如修改屏幕常亮类别参数, 修改无障碍服务列表内容等.
[m] canDisplayOverOtherApps#
canDisplayOverOtherApps()#
6.2.0
- returns { boolean }
获取 AutoJs6 的 显示在其他应用上层 权限状态.
console.log(autojs.canDisplayOverOtherApps()); // e.g. true
拥有 显示在其他应用上层 后, AutoJs6 可以使用悬浮窗工具, 并可通过脚本显示对话框或自定义浮动组件等.
[p] versionName#
6.2.0
- { string }
获取版本名称.
console.log(autojs.versionName); // e.g. 6.2.0-alpha9
console.log(autojs.version.name); /* 同上. */
[p] versionCode#
6.2.0
- { number }
获取版本号.
console.log(autojs.versionCode); // e.g. 1545
console.log(autojs.version.code); /* 同上. */
[p] versionDate#
6.2.0
- { string }
获取版本日期.
console.log(autojs.versionDate); // e.g. Dec 18, 2022
console.log(autojs.version.date); /* 同上. */
[p+] version#
[p] name#
6.2.0
- { string }
获取版本名称.
console.log(autojs.version.name); // e.g. 6.2.0-alpha9
console.log(autojs.versionName); /* 同上. */
[p] code#
6.2.0
- { number }
获取版本号.
console.log(autojs.version.code); // e.g. 1545
console.log(autojs.versionCode); /* 同上. */
[p] date#
6.2.0
- { string }
获取版本日期.
console.log(autojs.version.date); // e.g. Dec 18, 2022
console.log(autojs.versionDate); /* 同上. */
[m] isEqual#
isEqual(otherVersion)#
6.2.0
返回 AutoJs6 版本是否与参数对应的版本号等同.
console.log(autojs.version.isEqual('6.2.0')); // e.g. true
[m] isHigherThan#
isHigherThan(otherVersion)#
6.2.0
返回 AutoJs6 版本是否高于待比较版本.
console.log(autojs.version.isHigherThan('6.1.3')); // e.g. true
[m] isLowerThan#
isLowerThan(otherVersion)#
6.2.0
返回 AutoJs6 版本是否低于待比较版本.
console.log(autojs.version.isLowerThan('6.2.0')); // e.g. true
[m] isAtLeast#
isAtLeast(otherVersion)#
6.2.0 Overload 1/2
返回 AutoJs6 版本是否不低于 (即大于等于) 参数对应的版本号.
console.log(autojs.version.isAtLeast('6.1.3')); // e.g. true
isAtLeast(otherVersion, ignoreSuffix)#
6.2.0 Overload 2/2
- otherVersion { string | Version } - 待比较版本参数
- [ignoreSuffix = false] { boolean } - 是否忽略版本后缀
- returns { boolean }
返回 AutoJs6 版本是否不低于 (即大于等于) 参数对应的版本号且根据 ignoreSuffix 参数决定是否忽略版本后缀.
console.log(autojs.version.name); // e.g. 6.2.0-alpha9
console.log(autojs.version.isAtLeast('6.2.0')); // e.g. false
console.log(autojs.version.isAtLeast('6.2.0', true)); // e.g. true
[p+] R#
使用 R 类的子类中的静态整数可访问相应的应用资源, 如 R.string 访问字符串资源, R.drawable 访问可绘制资源等.
global.R 的别名属性, 参阅 全局对象 (Global) 章节.
通用应用 (App)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
app模块提供一系列函数, 用于使用其他应用、与其他应用交互. 例如发送意图、打开文件、发送邮件等.
同时提供了方便的进阶函数startActivity和sendBroadcast, 用他们可完成app模块没有内置的和其他应用的交互.
app.versionCode#
- { number }
当前软件版本号, 整数值. 例如160, 256等.
如果在Auto.js中运行则为Auto.js的版本号;在打包的软件中则为打包软件的版本号.
toastLog(app.versionCode);
app.versionName#
- { string }
当前软件的版本名称, 例如"3.0.0 Beta".
如果在Auto.js中运行则为Auto.js的版本名称;在打包的软件中则为打包软件的版本名称.
toastLog(app.verionName);
app.autojs.versionCode#
- { number }
Auto.js版本号, 整数值. 例如160, 256等.
app.autojs.versionName#
- { string }
Auto.js版本名称, 例如"3.0.0 Beta".
app.launchApp(appName)#
appName{ string } 应用名称
通过应用名称启动应用. 如果该名称对应的应用不存在, 则返回false; 否则返回true. 如果该名称对应多个应用, 则只启动其中某一个.
该函数也可以作为全局函数使用.
launchApp("Auto.js");
app.launch(packageName)#
packageName{ string } 应用包名
通过应用包名启动应用. 如果该包名对应的应用不存在, 则返回false;否则返回true.
该函数也可以作为全局函数使用.
//启动微信
launch("com.tencent.mm");
app.launchPackage(packageName)#
packageName{ string } 应用包名
相当于app.launch(packageName).
app.getPackageName(appName)#
appName{ string } 应用名称
获取应用名称对应的已安装的应用的包名. 如果该找不到该应用, 返回null;如果该名称对应多个应用, 则只返回其中某一个的包名.
该函数也可以作为全局函数使用.
var name = getPackageName("QQ"); //返回"com.tencent.mobileqq"
app.getAppName(packageName)#
packageName{ string } 应用包名
获取应用包名对应的已安装的应用的名称. 如果该找不到该应用, 返回null.
该函数也可以作为全局函数使用.
var name = getAppName("com.tencent.mobileqq"); //返回"QQ"
app.openAppSetting(packageName)#
packageName{ string } 应用包名
打开应用的详情页(设置页). 如果找不到该应用, 返回false; 否则返回true.
该函数也可以作为全局函数使用.
app.viewFile(path)#
path{ string } 文件路径
用其他应用查看文件. 文件不存在的情况由查看文件的应用处理.
如果找不出可以查看该文件的应用, 则抛出ActivityNotException.
//查看文本文件
app.viewFile("/sdcard/1.txt");
app.editFile(path)#
path{ string } 文件路径
用其他应用编辑文件. 文件不存在的情况由编辑文件的应用处理.
如果找不出可以编辑该文件的应用, 则抛出ActivityNotException.
//编辑文本文件
app.editFile("/sdcard/1.txt/);
app.uninstall(packageName)#
packageName{ string } 应用包名
卸载应用. 执行后会会弹出卸载应用的提示框. 如果该包名的应用未安装, 由应用卸载程序处理, 可能弹出"未找到应用"的提示.
//卸载QQ
app.uninstall("com.tencent.mobileqq");
app.openUrl(url)#
url{ string } 网站的Url, 如果不以"http://"或"https://"开头则默认是"http://".
用浏览器打开网站url.
如果没有安装浏览器应用, 则抛出ActivityNotException.
app.sendEmail(options)#
根据选项options调用邮箱应用发送邮件. 这些选项均是可选的.
如果没有安装邮箱应用, 则抛出ActivityNotException.
//发送邮件给10086@qq.com和10001@qq.com.
app.sendEmail({
email: ["10086@qq.com", "10001@qq.com"],
subject: "这是一个邮件标题",
text: "这是邮件正文"
});
app.startActivity(name)#
name{ string } 活动名称, 可选的值为:console日志界面settings设置界面
启动Auto.js的特定界面. 该函数在Auto.js内运行则会打开Auto.js内的界面, 在打包应用中运行则会打开打包应用的相应界面.
app.startActivity("console");
app.intent(options)#
options{ Object } 选项, 包括:action{ string } 意图的Action, 指意图要完成的动作, 是一个字符串常量, 比如"android.intent.action.SEND". 当action以"android.intent.action"开头时, 可以省略前缀, 直接用"SEND"代替. 参见Actions.type{ string } 意图的MimeType, 表示和该意图直接相关的数据的类型, 表示比如"text/plain"为纯文本类型.data{ string } 意图的Data, 表示和该意图直接相关的数据, 是一个Uri, 可以是文件路径或者Url等. 例如要打开一个文件, action为"android.intent.action.VIEW", data为"file:///sdcard/1.txt".category{ Array } 意图的类别. 比较少用. 参见Categories.packageName{ string } 目标包名className{ string } 目标Activity或Service等组件的名称extras{ Object } 以键值对构成的这个Intent的Extras(额外信息). 提供该意图的其他信息, 例如发送邮件时的邮件标题、邮件正文. 参见Extras.flags{ Array } intent的标识, 字符串数组, 例如["activity_new_task", "grant_read_uri_permission"]. 参见Flags.[v4.1.0新增]
root{ Boolea } 是否以root权限启动、发送该intent. 使用该参数后, 不能使用context.startActivity()等方法, 而应该直接使用诸如app.startActivity({...})的方法.[v4.1.0新增]
根据选项, 构造一个意图Intent对象.
例如:
//打开应用来查看图片文件
var i = app.intent({
action: "VIEW",
type: "image/png",
data: "file:///sdcard/1.png"
});
context.startActivity(i);
需要注意的是, 除非应用专门暴露Activity出来, 否则在没有root权限的情况下使用intent是无法跳转到特定Activity、应用的特定界面的. 例如我们能通过Intent跳转到QQ的分享界面, 是因为QQ对外暴露了分享的Activity;而在没有root权限的情况下, 我们无法通过intent跳转到QQ的设置界面, 因为QQ并没有暴露这个Activity.
但如果有root权限, 则在intent的参数加上"root": true即可. 例如使用root权限跳转到Auto.js的设置界面为:
app.startActivity({
packageName: "org.autojs.autojs",
className: "org.autojs.autojs.ui.settings.SettingsActivity_",
root: true
});
另外, 关于intent的参数如何获取的问题, 一些intent是意外发现并且在网络中传播的(例如跳转QQ聊天窗口是因为QQ给网页提供了跳转到客服QQ的方法), 如果要自己获取活动的intent的参数, 可以通过例如"intent记录", "隐式启动"等应用拦截内部intent或者查询暴露的intent. 其中拦截内部intent需要XPosed框架, 或者可以通过反编译等手段获取参数. 总之, 没有简单直接的方法.
更多信息, 请百度安卓Intent或参考Android指南: Intent.
app.startActivity(options)#
options{ Object } 选项
根据选项构造一个Intent, 并启动该Activity.
app.startActivity({
action: "SEND",
type: "text/plain",
data: "file:///sdcard/1.txt"
});
app.sendBroadcast(options)#
options{ Object } 选项
根据选项构造一个Intent, 并发送该广播.
app.startService(options)#
options{ Object } 选项
根据选项构造一个Intent, 并启动该服务.
app.sendBroadcast(name)#
[v4.1.0新增]
name{ string } 特定的广播名称, 包括:inspect_layout_hierarchy布局层次分析inspect_layout_bounds布局范围
发送以上特定名称的广播可以触发Auto.js的布局分析, 方便脚本调试. 这些广播在Auto.js发送才有效, 在打包的脚本上运行将没有任何效果.
app.sendBroadcast("inspect_layout_bounds");
app.intentToShell(options)#
[v4.1.0新增]
options{ Object } 选项
根据选项构造一个Intent, 转换为对应的shell的intent命令的参数.
例如:
shell("am start " + app.intentToShell({
packageName: "org.autojs.autojs",
className: "org.autojs.autojs.ui.settings.SettingsActivity_"
}), true);
参见intent参数的规范.
app.parseUri(uri)#
[v4.1.0新增]
uri{ string } 一个代表Uri的字符串, 例如"file:///sdcard/1.txt", "https://www.autojs.org"- 返回 { Uri } 一个代表Uri的对象, 参见android.net.Uri.
解析uri字符串并返回相应的Uri对象. 即使Uri格式错误, 该函数也会返回一个Uri对象, 但之后如果访问该对象的scheme, path等值可能因解析失败而返回null.
需要注意的是, 在高版本Android上, 由于系统限制直接在Uri暴露文件的绝对路径, 因此如果uri字符串是文件file://..., 返回的Uri会是诸如content://...的形式.
app.getUriForFile(path)#
[v4.1.0新增]
path{ string } 文件路径, 例如"/sdcard/1.txt"- 返回 { Uri } 一个指向该文件的Uri的对象, 参见android.net.Uri.
从一个文件路径创建一个uri对象. 需要注意的是, 在高版本Android上, 由于系统限制直接在Uri暴露文件的绝对路径, 因此返回的Uri会是诸如content://...的形式.
app.getInstalledApps([options])#
options{ Object } 选项, 包括:get: 指定返回的应用信息中包含的信息"activities"应用的Activity组件信息"configurations"应用的硬件配置"gids"应用的group id"instrumentation"应用的Instrumentation信息"intent_filters"应用的意图过滤"meta_data"应用的元信息(默认)"permissions"应用的权限信息"providers"应用的ContentProvider组件信息"receivers"应用的BroadcastReceiver组件信息"services"应用的Service组件信息"shared_library_files"应用的动态链接库文件信息"signatures"应用的签名信息(已弃用"signing_certificates"应用的签名信息"uri_permission_patterns""disabled_components"被卸载的但保留了数据的应用"disabled_until_used_components"禁用直到被使用的组件"uninstalled_packages"被卸载的但保留了数据的应用
match: 指定要匹配的应用列表"uninstalled_packages"被卸载的但保留了数据的应用"disabled_components"被禁用的组件"disabled_until_used_components"禁用直到被使用的组件"system_only"只匹配系统应用"factory_only"只匹配预装应用"apex"APEX应用
- 返回 { Array\<ApplicationInfo> }
返回为当前用户安装的所有应用程序包的列表. 如果设置了match选项 uninstalled_packages, 则包括被删除但保留了数据的应用程序.
获取安装的应用列表.
返回值是ApplicationInfo对象的数组. 如果没有安装任何应用, 则返回一个空数组.
选项options的match选项用于指定要返回哪些应用程序, get选项用于指定返回的应用程序携带哪些信息.
let apps = $app.getInstalledApps({
matcg
})
颜色 (Colors)#
此章节待补充或完善...
Marked by SuperMonster003 on Jan 21, 2023.
颜色表示#
AutoJs6 支持以下方式表示一个颜色:
- 颜色代码 (ColorHex)
- 字面量
#RGB(如#F00表示红色, 相当于#FF0000)#RRGGBB(如#FF0000表示红色)#AARRGGBB(如#80FF0000表示半透明红色)
- 方法
- colors.toHex (如
colors.toHex(0xFF0000)表示红色对应的颜色字符串, 结果为#FF0000) - colors.toFullHex (如
colors.toFullHex(0xFF0000)表示红色对应的完全颜色字符串, 结果为#FFFF0000) - ... ...
- colors.toHex (如
- 字面量
- 颜色整数 (ColorInt)
- 字面量
0xAARRGGBB(如0x8000FF00在Java的Integer范围对应值表示半透明绿色)
- 方法
- colors.rgb (如
colors.rgb(255, 0, 0)表示红色) - colors.argb (如
colors.argb(128, 255, 0, 0)表示半透明红色) - colors.rgba (如
colors.rgba(255, 0, 0, 128)表示半透明红色) - colors.hsv (如
colors.hsv(0, 1, 1)表示红色) - colors.hsva (如
colors.rgba(0, 1, 1, 0.5)表示半透明红色) - colors.hsl (如
colors.hsl(0, 1, 0.5)表示红色) - colors.hsla (如
colors.hsl(0, 1, 0.5, 0.5)表示半透明红色) - colors.toInt (如
colors.toInt('#FF0000')表示红色对应的颜色整数, 结果为-65536) - ... ...
- colors.rgb (如
- 常量
- colors.RED (Android 颜色列表 的红色颜色整数)
- colors.BLACK (Android 颜色列表 的黑色颜色整数)
- ... ...
- colors.css.RED (Css 颜色列表 的红色颜色整数)
- colors.css.BLACK (Css 颜色列表 的黑色颜色整数)
- ... ...
- colors.web.RED (Web 颜色列表 的红色颜色整数)
- colors.web.BLACK (Web 颜色列表 的黑色颜色整数)
- ... ...
- colors.material.ORANGE (Material 颜色列表 的橙色颜色整数)
- colors.material.ORANGE_300 (Material 颜色列表 的 300 色号橙色颜色整数)
- ... ...
- 字面量
- 颜色分量数组 (ColorComponents)
- 方法
- colors.toRgb (颜色分量数组
[R,G,B]) - colors.toRgba (颜色分量数组
[R,G,B,A]) - colors.toArgb (颜色分量数组
[A,R,G,B]) - colors.toHsv (颜色分量数组
[H,S,V]) - colors.toHsva (颜色分量数组
[H,S,V,A]) - colors.toHsl (颜色分量数组
[H,S,L]) - colors.toHsla (颜色分量数组
[H,S,L,A]) - ... ...
- colors.toRgb (颜色分量数组
- 方法
- 颜色名称 (ColorName)
- 常量
- "red" (红色)
- "black" (黑色)
- ... ...
- 常量
colors
[m] toInt#
toInt(color)#
将颜色参数转换为 颜色整数 (ColorInt).
/* ColorHex - 颜色代码. */
colors.toInt('#CC5500'); // -3386112
colors.toInt('#C50'); // -3386112
colors.toInt('#FFCC5500'); // -3386112
/* ColorInt - 颜色整数. */
colors.toInt(0xFFCC5500); // -3386112
colors.toInt(colors.web.BURNT_ORANGE); // -3386112
/* ColorName - 颜色名称. */
colors.toInt('BURNT_ORANGE'); // -3386112
colors.toInt('burnt-orange'); // -3386112
[m] toHex#
toHex(color)#
6.2.0 Overload 1/3
将颜色参数转换为 颜色代码 (ColorHex).
/* ColorHex - 颜色代码. */
colors.toHex('#CC5500'); // #CC5500
colors.toHex('#C50'); // #CC5500
colors.toHex('#FFCC5500'); // #CC5500
/* ColorInt - 颜色整数. */
colors.toHex(0xFFCC5500); // #CC5500
colors.toHex(colors.web.BURNT_ORANGE); // #CC5500
/* ColorName - 颜色名称. */
colors.toHex('BURNT_ORANGE'); // #CC5500
colors.toHex('burnt-orange'); // #CC5500
当 A (alpha) 分量为 100% (255/255;100/100) 时, FF 会自动省略,
如 #FFC0C0C0 将自动转换为 #C0C0C0, 此方法相当于 toHex(color, 'auto').
toHex(color, alpha)#
6.2.0 Overload 2/3
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- [alpha = 'auto'] { boolean |
'keep'|'none'|'auto'} - A (alpha) 分量参数 - returns { ColorHex } - 颜色代码
将颜色参数转换为 颜色代码 (ColorHex), 并根据 alpha 参数决定颜色代码 A (alpha) 分量的显示状态.
A (alpha) 分量参数取值表:
| 取值 | 含义 | 默认 |
|---|---|---|
| 'keep' / true | 强制显示 A 分量, 不论 A 分量是否为 0xFF | |
| 'none' / false | 强制去除 A 分量, 只保留 R / G / B 分量 | |
| 'auto' | 根据 A 分量是否为 0xFF 自动决定显示状态 | √ |
let cA = '#AAC0C0C0';
let cB = '#FFC0C0C0';
let cC = '#C0C0C0';
colors.toHex(cA, 'auto'); /* #AAC0C0C0, 'auto' 参数可省略. */
colors.toHex(cB, 'auto'); /* #C0C0C0, 'auto' 参数可省略. */
colors.toHex(cC, 'auto'); /* #C0C0C0, 'auto' 参数可省略. */
/* cA 舍弃 A 分量. */
colors.toHex(cA, false); // #C0C0C0
colors.toHex(cA, 'none'); /* 同上. */
/* cB 保留 A 分量. */
colors.toHex(cB, true); // #FFC0C0C0
colors.toHex(cB, 'keep'); /* 同上. */
/* cC 强制显示 A 分量. */
colors.toHex(cC, true); // #FFC0C0C0
colors.toHex(cC, 'keep'); /* 同上. */
toHex(color, length)#
6.2.0 Overload 3/3
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- length {
8|6|3} - Hex 代码长度参数 - returns { ColorHex } - 颜色代码
将颜色参数转换为 颜色代码 (ColorHex), 并根据 length 参数决定颜色代码的显示状态.
Hex 代码长度参数取值表:
| 取值 | 含义 |
|---|---|
| 8 | 强制显示 A 分量, 结果格式为 #AARRGGBB |
| 6 | 强制去除 A 分量, 结果格式为 #RRGGBB |
| 3 | 强制去除 A 分量, 结果格式为 #RGB |
let cA = '#AA9966CC';
let cB = '#FF9966CC';
let cC = '#9966CC';
let cD = '#FAEBD7';
/* 转换为 8 长度颜色代码, 强制保留 A 分量. */
colors.toHex(cA, 8); // #AA9966CC
colors.toHex(cB, 8); // #FF9966CC
colors.toHex(cC, 8); // #FF9966CC
colors.toHex(cD, 8); // #FFFAEBD7
/* 转换为 6 长度颜色代码, 强制去除 A 分量. */
colors.toHex(cA, 6); // #9966CC
colors.toHex(cB, 6); // #9966CC
colors.toHex(cC, 6); // #9966CC
colors.toHex(cD, 6); // #FAEBD7
/* 转换为 3 长度颜色代码, 强制去除 A 分量. */
colors.toHex(cA, 3); // #96C
colors.toHex(cB, 3); // #96C
colors.toHex(cC, 3); // #96C
colors.toHex(cD, 3); /* 抛出异常. */
[m] toFullHex#
toFullHex(color)#
将颜色参数强制转换为 颜色代码 (ColorHex) 的完整形式 (#AARRGGBB).
此方法为 colors.toHex(color, 8) 的别名方法.
colors.toHex('#CC5500'); // #CC5500
colors.toFullHex('#CC5500'); // #FFCC5500
[m] parseColor#
parseColor(color)#
将颜色参数转换为 颜色整数 (ColorInt).
类似 toInt, 但参数接受范围相对狭小且类型及数值要求更加严格.
parseColor 的颜色参数仅支持六位数及八位数颜色代码及部分颜色名称.
支持的颜色名称 (不区分大小写):
'aqua', 'black', 'blue', 'cyan', 'darkgray', 'darkgrey',
'fuchsia', 'gray', 'green', 'grey', 'lightgray',
'lightgrey', 'lime', 'magenta', 'maroon', 'navy', 'olive',
'purple', 'red', 'silver', 'teal', 'white', 'yellow'`.
下表列出部分 toInt 与 parseColor 传参后的结果对照:
| 参数 | toInt | parseColor |
|---|---|---|
| 'blue' | -16776961 | -16776961 |
| 'burnt-orange' | -3386112 | # 抛出异常 # |
| '#FFCC5500' | -3386112 | -3386112 |
| '#CC5500' | -3386112 | -3386112 |
| '#C50' | -3386112 | # 抛出异常 # |
| 0xFFCC5500 | -3386112 | # 抛出异常 # |
| colors.web.BURNT_ORANGE | -3386112 | # 抛出异常 # |
除非需要考虑多版本兼容, 否则建议始终使用 toInt 替代 parseColor.
[m] toString#
toString(color)#
[6.2.0] Overload 1/3
将颜色参数转换为 颜色代码 (ColorHex).
toHex(color) 的别名方法.
toString(color, alpha)#
6.2.0 Overload 2/3
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- [alpha = 'auto'] { boolean |
'keep'|'none'|'auto'} - A (alpha) 分量参数 - returns { ColorHex } - 颜色代码
将颜色参数转换为 颜色代码 (ColorHex), 并根据 alpha 参数决定颜色代码 A (alpha) 分量的显示状态.
toHex(color, alpha) 的别名方法.
toString(color, length)#
6.2.0 Overload 3/3
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- length {
8|6|3} - Hex 代码长度参数 - returns { ColorHex } - 颜色代码
将颜色参数转换为 颜色代码 (ColorHex), 并根据 length 参数决定颜色代码的显示状态.
toHex(color, length) 的别名方法.
[m] alpha#
alpha(color)#
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- returns { IntRange[0..255] }
获取颜色的 A (alpha) 分量, 取值范围 [0..255].
colors.alpha('#663399'); // 255
colors.alpha(colors.TRANSPARENT); // 0
colors.alpha('#05060708'); // 5
[m] alphaDouble#
alphaDouble(color)#
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- returns { Range[0..1] }
获取颜色的 A (alpha) 分量, 取值范围 [0..1].
colors.alphaDouble('#663399'); // 1
colors.alphaDouble(colors.TRANSPARENT); // 0
colors.alphaDouble('#05060708'); // 0.0196078431372549
[m] red#
red(color)#
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- returns { IntRange[0..255] }
获取颜色的 R (red) 分量, 取值范围 [0..255].
colors.red('#663399'); // 102
colors.red(colors.TRANSPARENT); // 0
colors.red('#05060708'); // 6
[m] green#
green(color)#
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- returns { IntRange[0..255] }
获取颜色的 G (green) 分量, 取值范围 [0..255].
colors.green('#663399'); // 51
colors.green(colors.TRANSPARENT); // 0
colors.green('#05060708'); // 7
[m] blue#
blue(color)#
- color { ColorHex | ColorInt | ColorName } - 颜色参数
- returns { IntRange[0..255] }
获取颜色的 B (blue) 分量, 取值范围 [0..255].
colors.blue('#663399'); // 153
colors.blue(colors.TRANSPARENT); // 0
colors.blue('#05060708'); // 8
[m] rgb#
rgb(color)#
[6.2.0] Overload 1/3
获取 color 参数对应的 颜色整数 (ColorInt).
color 参数为颜色代码时, 支持情况如下:
| 格式 | 备注 |
|---|---|
| #RRGGBB | 正常 |
| #RGB | 正常 |
| #AARRGGBB | A (alpha) 分量被忽略 |
方法调用结果的 A (alpha) 分量恒为 255, 意味着 color 参数中的 A 分量信息将被忽略.
colors.rgb('#663399');
colors.rgb('#DE663399'); /* 同上, A 分量被忽略. */
rgb(red, green, blue)#
6.2.0 Overload 2/3
- red { ColorComponent } - 颜色分量 - R (red)
- green { ColorComponent } - 颜色分量 - G (green)
- blue { ColorComponent } - 颜色分量 - B (blue)
- returns { ColorInt }
通过 颜色分量 获取 颜色整数 (ColorInt).
colors.rgb(255, 128, 9);
colors.rgb(0xFF, 0x80, 0x09); /* 同上. */
colors.rgb('#FF8009'); /* 同上. */
colors.rgb(1, 0.5, '3.53%'); /* 同上. */
rgb(components)#
6.2.0 Overload 3/3
- components { ColorComponents[] } - 颜色分量数组
- returns { ColorInt }
通过 颜色分量数组 获取 颜色整数 (ColorInt).
colors.rgb([ 255, 128, 9 ]);
colors.rgb([ 0xFF, 0x80, 0x09 ]); /* 同上. */
colors.rgb([ 1, 0.5, '3.53%' ]); /* 同上. */
[m] argb#
argb(color)#
[6.2.0] Overload 1/3
获取 color 参数对应的 颜色整数 (ColorInt).
color 参数为颜色代码时, 支持情况如下:
| 格式 | 备注 |
|---|---|
| #RRGGBB | A (alpha) 分量为 0xFF |
| #RGB | A (alpha) 分量为 0xFF |
| #AARRGGBB | 正常 |
colors.argb('#663399'); /* 相当于 argb('#FF663399') . */
colors.argb('#DE663399'); /* 结果不同上. */
argb(alpha, red, green, blue)#
6.2.0 Overload 2/3
- alpha { ColorComponent } - 颜色分量 - A (alpha)
- red { ColorComponent } - 颜色分量 - R (red)
- green { ColorComponent } - 颜色分量 - G (green)
- blue { ColorComponent } - 颜色分量 - B (blue)
- returns { ColorInt }
通过 颜色分量 获取 颜色整数 (ColorInt).
colors.argb(64, 255, 128, 9);
colors.argb(0x40, 0xFF, 0x80, 0x09); /* 同上. */
colors.argb('#40FF8009'); /* 同上. */
colors.argb(0.25, 1, 0.5, '3.53%'); /* 同上. */
argb(components)#
6.2.0 Overload 3/3
- components { ColorComponents[] } - 颜色分量数组
- returns { ColorInt }
通过 颜色分量数组 获取 颜色整数 (ColorInt).
colors.argb([ 64, 255, 128, 9 ]);
colors.argb([ 0x40, 0xFF, 0x80, 0x09 ]); /* 同上. */
colors.argb([ 0.25, 1, 0.5, '3.53%' ]); /* 同上. */
[m] rgba#
rgba(color)#
[6.2.0] Overload 1/3
获取 color 参数对应的 颜色整数 (ColorInt).
color 参数为颜色代码时, 支持情况如下:
| 格式 | 备注 |
|---|---|
| #RRGGBB | A (alpha) 分量为 0xFF |
| #RGB | A (alpha) 分量为 0xFF |
| #RRGGBBAA | 正常 |
colors.rgba('#663399'); /* 相当于 rgba('#663399FF') . */
colors.rgba('#663399FF'); /* 结果同上. */
colors.rgba('#FF663399'); /* 结果不同上. */
注意区分 colors.rgba 与 colors.argb:
colors.rgba('#11335577'); /* A (alpha) 分量为 0x77 . */
colors.argb('#11335577'); /* A (alpha) 分量为 0x11 . */
rgba(red, green, blue, alpha)#
6.2.0 Overload 2/3
- red { ColorComponent } - 颜色分量 - R (red)
- green { ColorComponent } - 颜色分量 - G (green)
- blue { ColorComponent } - 颜色分量 - B (blue)
- alpha { ColorComponent } - 颜色分量 - A (alpha)
- returns { ColorInt }
通过 颜色分量 获取 颜色整数 (ColorInt).
colors.rgba(255, 128, 9, 64);
colors.rgba(0xFF, 0x80, 0x09, 0x40); /* 同上. */
colors.rgba('#FF800940'); /* 同上. */
colors.rgba(1, 0.5, '3.53%', 0.25); /* 同上. */
rgba(components)#
6.2.0 Overload 3/3
- components { ColorComponents[] } - 颜色分量数组
- returns { ColorInt }
通过 颜色分量数组 获取 颜色整数 (ColorInt).
colors.rgba([ 255, 128, 9, 64 ]);
colors.rgba([ 0xFF, 0x80, 0x09, 0x40 ]); /* 同上. */
colors.rgba([ 1, 0.5, '3.53%', 0.25 ]); /* 同上. */
hsv(hue, saturation, value)#
6.2.0 Overload 1/2
- hue { ColorComponent } - 颜色分量 - H (hue)
- saturation { ColorComponent } - 颜色分量 - S (saturation)
- value { ColorComponent } - 颜色分量 - V (value)
- returns { ColorInt }
通过 颜色分量 获取 颜色整数 (ColorInt).
colors.hsv(90, 80, 64);
colors.hsv(90, 0.8, 0.64); /* 同上. */
colors.hsv(0.25, 0.8, 0.64); /* 同上. */
colors.hsv('25%', '80%', '64%'); /* 同上. */
hsv(components)#
6.2.0 Overload 2/2
- components { ColorComponents[] } - 颜色分量数组
- returns { ColorInt }
通过 颜色分量数组 获取 颜色整数 (ColorInt).
colors.hsv([ 90, 80, 64 ]);
colors.hsv([ 90, 0.8, 0.64 ]); /* 同上. */
colors.hsv([ 0.25, 0.8, 0.64 ]); /* 同上. */
colors.hsv([ '25%', '80%', '64%' ]); /* 同上. */
[m] hsva#
//// -=-= PENDING =-=- ////
[m] hsl#
//// -=-= PENDING =-=- ////
[m] hsla#
//// -=-= PENDING =-=- ////
[m] toRgb#
//// -=-= PENDING =-=- ////
[m] toRgba#
//// -=-= PENDING =-=- ////
[m] toArgb#
//// -=-= PENDING =-=- ////
[m] toHsv#
//// -=-= PENDING =-=- ////
[m] toHsva#
//// -=-= PENDING =-=- ////
[m] toHsl#
//// -=-= PENDING =-=- ////
[m] toHsla#
//// -=-= PENDING =-=- ////
[m] isSimilar#
//// -=-= PENDING =-=- ////
[m] equals#
//// -=-= PENDING =-=- ////
[m] luminance#
//// -=-= PENDING =-=- ////
[p+] android#
//// -=-= PENDING =-=- ////
[p+] css#
//// -=-= PENDING =-=- ////
[p+] web#
//// -=-= PENDING =-=- ////
[p+] material#
//// -=-= PENDING =-=- ////
[p] BLACK#
//// -=-= PENDING =-=- ////
[p] BLUE#
//// -=-= PENDING =-=- ////
[p] CYAN#
//// -=-= PENDING =-=- ////
[p] AQUA#
//// -=-= PENDING =-=- ////
[p] DARK_GRAY#
//// -=-= PENDING =-=- ////
[p] DARK_GREY#
//// -=-= PENDING =-=- ////
[p] DKGRAY#
//// -=-= PENDING =-=- ////
[p] GRAY#
//// -=-= PENDING =-=- ////
[p] GREY#
//// -=-= PENDING =-=- ////
[p] GREEN#
//// -=-= PENDING =-=- ////
[p] LIME#
//// -=-= PENDING =-=- ////
[p] LIGHT_GRAY#
//// -=-= PENDING =-=- ////
[p] LIGHT_GREY#
//// -=-= PENDING =-=- ////
[p] LTGRAY#
//// -=-= PENDING =-=- ////
[p] MAGENTA#
//// -=-= PENDING =-=- ////
[p] FUCHSIA#
//// -=-= PENDING =-=- ////
[p] MAROON#
//// -=-= PENDING =-=- ////
[p] NAVY#
//// -=-= PENDING =-=- ////
[p] OLIVE#
//// -=-= PENDING =-=- ////
[p] PURPLE#
//// -=-= PENDING =-=- ////
[p] RED#
//// -=-= PENDING =-=- ////
[p] SILVER#
//// -=-= PENDING =-=- ////
[p] TEAL#
//// -=-= PENDING =-=- ////
[p] WHITE#
//// -=-= PENDING =-=- ////
[p] YELLOW#
//// -=-= PENDING =-=- ////
[p] TRANSPARENT#
//// -=-= PENDING =-=- ////
图像 (Images)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
images模块提供了一些手机设备中常见的图片处理函数, 包括截图、读写图片、图片剪裁、旋转、二值化、找色找图等.
该模块分为两个部分, 找图找色部分和图片处理部分.
需要注意的是, image对象创建后尽量在不使用时进行回收, 同时避免循环创建大量图片. 因为图片是一种占用内存比较大的资源, 尽管Auto.js通过各种方式(比如图片缓存机制、垃圾回收时回收图片、脚本结束时回收所有图片)尽量降低图片资源的泄漏和内存占用, 但是糟糕的代码仍然可以占用大量内存.
Image对象通过调用recycle()函数来回收. 例如:
// 读取图片
var img = images.read("./1.png");
//对图片进行操作
...
// 回收图片
img.recycle();
例外的是, caputerScreen()返回的图片不需要回收.
图片处理#
images.read(path)#
path{ string } 图片路径
读取在路径path的图片文件并返回一个Image对象. 如果文件不存在或者文件无法解码则返回null.
images.load(url)#
url{ string } 图片URL地址
加载在地址URL的网络图片并返回一个Image对象. 如果地址不存在或者图片无法解码则返回null.
images.copy(img)#
img{ Image } 图片- 返回 { Image }
复制一张图片并返回新的副本. 该函数会完全复制img对象的数据.
images.save(image, path[, format = "png", quality = 100])#
把图片image以PNG格式保存到path中. 如果文件不存在会被创建;文件存在会被覆盖.
//把图片压缩为原来的一半质量并保存
var img = images.read("/sdcard/1.png");
images.save(img, "/sdcard/1.jpg", "jpg", 50);
app.viewFile("/sdcard/1.jpg");
images.fromBase64(base64)#
base64{ string } 图片的Base64数据- 返回 { Image }
解码Base64数据并返回解码后的图片Image对象. 如果base64无法解码则返回null.
images.toBase64(img[, format = "png", quality = 100])#
把图片编码为base64数据并返回.
images.fromBytes(bytes)#
bytes{ byte[] } 字节数组
解码字节数组bytes并返回解码后的图片Image对象. 如果bytes无法解码则返回null.
images.toBytes(img[, format = "png", quality = 100])#
把图片编码为字节数组并返回.
images.clip(img, x, y, w, h)#
从图片img的位置(x, y)处剪切大小为w * h的区域, 并返回该剪切区域的新图片.
var src = images.read("/sdcard/1.png");
var clip = images.clip(src, 100, 100, 400, 400);
images.save(clip, "/sdcard/clip.png");
images.resize(img, size[, interpolation])#
[v4.1.0新增]
img{ Image } 图片size{ Array } 两个元素的数组[w, h], 分别表示宽度和高度;如果只有一个元素, 则宽度和高度相等interpolation{ string } 插值方法, 可选, 默认为"LINEAR"(线性插值), 可选的值有:NEAREST最近邻插值LINEAR线性插值(默认)AREA区域插值CUBIC三次样条插值LANCZOS4Lanczos插值 参见InterpolationFlags
返回 { Image }
调整图片大小, 并返回调整后的图片. 例如把图片放缩为200*300:images.resize(img, [200, 300]).
images.scale(img, fx, fy[, interpolation])#
[v4.1.0新增]
img{ Image } 图片fx{ number } 宽度放缩倍数fy{ number } 高度放缩倍数interpolation{ string } 插值方法, 可选, 默认为"LINEAR"(线性插值), 可选的值有:NEAREST最近邻插值LINEAR线性插值(默认)AREA区域插值CUBIC三次样条插值LANCZOS4Lanczos插值 参见InterpolationFlags
返回 { Image }
放缩图片, 并返回放缩后的图片. 例如把图片变成原来的一半:images.scale(img, 0.5, 0.5).
images.rotate(img, degress[, x, y])#
[v4.1.0新增]
img{ Image } 图片degress{ number } 旋转角度.x{ number } 旋转中心x坐标, 默认为图片中点y{ number } 旋转中心y坐标, 默认为图片中点- 返回 { Image }
将图片逆时针旋转degress度, 返回旋转后的图片对象.
例如逆时针旋转90度为images.rotate(img, 90).
images.concat(img1, image2[, direction])#
[v4.1.0新增]
img1{ Image } 图片1img2{ Image } 图片2- direction { string } 连接方向, 默认为"RIGHT", 可选的值有:
LEFT将图片2接到图片1左边RIGHT将图片2接到图片1右边TOP将图片2接到图片1上边BOTTOM将图片2接到图片1下边
- 返回 { Image }
连接两张图片, 并返回连接后的图像. 如果两张图片大小不一致, 小的那张将适当居中.
images.grayscale(img)#
[v4.1.0新增]
img{ Image } 图片- 返回 { Image }
灰度化图片, 并返回灰度化后的图片.
image.threshold(img, threshold, maxVal[, type])#
[v4.1.0新增]
img{ Image } 图片threshold{ number } 阈值maxVal{ number } 最大值type{ string } 阈值化类型, 默认为"BINARY", 参见ThresholdTypes, 可选的值:BINARYBINARY_INVTRUNCTOZEROTOZERO_INVOTSUTRIANGLE
返回 { Image }
将图片阈值化, 并返回处理后的图像. 可以用这个函数进行图片二值化. 例如:images.threshold(img, 100, 255, "BINARY"), 这个代码将图片中大于100的值全部变成255, 其余变成0, 从而达到二值化的效果. 如果img是一张灰度化图片, 这个代码将会得到一张黑白图片.
可以参考有关博客(比如threshold函数的使用)或者OpenCV文档threshold.
images.adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C)#
[v4.1.0新增]
img{ Image } 图片maxValue{ number } 最大值adaptiveMethod{ string } 在一个邻域内计算阈值所采用的算法, 可选的值有:MEAN_C计算出领域的平均值再减去参数C的值GAUSSIAN_C计算出领域的高斯均值再减去参数C的值
thresholdType{ string } 阈值化类型, 可选的值有:BINARYBINARY_INV
blockSize{ number } 邻域块大小C{ number } 偏移值调整量- 返回 { Image }
对图片进行自适应阈值化处理, 并返回处理后的图像.
可以参考有关博客(比如threshold与adaptiveThreshold)或者OpenCV文档adaptiveThreshold.
images.cvtColor(img, code[, dstCn])#
[v4.1.0新增]
img{ Image } 图片code{ string } 颜色空间转换的类型, 可选的值有一共有205个(参见ColorConversionCodes), 这里只列出几个:BGR2GRAYBGR转换为灰度BGR2HSVBGR转换为HSV
dstCn{ number } 目标图像的颜色通道数量, 如果不填写则根据其他参数自动决定.- 返回 { Image }
对图像进行颜色空间转换, 并返回转换后的图像.
可以参考有关博客(比如颜色空间转换)或者OpenCV文档cvtColor.
images.inRange(img, lowerBound, upperBound)#
[v4.1.0新增]
img{ Image } 图片lowerBound{ string } | { number } 颜色下界upperBound{ string } | { number } 颜色下界- 返回 { Image }
将图片二值化, 在lowerBound~upperBound范围以外的颜色都变成0, 在范围以内的颜色都变成255.
例如images.inRange(img, "#000000", "#222222").
images.interval(img, color, interval)#
[v4.1.0新增]
将图片二值化, 在color-interval ~ color+interval范围以外的颜色都变成0, 在范围以内的颜色都变成255. 这里对color的加减是对每个通道而言的.
例如images.interval(img, "#888888", 16), 每个通道的颜色值均为0x88, 加减16后的范围是[0x78, 0x98], 因此这个代码将把#787878~#989898的颜色变成#FFFFFF, 而把这个范围以外的变成#000000.
images.blur(img, size[, anchor, type])#
[v4.1.0新增]
img{ Image } 图片size{ Array } 定义滤波器的大小, 如[3, 3]anchor{ Array } 指定锚点位置(被平滑点), 默认为图像中心type{ string } 推断边缘像素类型, 默认为"DEFAULT", 可选的值有:CONSTANTiiiiii|abcdefgh|iiiiiii with some specified iREPLICATEaaaaaa|abcdefgh|hhhhhhhREFLECTfedcba|abcdefgh|hgfedcbWRAPcdefgh|abcdefgh|abcdefgREFLECT_101gfedcb|abcdefgh|gfedcbaTRANSPARENTuvwxyz|abcdefgh|ijklmnoREFLECT101same as BORDER_REFLECT_101DEFAULTsame as BORDER_REFLECT_101ISOLATEDdo not look outside of ROI
- 返回 { Image }
对图像进行模糊(平滑处理), 返回处理后的图像.
可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur.
images.medianBlur(img, size)#
[v4.1.0新增]
img{ Image } 图片size{ Array } 定义滤波器的大小, 如[3, 3]- 返回 { Image }
对图像进行中值滤波, 返回处理后的图像.
可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur.
images.gaussianBlur(img, size[, sigmaX, sigmaY, type])#
[v4.1.0新增]
img{ Image } 图片size{ Array } 定义滤波器的大小, 如[3, 3]sigmaX{ number } x方向的标准方差, 不填写则自动计算sigmaY{ number } y方向的标准方差, 不填写则自动计算type{ string } 推断边缘像素类型, 默认为"DEFAULT", 参见images.blur- 返回 { Image }
对图像进行高斯模糊, 返回处理后的图像.
可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档GaussianBlur.
images.matToImage(mat)#
[v4.1.0新增]
mat{ Mat } OpenCV的Mat对象- 返回 { Image }
把Mat对象转换为Image对象.
找图找色#
images.requestScreenCapture([landscape])#
landscape{ boolean } 布尔值, 表示将要执行的截屏是否为横屏. 如果landscape为false, 则表示竖屏截图; true为横屏截图.
向系统申请屏幕截图权限, 返回是否请求成功.
第一次使用该函数会弹出截图权限请求, 建议选择“总是允许”.
这个函数只是申请截图权限, 并不会真正执行截图, 真正的截图函数是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)#
path{ string } 截图保存路径
截取当前屏幕并以PNG格式保存到path中. 如果文件不存在会被创建;文件存在会被覆盖.
该函数不会返回任何值. 该函数也可以作为全局函数使用.
images.pixel(image, x, y)#
返回图片image在点(x, y)处的像素的ARGB值.
该值的格式为0xAARRGGBB, 是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型).
坐标系以图片左上角为原点. 以图片左侧边为y轴, 上侧边为x轴.
images.findColor(image, color, options)#
在图片中寻找颜色color. 找到时返回找到的点Point, 找不到时返回null.
选项包括:
region{ Array } 找色区域. 是一个两个或四个元素的数组. (region[0], region[1])表示找色区域的左上角;region[2]*region[3]表示找色区域的宽高. 如果只有region只有两个元素, 则找色区域为(region[0], region[1])到屏幕右下角. 如果不指定region选项, 则找色区域为整张图片.threshold{ number } 找色时颜色相似度的临界值, 范围为0~255(越小越相似, 0为颜色相等, 255为任何颜色都能匹配). 默认为4. threshold和浮点数相似度(0.0~1.0)的换算为 similarity = (255 - threshold) / 255.
该函数也可以作为全局函数使用.
一个循环找色的例子如下:
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])#
在图片img指定区域中找到颜色和color完全相等的某个点, 并返回该点的左边;如果没有找到, 则返回null.
找色区域通过x, y, width, height指定, 如果不指定找色区域, 则在整张图片中寻找.
该函数也可以作为全局函数使用.
示例: (通过找QQ红点的颜色来判断是否有未读消息)
requestScreenCapture();
launchApp("QQ");
sleep(1200);
var p = findColorEquals(captureScreen(), "#f64d30");
if(p){
toast("有未读消息");
}else{
toast("没有未读消息");
}
images.findMultiColors(img, firstColor, colors[, options])#
img{ Image } 要找色的图片firstColor{ number } | { string } 第一个点的颜色colors{ Array } 表示剩下的点相对于第一个点的位置和颜色的数组, 数组的每个元素为[x, y, color]options{ Object } 选项, 包括:region{ Array } 找色区域. 是一个两个或四个元素的数组. (region[0], region[1])表示找色区域的左上角;region[2]*region[3]表示找色区域的宽高. 如果只有region只有两个元素, 则找色区域为(region[0], region[1])到屏幕右下角. 如果不指定region选项, 则找色区域为整张图片.threshold{ number } 找色时颜色相似度的临界值, 范围为0~255(越小越相似, 0为颜色相等, 255为任何颜色都能匹配). 默认为4. threshold和浮点数相似度(0.0~1.0)的换算为 similarity = (255 - threshold) / 255.
多点找色, 类似于按键精灵的多点找色, 其过程如下:
- 在图片img中找到颜色firstColor的位置(x0, y0)
- 对于数组colors的每个元素[x, y, color], 检查图片img在位置(x + x0, y + y0)上的像素是否是颜色color, 是的话返回(x0, y0), 否则继续寻找firstColor的位置, 重新执行第1步
- 整张图片都找不到时返回
null
例如, 对于代码images.findMultiColors(img, "#123456", [[10, 20, "#ffffff"], [30, 40, "#000000"]]), 假设图片在(100, 200)的位置的颜色为#123456, 这时如果(110, 220)的位置的颜色为#fffff且(130, 240)的位置的颜色为#000000, 则函数返回点(100, 200).
如果要指定找色区域, 则在options中指定, 例如:
var p = images.findMultiColors(img, "#123456", [[10, 20, "#ffffff"], [30, 40, "#000000"]], {
region: [0, 960, 1080, 960]
});
images.detectsColor(image, color, x, y[, threshold = 16, algorithm = "diff"])#
image{ Image } 图片color{ number } | { string } 要检测的颜色x{ number } 要检测的位置横坐标y{ number } 要检测的位置纵坐标threshold{ number } 颜色相似度临界值, 默认为16. 取值范围为0~255.algorithm{ string } 颜色匹配算法, 包括:- "equal": 相等匹配, 只有与给定颜色color完全相等时才匹配.
- "diff": 差值匹配. 与给定颜色的R、G、B差的绝对值之和小于threshold时匹配.
"rgb": rgb欧拉距离相似度. 与给定颜色color的rgb欧拉距离小于等于threshold时匹配.
"rgb+": 加权rgb欧拉距离匹配(LAB Delta E).
- "hs": hs欧拉距离匹配. hs为HSV空间的色调值.
返回图片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{ Image } 大图片template{ Image } 小图片(模板)options{ Object } 找图选项
找图. 在大图片img中查找小图片template的位置(模块匹配), 找到时返回位置坐标(Point), 找不到时返回null.
选项包括:
threshold{ number } 图片相似度. 取值范围为0~1的浮点数. 默认值为0.9.region{ Array } 找图区域. 参见findColor函数关于region的说明.level{ number } 一般而言不必修改此参数. 不加此参数时该参数会根据图片大小自动调整. 找图算法是采用图像金字塔进行的, level参数表示金字塔的层次, level越大可能带来越高的找图效率, 但也可能造成找图失败(图片因过度缩小而无法分辨)或返回错误位置. 因此, 除非您清楚该参数的意义并需要进行性能调优, 否则不需要用到该参数.
该函数也可以作为全局函数使用.
一个最简单的找图例子如下:
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
})
该函数也可以作为全局函数使用.
images.matchTemplate(img, template, options)#
[v4.1.0新增]
img{ Image } 大图片template{ Image } 小图片(模板)options{ Object } 找图选项:threshold{ number } 图片相似度. 取值范围为0~1的浮点数. 默认值为0.9.region{ Array } 找图区域. 参见findColor函数关于region的说明.max{ number } 找图结果最大数量, 默认为5level{ number } 一般而言不必修改此参数. 不加此参数时该参数会根据图片大小自动调整. 找图算法是采用图像金字塔进行的, level参数表示金字塔的层次, level越大可能带来越高的找图效率, 但也可能造成找图失败(图片因过度缩小而无法分辨)或返回错误位置. 因此, 除非您清楚该参数的意义并需要进行性能调优, 否则不需要用到该参数.
- 返回 { MatchingResult }
在大图片中搜索小图片, 并返回搜索结果MatchingResult. 该函数可以用于找图时找出多个位置, 可以通过max参数控制最大的结果数量. 也可以对匹配结果进行排序、求最值等操作.
MatchingResult#
[v4.1.0新增]
matches#
- { Array } 匹配结果的数组.
数组的元素是一个Match对象:
point{ Point } 匹配位置similarity{ number } 相似度
例如:
var result = images.matchTemplate(img, template, {
max: 100
});
result.matches.forEach(match => {
log("point = " + match.point + ", similarity = " + match.similarity);
});
points#
- { Array } 匹配位置的数组.
first()#
- 返回 { Match }
第一个匹配结果. 如果没有任何匹配, 则返回null.
last()#
- 返回 { Match }
最后一个匹配结果. 如果没有任何匹配, 则返回null.
leftmost()#
- 返回 { Match }
位于大图片最左边的匹配结果. 如果没有任何匹配, 则返回null.
topmost()#
- 返回 { Match }
位于大图片最上边的匹配结果. 如果没有任何匹配, 则返回null.
rightmost()#
- 返回 { Match }
位于大图片最右边的匹配结果. 如果没有任何匹配, 则返回null.
bottommost()#
- 返回 { Match }
位于大图片最下边的匹配结果. 如果没有任何匹配, 则返回null.
best()#
- 返回 { Match }
相似度最高的匹配结果. 如果没有任何匹配, 则返回null.
worst()#
- 返回 { Match }
相似度最低的匹配结果. 如果没有任何匹配, 则返回null.
sortBy(cmp)#
对匹配结果进行排序, 并返回排序后的结果.
var result = images.matchTemplate(img, template, {
max: 100
});
log(result.sortBy("top-right"));
Image#
表示一张图片, 可以是截图的图片, 或者本地读取的图片, 或者从网络获取的图片.
Image.getWidth()#
返回以像素为单位图片宽度.
Image.getHeight()#
返回以像素为单位的图片高度.
Image.saveTo(path)#
path{ string } 路径
把图片保存到路径path. (如果文件存在则覆盖)
Image.pixel(x, y)#
返回图片image在点(x, y)处的像素的ARGB值.
该值的格式为0xAARRGGBB, 是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型).
坐标系以图片左上角为原点. 以图片左侧边为y轴, 上侧边为x轴.
##
Point#
findColor, findImage返回的对象. 表示一个点(坐标).
Point.x#
横坐标.
Point.y#
纵坐标.
按键 (Keys)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
按键模拟部分提供了一些模拟物理按键的全局函数, 包括Home、音量键、照相键等, 有的函数依赖于无障碍服务, 有的函数依赖于root权限.
一般来说, 以大写字母开头的函数都依赖于root权限. 执行此类函数时, 如果没有root权限, 则函数执行后没有效果, 并会在控制台输出一个警告.
back()#
- 返回 { boolean }
模拟按下返回键. 返回是否执行成功. 此函数依赖于无障碍服务.
home()#
- 返回 { boolean }
模拟按下Home键. 返回是否执行成功. 此函数依赖于无障碍服务.
powerDialog()#
- 返回 { boolean }
弹出电源键菜单. 返回是否执行成功. 此函数依赖于无障碍服务.
notifications()#
- 返回 { boolean }
拉出通知栏. 返回是否执行成功. 此函数依赖于无障碍服务.
quickSettings()#
- 返回 { boolean }
显示快速设置(下拉通知栏到底). 返回是否执行成功. 此函数依赖于无障碍服务.
recents()#
- 返回 { boolean }
显示最近任务. 返回是否执行成功. 此函数依赖于无障碍服务.
splitScreen()#
- 返回 { boolean }
分屏. 返回是否执行成功. 此函数依赖于无障碍服务, 并且需要系统自身功能的支持.
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)#
- text { string } 要输入的文字, 只能为英文或英文符号
输入文字text. 例如
Text("aaa");
KeyCode(code)#
- code { number } |
要按下的按键的数字代码或名称. 参见下表. 模拟物理按键. 例如 KeyCode(29)和KeyCode("KEYCODE_A")是按下A键.
附录: KeyCode对照表#
KeyCode KeyEvent Value
- KEYCODE_MENU 1
- KEYCODE_SOFT_RIGHT 2
- KEYCODE_HOME 3
- KEYCODE_BACK 4
- KEYCODE_CALL 5
- KEYCODE_ENDCALL 6
- KEYCODE_0 7
- KEYCODE_1 8
- KEYCODE_2 9
- KEYCODE_3 10
- KEYCODE_4 11
- KEYCODE_5 12
- KEYCODE_6 13
- KEYCODE_7 14
- KEYCODE_8 15
- KEYCODE_9 16
- KEYCODE_STAR 17
- KEYCODE_POUND 18
- KEYCODE_DPAD_UP 19
- KEYCODE_DPAD_DOWN 20
- KEYCODE_DPAD_LEFT 21
- KEYCODE_DPAD_RIGHT 22
- KEYCODE_DPAD_CENTER 23
- KEYCODE_VOLUME_UP 24
- KEYCODE_VOLUME_DOWN 25
- KEYCODE_POWER 26
- KEYCODE_CAMERA 27
- KEYCODE_CLEAR 28
- KEYCODE_A 29
- KEYCODE_B 30
- KEYCODE_C 31
- KEYCODE_D 32
- KEYCODE_E 33
- KEYCODE_F 34
- KEYCODE_G 35
- KEYCODE_H 36
- KEYCODE_I 37
- KEYCODE_J 38
- KEYCODE_K 39
- KEYCODE_L 40
- KEYCODE_M 41
- KEYCODE_N 42
- KEYCODE_O 43
- KEYCODE_P 44
- KEYCODE_Q 45
- KEYCODE_R 46
- KEYCODE_S 47
- KEYCODE_T 48
- KEYCODE_U 49
- KEYCODE_V 50
- KEYCODE_W 51
- KEYCODE_X 52
- KEYCODE_Y 53
- KEYCODE_Z 54
- KEYCODE_COMMA 55
- KEYCODE_PERIOD 56
- KEYCODE_ALT_LEFT 57
- KEYCODE_ALT_RIGHT 58
- KEYCODE_SHIFT_LEFT 59
- KEYCODE_SHIFT_RIGHT 60
- KEYCODE_TAB 61
- KEYCODE_SPACE 62
- KEYCODE_SYM 63
- KEYCODE_EXPLORER 64
- KEYCODE_ENVELOPE 65
- KEYCODE_ENTER 66
- KEYCODE_DEL 67
- KEYCODE_GRAVE 68
- KEYCODE_MINUS 69
- KEYCODE_EQUALS 70
- KEYCODE_LEFT_BRACKET 71
- KEYCODE_RIGHT_BRACKET 72
- KEYCODE_BACKSLASH 73
- KEYCODE_SEMICOLON 74
- KEYCODE_APOSTROPHE 75
- KEYCODE_SLASH 76
- KEYCODE_AT 77
- KEYCODE_NUM 78
- KEYCODE_HEADSETHOOK 79
- KEYCODE_FOCUS 80
- KEYCODE_PLUS 81
- KEYCODE_MENU 82
- KEYCODE_NOTIFICATION 83
- KEYCODE_SEARCH 84
- TAG_LAST_ KEYCODE 85
设备 (Device)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
device模块提供了与设备有关的信息与操作, 例如获取设备宽高, 内存使用率, IMEI, 调整设备亮度、音量等.
此模块的部分函数, 例如调整音量, 需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.width#
- { number }
设备屏幕分辨率宽度. 例如1080.
device.height#
- { number }
设备屏幕分辨率高度. 例如1920.
device.buildId#
- { string }
Either a changelist number, or a label like "M4-rc20".
修订版本号, 或者诸如"M4-rc20"的标识.
device.broad#
- { string }
The name of the underlying board, like "goldfish".
设备的主板(?)型号.
device.brand#
- { string }
The consumer-visible brand with which the product/hardware will be associated, if any.
与产品或硬件相关的厂商品牌, 如"Xiaomi", "Huawei"等.
device.device#
- { string }
The name of the industrial design.
设备在工业设计中的名称.
device.model#
- { string }
The end-user-visible name for the end product.
设备型号.
device.product#
- { string }
The name of the overall product.
整个产品的名称.
device.bootloader#
- { string }
The system bootloader version number.
设备Bootloader的版本.
device.hardware#
- { string }
The name of the hardware (from the kernel command line or /proc).
设备的硬件名称(来自内核命令行或者/proc).
device.fingerprint#
- { string }
A string that uniquely identifies this build. Do not attempt to parse this value.
构建(build)的唯一标识码.
device.serial#
- { string }
A hardware serial number, if available. Alphanumeric only, case-insensitive.
硬件序列号.
device.sdkInt#
- { number }
The user-visible SDK version of the framework; its possible values are defined in Build.VERSION_CODES.
安卓系统API版本. 例如安卓4.4的sdkInt为19.
device.incremental#
- { string }
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#
- { string }
The user-visible version string. E.g., "1.0" or "3.4b5".
Android系统版本号. 例如"5.0", "7.1.1".
device.baseOS#
- { string }
The base OS build the product is based on.
device.securityPatch#
- { string }
The user-visible security patch level.
安全补丁程序级别.
device.codename#
- { string }
The current development codename, or the string "REL" if this is a release build.
开发代号, 例如发行版是"REL".
device.getIMEI()#
- { string }
返回设备的IMEI.
device.getAndroidId()#
- { string }
返回设备的Android ID.
Android ID为一个用16进制字符串表示的64位整数, 在设备第一次使用时随机生成, 之后不会更改, 除非恢复出厂设置.
device.getMacAddress()#
- { string }
返回设备的Mac地址. 该函数需要在有WLAN连接的情况下才能获取, 否则会返回null.
可能的后续修改:未来可能增加有root权限的情况下通过root权限获取, 从而在没有WLAN连接的情况下也能返回正确的Mac地址, 因此请勿使用此函数判断WLAN连接.
device.getBrightness()#
- { number }
返回当前的(手动)亮度. 范围为0~255.
device.getBrightnessMode()#
- { number }
返回当前亮度模式, 0为手动亮度, 1为自动亮度.
device.setBrightness(b)#
b{ number } 亮度, 范围0~255
设置当前手动亮度. 如果当前是自动亮度模式, 该函数不会影响屏幕的亮度.
此函数需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.setBrightnessMode(mode)#
mode{ number } 亮度模式, 0为手动亮度, 1为自动亮度
设置当前亮度模式.
此函数需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.getMusicVolume()#
- { number } 整数值
返回当前媒体音量.
device.getNotificationVolume()#
- { number } 整数值
返回当前通知音量.
device.getAlarmVolume()#
- { number } 整数值
返回当前闹钟音量.
device.getMusicMaxVolume()#
- { number } 整数值
返回媒体音量的最大值.
device.getNotificationMaxVolume()#
- { number } 整数值
返回通知音量的最大值.
device.getAlarmMaxVolume()#
- { number } 整数值
返回闹钟音量的最大值.
device.setMusicVolume(volume)#
volume{ number } 音量
设置当前媒体音量.
此函数需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.setNotificationVolume(volume)#
volume{ number } 音量
设置当前通知音量.
此函数需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.setAlarmVolume(volume)#
volume{ number } 音量
设置当前闹钟音量.
此函数需要"修改系统设置"的权限. 如果没有该权限, 会抛出SecurityException并跳转到权限设置界面.
device.getBattery()#
- { number } 0.0~100.0的浮点数
返回当前电量百分比.
device.isCharging()#
- { boolean }
返回设备是否正在充电.
device.getTotalMem()#
- { number }
返回设备内存总量, 单位字节(B). 1MB = 1024 * 1024B.
device.getAvailMem()#
- { number }
返回设备当前可用的内存, 单位字节(B).
device.isScreenOn()#
- 返回 { boolean }
返回设备屏幕是否是亮着的. 如果屏幕亮着, 返回true; 否则返回false.
需要注意的是, 类似于vivo xplay系列的息屏时钟不属于"屏幕亮着"的情况, 虽然屏幕确实亮着但只能显示时钟而且不可交互, 此时isScreenOn()也会返回false.
device.wakeUp()#
唤醒设备. 包括唤醒设备CPU、屏幕等. 可以用来点亮屏幕.
device.wakeUpIfNeeded()#
如果屏幕没有点亮, 则唤醒设备.
device.keepScreenOn([timeout])#
timeout{ number } 屏幕保持常亮的时间, 单位毫秒. 如果不加此参数, 则一直保持屏幕常亮.
保持屏幕常亮.
此函数无法阻止用户使用锁屏键等正常关闭屏幕, 只能使得设备在无人操作的情况下保持屏幕常亮;同时, 如果此函数调用时屏幕没有点亮, 则会唤醒屏幕.
在某些设备上, 如果不加参数timeout, 只能在Auto.js的界面保持屏幕常亮, 在其他界面会自动失效, 这是因为设备的省电策略造成的. 因此, 建议使用比较长的时长来代替"一直保持屏幕常亮"的功能, 例如device.keepScreenOn(3600 * 1000).
可以使用device.cancelKeepingAwake()来取消屏幕常亮.
//一直保持屏幕常亮
device.keepScreenOn()
device.keepScreenDim([timeout])#
timeout{ number } 屏幕保持常亮的时间, 单位毫秒. 如果不加此参数, 则一直保持屏幕常亮.
保持屏幕常亮, 但允许屏幕变暗来节省电量. 此函数可以用于定时脚本唤醒屏幕操作, 不需要用户观看屏幕, 可以让屏幕变暗来节省电量.
此函数无法阻止用户使用锁屏键等正常关闭屏幕, 只能使得设备在无人操作的情况下保持屏幕常亮;同时, 如果此函数调用时屏幕没有点亮, 则会唤醒屏幕.
可以使用device.cancelKeepingAwake()来取消屏幕常亮.
device.cancelKeepingAwake()#
取消设备保持唤醒状态. 用于取消device.keepScreenOn(), device.keepScreenDim()等函数设置的屏幕常亮.
device.vibrate(millis)#
millis{ number } 震动时间, 单位毫秒
使设备震动一段时间.
//震动两秒
device.vibrate(2000);
device.cancelVibration()#
如果设备处于震动状态, 则取消震动.
存储 (Storages)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
storages模块提供了保存简单数据、用户配置等的支持. 保存的数据除非应用被卸载或者被主动删除, 否则会一直保留.
storages支持number, boolean, string等数据类型以及把Object, Array用JSON.stringify序列化存取.
storages保存的数据在脚本之间是共享的, 任何脚本只要知道storage名称便可以获取到相应的数据, 因此它不能用于敏感数据的储存. storages无法像Web开发中LocalStorage一样提供根据域名独立的存储, 因为脚本的路径随时可能改变.
storages.create(name)#
name{ string } 本地存储名称
创建一个本地存储并返回一个Storage对象. 不同名称的本地存储的数据是隔开的, 而相同名称的本地存储的数据是共享的.
例如在一个脚本中, 创建名称为ABC的存储并存入a=123:
var storage = storages.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)#
name{ string } 本地存储名称
删除一个本地存储以及他的全部数据. 如果该存储不存在, 返回false;否则返回true.
Storages#
Storage.get(key[, defaultValue])#
key{ string } 键值defaultValue{ any } 可选, 默认值
从本地存储中取出键值为key的数据并返回.
如果该存储中不包含该数据, 这时若指定了默认值参数则返回默认值, 否则返回undefined.
返回的数据可能是任意数据类型, 这取决于使用Storage.put保存该键值的数据时的数据类型.
Storage.put(key, value)#
key{ string } 键值value{ any } 值
把值value保存到本地存储中. value可以是undefined以外的任意数据类型. 如果value为undefined则抛出TypeError.
存储的过程实际上是使用JSON.stringify把value转换为字符串再保存, 因此value必须是可JSON化的才能被接受.
Storage.remove(key)#
key{ string } 键值
移除键值为key的数据. 不返回任何值.
Storage.contains(key)#
key{ string } 键值
返回该本地存储是否包含键值为key的数据. 是则返回true, 否则返回false.
Storage.clear()#
移除该本地存储的所有数据. 不返回任何值.
文件 (Files)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
files模块提供了一些常见的文件处理, 包括文件读写、移动、复制、删掉等.
一次性的文件读写可以直接使用files.read(), files.write(), files.append()等方便的函数, 但如果需要频繁读写或随机读写, 则使用open()函数打开一个文件对象来操作文件, 并在操作完毕后调用close()函数关闭文件.
files.isFile(path)#
返回路径path是否是文件.
log(files.isDir("/sdcard/文件夹/")); //返回false
log(files.isDir("/sdcard/文件.txt")); //返回true
files.isDir(path)#
返回路径path是否是文件夹.
log(files.isDir("/sdcard/文件夹/")); //返回true
log(files.isDir("/sdcard/文件.txt")); //返回false
files.isEmptyDir(path)#
返回文件夹path是否为空文件夹. 如果该路径并非文件夹, 则直接返回false.
files.join(parent, child)#
连接两个路径并返回, 例如files.join("/sdcard/", "1.txt")返回"/sdcard/1.txt".
files.create(path)#
创建一个文件或文件夹并返回是否创建成功. 如果文件已经存在, 则直接返回false.
files.create("/sdcard/新文件夹/");
files.createWithDirs(path)#
创建一个文件或文件夹并返回是否创建成功. 如果文件所在文件夹不存在, 则先创建他所在的一系列文件夹. 如果文件已经存在, 则直接返回false.
files.createWithDirs("/sdcard/新文件夹/新文件夹/新文件夹/1.txt");
files.exists(path)#
返回在路径path处的文件是否存在.
files.ensureDir(path)#
path{ string } 路径
确保路径path所在的文件夹存在. 如果该路径所在文件夹不存在, 则创建该文件夹.
例如对于路径"/sdcard/Download/ABC/1.txt", 如果/Download/文件夹不存在, 则会先创建Download, 再创建ABC文件夹.
files.read(path[, encoding = "utf-8"])#
读取文本文件path的所有内容并返回. 如果文件不存在, 则抛出FileNotFoundException.
log(files.read("/sdcard/1.txt"));
files.readBytes(path)#
path{ string } 路径- 返回 { byte[] }
读取文件path的所有内容并返回一个字节数组. 如果文件不存在, 则抛出FileNotFoundException.
注意, 该数组是Java的数组, 不具有JavaScript数组的forEach, slice等函数.
一个以16进制形式打印文件的例子如下:
var data = files.readBytes("/sdcard/1.png");
var sb = new java.lang.StringBuilder();
for(var i = 0; i < data.length; i++){
sb.append(data[i].toString(16));
}
log(sb.toString());
files.write(path, text[, encoding = "utf-8"])#
把text写入到文件path中. 如果文件存在则覆盖, 不存在则创建.
var text = "文件内容";
//写入文件
files.write("/sdcard/1.txt", text);
//用其他应用查看文件
app.viewFile("/sdcard/1.txt");
files.writeBytes(path, bytes)#
path{ string } 路径bytes{ byte[] } 字节数组, 要写入的二进制数据
把bytes写入到文件path中. 如果文件存在则覆盖, 不存在则创建.
files.append(path, text[, encoding = 'utf-8'])#
把text追加到文件path的末尾. 如果文件不存在则创建.
var text = "追加的文件内容";
files.append("/sdcard/1.txt", text);
files.append("/sdcard/1.txt", text);
//用其他应用查看文件
app.viewFile("/sdcard/1.txt");
files.appendBytes(path, text[, encoding = 'utf-8'])#
path{ string } 路径bytes{ byte[] } 字节数组, 要写入的二进制数据
把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()#
- 返回 { string }
返回SD卡路径. 所谓SD卡, 即外部存储器.
files.cwd()#
- 返回 { string }
返回脚本的"当前工作文件夹路径". 该路径指的是, 如果脚本本身为脚本文件, 则返回这个脚本文件所在目录;否则返回null获取其他设定路径.
例如, 对于脚本文件"/sdcard/脚本/1.js"运行files.cwd()返回"/sdcard/脚本/".
files.path(relativePath)#
返回相对路径对应的绝对路径. 例如files.path("./1.png"), 如果运行这个语句的脚本位于文件夹"/sdcard/脚本/"中, 则返回"/sdcard/脚本/1.png".
files.listDir(path[, filter])#
列出文件夹path下的满足条件的文件和文件夹的名称的数组. 如果不加filter参数, 则返回所有文件和文件夹.
列出sdcard目录下所有文件和文件夹为:
var arr = files.listDir("/sdcard/");
log(arr);
列出脚本目录下所有js脚本文件为:
var dir = "/sdcard/脚本/";
var jsFiles = files.listDir(dir, function(name){
return name.endsWith(".js") && files.isFile(files.join(dir, name));
});
log(jsFiles);
open(path[, mode = "r", encoding = "utf-8", bufferSize = 8192])#
打开一个文件. 根据打开模式返回不同的文件对象. 包括:
- "r": 返回一个ReadableTextFile对象.
- "w", "a": 返回一个WritableTextFile对象.
对于"w"模式, 如果文件并不存在, 则会创建一个, 已存在则会清空该文件内容;其他模式文件不存在会抛出FileNotFoundException.
ReadableTextFile#
可读文件对象.
ReadableTextFile.read()#
返回该文件剩余的所有内容的字符串.
ReadableTextFile.read(maxCount)#
maxCount{ Number } 最大读取的字符数量
读取该文件接下来最长为maxCount的字符串并返回. 即使文件剩余内容不足maxCount也不会出错.
ReadableTextFile.readline()#
读取一行并返回(不包含换行符).
ReadableTextFile.readlines()#
读取剩余的所有行, 并返回它们按顺序组成的字符串数组.
close()#
关闭该文件.
打开一个文件不再使用时务必关闭
PWritableTextFile#
可写文件对象.
PWritableTextFile.write(text)#
text{ string } 文本
把文本内容text写入到文件中.
PWritableTextFile.writeline(line)#
text{ string } 文本
把文本line写入到文件中并写入一个换行符.
PWritableTextFile.writelines(lines)#
lines{ Array } 字符串数组
把很多行写入到文件中....
PWritableTextFile.flush()#
把缓冲区内容输出到文件中.
PWritableTextFile.close()#
关闭文件. 同时会被缓冲区内容输出到文件.
打开一个文件写入后, 不再使用时务必关闭, 否则文件可能会丢失
引擎 (Engines)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
engines模块包含了一些与脚本环境、脚本运行、脚本引擎有关的函数, 包括运行其他脚本, 关闭脚本等.
例如, 获取脚本所在目录:
toast(engines.myEngine().cwd());
engines.execScript(name, script[, config])#
在新的脚本环境中运行脚本script. 返回一个ScriptExectuion对象.
所谓新的脚本环境, 指定是, 脚本中的变量和原脚本的变量是不共享的, 并且, 脚本会在新的线程中运行.
最简单的例子如下:
engines.execScript("hello world", "toast('hello world')");
如果要循环运行, 则:
//每隔3秒运行一次脚本, 循环10次
engines.execScript("hello world", "toast('hello world')", {
loopTimes: 10,
interval: 3000
});
用字符串来编写脚本非常不方便, 可以结合 Function.toString()的方法来执行特定函数:
function helloWorld(){
//注意, 这里的变量和脚本主体的变量并不共享
toast("hello world");
}
engines.execScript("hello world", "helloWorld();\n" + helloWorld.toString());
如果要传递变量, 则可以把这些封装成一个函数:
function exec(action, args){
args = args || {};
engines.execScript(action.name, action.name + "(" + JSON.stringify(args) + ");\n" + action.toString());
}
//要执行的函数, 是一个简单的加法
function add(args){
toast(args.a + args.b);
}
//在新的脚本环境中执行 1 + 2
exec(add, {a: 1, b:2});
engines.execScriptFile(path[, config])#
在新的脚本环境中运行脚本文件path. 返回一个ScriptExecution对象.
engines.execScriptFile("/sdcard/脚本/1.js");
engines.execAutoFile(path[, config])#
在新的脚本环境中运行录制文件path. 返回一个ScriptExecution对象.
engines.execAutoFile("/sdcard/脚本/1.auto");
engines.stopAll()#
停止所有正在运行的脚本. 包括当前脚本自身.
engines.stopAllAndToast()#
停止所有正在运行的脚本并显示停止的脚本数量. 包括当前脚本自身.
engines.myEngine()#
返回当前脚本的脚本引擎对象(ScriptEngine)
[v4.1.0新增]
特别的, 该对象可以通过execArgv来获取他的运行参数, 包括外部参数、intent等. 例如:
log(engines.myEngine().execArgv);
普通脚本的运行参数通常为空, 通过定时任务的广播启动的则可以获取到启动的intent.
engines.all()#
- 返回 { Array }
返回当前所有正在运行的脚本的脚本引擎ScriptEngine的数组.
log(engines.all());
ScriptExecution#
执行脚本时返回的对象, 可以通过他获取执行的引擎、配置等, 也可以停止这个执行.
要停止这个脚本的执行, 使用exectuion.getEngine().forceStop().
ScriptExecution.getEngine()#
返回执行该脚本的脚本引擎对象(ScriptEngine)
ScriptExecution.getConfig()#
返回该脚本的运行配置(ScriptConfig)
ScriptEngine#
脚本引擎对象.
ScriptEngine.forceStop()#
停止脚本引擎的执行.
ScriptEngine.cwd()#
- 返回 { string }
返回脚本执行的路径. 对于一个脚本文件而言为这个脚本所在的文件夹;对于其他脚本, 例如字符串脚本, 则为null或者执行时的设置值.
ScriptEngine.getSource()#
- 返回 ScriptSource
返回当前脚本引擎正在执行的脚本对象.
log(engines.myEngine().getSource());
ScriptEngine.emit(eventName[, ...args])#
eventName{ string } 事件名称...args{ any } 事件参数
向该脚本引擎发送一个事件, 该事件可以在该脚本引擎对应的脚本的events模块监听到并在脚本主线程执行事件处理.
例如脚本receiver.js的内容如下:
//监听say事件
events.on("say", function(words){
toastLog(words);
});
//保持脚本运行
setInterval(()=>{}, 1000);
同一目录另一脚本可以启动他并发送该事件:
//运行脚本
var e = engines.execScriptFile("./receiver.js");
//等待脚本启动
sleep(2000);
//向该脚本发送事件
e.getEngine().emit("say", "你好");
ScriptConfig#
脚本执行时的配置.
delay#
- { number }
延迟执行的毫秒数
interval#
- { number }
循环运行时两次运行之间的时间间隔
loopTimes#
- { number }
循环运行次数
getPath()#
- 返回 { Array }
返回一个字符串数组表示脚本运行时模块寻找的路径.
任务 (Tasks)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
模块 (Module)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
Auto.js 有一个简单的模块加载系统. 在 Auto.js 中, 文件和模块是一一对应的(每个文件被视为一个独立的模块).
例子, 假设有一个名为 foo.js 的文件:
var 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 = function (r) {
return PI * r * r;
};
circle.circumference = (r) => 2 * PI * r;
module.exports = circle;
circle.js 模块导出了 area() 和 circumference() 两个函数. 通过在特殊的 exports 对象上指定额外的属性, 函数和对象可以被添加到模块的根部.
模块内的本地变量是私有的. 在这个例子中, 变量 PI 是 circle.js 私有的, 不会影响到加载他的脚本的变量环境.
module.exports属性可以被赋予一个新的值(例如函数或对象).
如下, bar.js 会用到 square 模块, square 导出一个构造函数:
const square = require('square.js');
const mySquare = square(2);
console.log("正方形的面积是 %d", mySquare.area());
square 模块定义在 square.js 中:
// 赋值给 `exports` 不会修改模块, 必须使用 `module.exports`
module.exports = function(width) {
return {
area: () => width ** 2
};
};
插件 (Plugins)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
协程 (Continuation)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
控制台 (Console)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
控制台模块提供了一个和Web浏览器中相似的用于调试的控制台. 用于输出一些调试信息、中间结果等. console模块中的一些函数也可以直接作为全局函数使用, 例如log, print等.
console.show()#
显示控制台. 这会显示一个控制台的悬浮窗(需要悬浮窗权限).
console.hide()#
隐藏控制台悬浮窗.
console.clear()#
清空控制台.
console.log([data][, ...args])#
data{ any }...args{ any }
打印到控制台, 并带上换行符. 可以传入多个参数, 第一个参数作为主要信息, 其他参数作为类似于 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])#
data{ any }...args{ any }
与console.log类似, 但输出结果以灰色字体显示. 输出优先级低于log, 用于输出观察性质的信息.
console.info([data][, ...args])#
data{ any }...args{ any }
与console.log类似, 但输出结果以绿色字体显示. 输出优先级高于log, 用于输出重要信息.
console.warn([data][, ...args])#
data{ any }...args{ any }
与console.log类似, 但输出结果以蓝色字体显示. 输出优先级高于info, 用于输出警告信息.
console.error([data][, ...args])#
data{ any }...args{ any }
与console.log类似, 但输出结果以红色字体显示. 输出优先级高于warn, 用于输出错误信息.
console.assert(value, message)#
- value { any } 要断言的布尔值
- message { string } value为false时要输出的信息
断言. 如果value为false则输出错误信息message并停止脚本运行.
var a = 1 + 1;
console.assert(a == 2, "加法出错啦");
console.time([label])#
[v4.1.0新增]
label{ String } 计时器标签, 可省略
启动一个定时器, 用以计算一个操作的持续时间.
定时器由一个唯一的 label 标识.
当调用 console.timeEnd() 时, 可以使用相同的 label 来停止定时器, 并以毫秒为单位将持续时间输出到控制台.
重复启动同一个标签的定时器会覆盖之前启动同一标签的定时器.
console.timeEnd(label)#
[v4.1.0新增]
label{ String } 计时器标签
停止之前通过调用 console.time() 启动的定时器, 并打印结果到控制台.
调用 console.timeEnd() 后定时器会被删除. 如果不存在标签指定的定时器则会打印 NaNms.
console.time('求和');
var sum = 0;
for(let i = 0; i < 100000; i++){
sum += i;
}
console.timeEnd('求和');
// 打印 求和: xxx ms
console.trace([data][, ...args])#
[v4.1.0新增]
data{ any }...args{ any }
与console.log类似, 同时会打印出调用这个函数所在的调用栈信息(即当前运行的文件、行数等信息).
console.trace('Show me');
// 打印: (堆栈跟踪会根据被调用的跟踪的位置而变化)
// Show me
// at <test>:7
console.input(data[, ...args])#
data{ any }...args{ any }
与console.log一样输出信息, 并在控制台显示输入框等待输入. 按控制台的确认按钮后会将输入的字符串用eval计算后返回.
部分机型可能会有控制台不显示输入框的情况, 属于bug.
例如:
var n = console.input("请输入一个数字:");
//输入123之后:
toast(n + 1);
//显示124
console.rawInput(data[, ...args])#
data{ any }...args{ any }
与console.log一样输出信息, 并在控制台显示输入框等待输入. 按控制台的确认按钮后会将输入的字符串直接返回.
部分机型可能会有控制台不显示输入框的情况, 属于bug.
例如:
var n = console.rawInput("请输入一个数字:");
//输入123之后:
toast(n + 1);
//显示1231
console.setSize(w, h)#
设置控制台的大小, 单位像素.
console.show();
//设置控制台大小为屏幕的四分之一
console.setSize(device.width / 2, device.height / 2);
console.setPosition(x, y)#
设置控制台的位置, 单位像素.
console.show();
console.setPosition(100, 100);
console.setGlobalLogConfig(config)#
[v4.1.0新增]
config{ Object } 日志配置, 可选的项有:
设置日志保存的路径和配置. 例如把日志保存到"/sdcard/1.txt":
console.setGlobalLogConfig({
"file": "/sdcard/1.txt"
});
注意该函数会影响所有脚本的日志记录.
print(text)#
相当于log(text).
Shell#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
shell即Unix Shell, 在类Unix系统提供与操作系统交互的一系列命令.
很多程序可以用来执行shell命令, 例如终端模拟器.
在Auto.js大致等同于用adb执行命令"adb shell". 其实现包括两种方式:
- 通过
java.lang.Runtime.exec执行(shell, Tap, Home等函数) - 通过内嵌终端模拟器执行(RootAutomator, Shell等对象)
shell函数#
shell(cmd[, root])#
一次性执行命令cmd, 并返回命令的执行结果. 返回对象的其属性如下:
- code { number } 返回码. 执行成功时为0, 失败时为非0的数字.
- result { string } 运行结果(stdout输出结果)
- error { string } 运行的错误信息(stderr输出结果). 例如执行需要root权限的命令但没有授予root权限会返回错误信息"Permission denied".
示例(强制停止微信) :
var result = shell("am force-stop com.tencent.mm", true);
log(result);
console.show();
if(result.code == 0){
toast("执行成功");
}else{
toast("执行失败!请到控制台查看错误信息");
}
Shell#
shell函数通过用来一次性执行单条命令并获取结果. 如果有多条命令需要执行, 用Shell对象的效率更高. 这是因为, 每次运行shell函数都会打开一个单独的shell进程并在运行结束后关闭他, 这个过程需要一定的时间;而Shell对象自始至终使用同一个shell进程.
new Shell(root)#
- root { Boolean } 是否以root权限运行一个shell进程, 默认为false. 这将会影响其后使用该Shell对象执行的命令的权限
Shell对象的"构造函数".
var sh = new Shell(true);
//强制停止微信
sh.exec("am force-stop com.tencent.mm");
sh.exit();
Shell.exec(cmd)#
cmd{ string } 要执行的命令
执行命令cmd. 该函数不会返回任何值.
注意, 命令执行是"异步"的、非阻塞的. 也就是不会等待命令完成后才继续向下执行.
尽管这样的设计使用起来有很多不便之处, 但受限于终端模拟器, 暂时没有解决方式;如果后续能找到解决方案, 则将提供Shell.execAndWaitFor函数.
Shell.exit()#
直接退出shell. 正在执行的命令会被强制退出.
Shell.exitAndWaitFor()#
执行"exit"命令并等待执行命令执行完成、退出shell.
此函数会执行exit命令来正常退出shell.
Shell.setCallback(callback)#
- callback { Object } 回调函数
设置该Shell的回调函数, 以便监听Shell的输出. 可以包括以下属性:
- onOutput { Function } 每当shell有新的输出时便会调用该函数. 其参数是一个字符串.
- onNewLine { Function } 每当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 参数的规范.
选项包括:
- -D:启用调试.
- -W:等待启动完成.
- --start-profiler file:启动分析器并将结果发送到 file.
- -P file:类似于 --start-profiler, 但当应用进入空闲状态时分析停止.
- -R count:重复 Activity 启动 count 次数. 在每次重复前, 将完成顶部 Activity.
- -S:启动 Activity 前强行停止目标应用.
- --opengl-trace:启用 OpenGL 函数的跟踪.
- --user user_id | current:指定要作为哪个用户运行;如果未指定, 则作为当前用户运行.
startservice [options] intent#
启动 intent 指定的 Service(服务).
请参阅 intent 参数的规范.
选项包括:
- --user user_id | current:指定要作为哪个用户运行;如果未指定, 则作为当前用户运行.
force-stop package#
强行停止与 package(应用包名)关联的所有应用.
kill [options] package#
终止与 package(应用包名)关联的所有进程. 此命令仅终止可安全终止且不会影响用户体验的进程.
选项包括:
- --user user_id | all | current:指定将终止其进程的用户;如果未指定, 则终止所有用户的进程.
kill-all#
终止所有后台进程.
broadcast [options] intent#
发出广播 intent. 请参阅 intent 参数的规范.
选项包括:
- [--user user_id | all | current]:指定要发送到的用户;如果未指定, 则发送到所有用户.
instrument [options] component#
使用 Instrumentation 实例启动监控. 通常, 目标 component 是表单 test_package/runner_class.
选项包括:
- -r:输出原始结果(否则对 report_key_streamresult 进行解码). 与 [-e perf true] 结合使用以生成性能测量的原始输出.
- -e name value:将参数 name 设为 value. 对于测试运行器, 通用表单为 -e testrunner_flag value[,value...].
- -p file:将分析数据写入 file.
- -w:先等待仪器完成, 然后再返回. 测试运行器需要使用此选项.
- --no-window-animation:运行时关闭窗口动画.
- --user user_id | current:指定仪器在哪个用户中运行;如果未指定, 则在当前用户中运行.
- profile start process file 启动 process 的分析器, 将结果写入 file.
- profile stop process 停止 process 的分析器.
dumpheap [options] process file#
转储 process 的堆, 写入 file.
选项包括:
- --user [user_id|current]:提供进程名称时, 指定要转储的进程用户;如果未指定, 则使用当前用户.
- -n:转储原生堆, 而非托管堆.
- set-debug-app [options] package 将应用 package 设为调试.
选项包括:
- -w:应用启动时等待调试程序.
- --persistent:保留此值.
- clear-debug-app 使用 set-debug-app 清除以前针对调试用途设置的软件包.
monitor [options] 启动对崩溃或 ANR 的监控.#
选项包括:
- --gdb:在崩溃/ANR 时在给定端口上启动 gdbserv.
screen-compat { on | off } package#
控制 package 的屏幕兼容性模式.
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:
- -a action
指定 intent 操作, 如“android.intent.action.VIEW”. 此指定只能声明一次. - -d data_uri
指定 intent 数据 URI, 如“content://contacts/people/1”. 此指定只能声明一次. - -t mime_type
指定 intent MIME 类型, 如“image/png”. 此指定只能声明一次. - -c category
指定 intent 类别, 如“android.intent.category.APP_CONTACTS”. - -n component
指定带有软件包名称前缀的组件名称以创建显式 intent, 如“com.example.app/.ExampleActivity”. - -f flags
将标志添加到 setFlags() 支持的 intent. - --esn extra_key
添加一个 null extra. URI intent 不支持此选项. - -e|--es extra_key extra_string_value
添加字符串数据作为键值对. - --ez extra_key extra_boolean_value
添加布尔型数据作为键值对. - --ei extra_key extra_int_value
添加整数型数据作为键值对. - --el extra_key extra_long_value
添加长整型数据作为键值对. - --ef extra_key extra_float_value
添加浮点型数据作为键值对. - --eu extra_key extra_uri_value
添加 URI 数据作为键值对. - --ecn extra_key extra_component_name_value
添加组件名称, 将其作为 ComponentName 对象进行转换和传递. - --eia extra_key extra_int_value[,extra_int_value...]
添加整数数组. - --ela extra_key extra_long_value[,extra_long_value...]
添加长整型数组. - --efa extra_key extra_float_value[,extra_float_value...]
添加浮点型数组. - --grant-read-uri-permission
包含标志 FLAG_GRANT_READ_URI_PERMISSION. - --grant-write-uri-permission
包含标志 FLAG_GRANT_WRITE_URI_PERMISSION. - --debug-log-resolution
包含标志 FLAG_DEBUG_LOG_RESOLUTION. - --exclude-stopped-packages
包含标志 FLAG_EXCLUDE_STOPPED_PACKAGES. - --include-stopped-packages
包含标志 FLAG_INCLUDE_STOPPED_PACKAGES. - --activity-brought-to-front
包含标志 FLAG_ACTIVITY_BROUGHT_TO_FRONT. - --activity-clear-top
包含标志 FLAG_ACTIVITY_CLEAR_TOP. - --activity-clear-when-task-reset
包含标志 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET. - --activity-exclude-from-recents
包含标志 FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. - --activity-launched-from-history
包含标志 FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY. - --activity-multiple-task
包含标志 FLAG_ACTIVITY_MULTIPLE_TASK. - --activity-no-animation
包含标志 FLAG_ACTIVITY_NO_ANIMATION. - --activity-no-history
包含标志 FLAG_ACTIVITY_NO_HISTORY. - --activity-no-user-action
包含标志 FLAG_ACTIVITY_NO_USER_ACTION. - --activity-previous-is-top
包含标志 FLAG_ACTIVITY_PREVIOUS_IS_TOP. - --activity-reorder-to-front
包含标志 FLAG_ACTIVITY_REORDER_TO_FRONT. - --activity-reset-task-if-needed
包含标志 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED. - --activity-single-top
包含标志 FLAG_ACTIVITY_SINGLE_TOP. - --activity-clear-task
包含标志 FLAG_ACTIVITY_CLEAR_TASK. - --activity-task-on-home
包含标志 FLAG_ACTIVITY_TASK_ON_HOME. - --receiver-registered-only
包含标志 FLAG_RECEIVER_REGISTERED_ONLY. - --receiver-replace-pending
包含标志 FLAG_RECEIVER_REPLACE_PENDING. - --selector
需要使用 -d 和 -t 选项以设置 intent 数据和类型.
URI component package#
如果不受上述某一选项的限制, 您可以直接指定 URI、软件包名称和组件名称. 当参数不受限制时, 如果参数包含一个“:”(冒号), 则此工具假定参数是一个 URI;如果参数包含一个“/”(正斜杠), 则此工具假定参数是一个组件名称;否则, 此工具假定参数是一个软件包名称.
应用包名#
所谓应用包名, 是唯一确定应用的标识. 例如微信的包名是"com.tencent.mm", QQ的包名是"com.tencent.mobileqq".
要获取一个应用的包名, 可以通过函数getPackageName(appName)获取. 参见帮助->其他一般函数.
pm命令#
pm命令用于管理应用程序, 例如卸载应用、冻结应用等.
以下命令均以"pm "开头, 例如"shell(\"pm disable com.tencent.mm\");"(冻结微信)
list packages [options] filter#
输出所有软件包, 或者, 仅输出包名称包含 filter 中的文本的软件包.
选项:
- -f:查看它们的关联文件.
- -d:进行过滤以仅显示已停用的软件包.
- -e:进行过滤以仅显示已启用的软件包.
- -s:进行过滤以仅显示系统软件包.
- -3:进行过滤以仅显示第三方软件包.
- -i:查看软件包的安装程序.
- -u:也包括卸载的软件包.
- --user user_id:要查询的用户空间.
list permission-groups#
输出所有已知的权限组.
list permissions [options] group#
输出所有已知权限, 或者, 仅输出 group 中的权限.
选项:
- -g:按组加以组织.
- -f:输出所有信息.
- -s:简短摘要.
- -d:仅列出危险权限.
- -u:仅列出用户将看到的权限.
list instrumentation [options]#
列出所有测试软件包.
选项:
- -f:列出用于测试软件包的 APK 文件.
- target_package:列出仅用于此应用的测试软件包.
list features#
输出系统的所有功能.
list libraries#
输出当前设备支持的所有库.
list users#
输出系统上的所有用户.
path package#
输出给定 package 的 APK 的路径.
install [options] path#
将软件包(通过 path 指定)安装到系统.
选项:
- -l:安装具有转发锁定功能的软件包.
- -r:重新安装现有应用, 保留其数据.
- -t:允许安装测试 APK.
- -i installer_package_name:指定安装程序软件包名称.
- -s:在共享的大容量存储(如 sdcard)上安装软件包.
- -f:在内部系统内存上安装软件包.
- -d:允许版本代码降级.
- -g:授予应用清单文件中列出的所有权限.
uninstall [options] package#
从系统中卸载软件包.
选项:
- -k:移除软件包后保留数据和缓存目录.
clear package#
删除与软件包关联的所有数据.
enable package_or_component#
启用给定软件包或组件(作为“package/class”写入).
disable package_or_component#
停用给定软件包或组件(作为“package/class”写入).
disable-user [options] package_or_component#
选项:
- --user user_id:要停用的用户.
grant package_name permission#
向应用授予权限. 在运行 Android 6.0(API 级别 23)及更高版本的设备上, 可以是应用清单中声明的任何权限. 在运行 Android 5.1(API 级别 22)和更低版本的设备上, 必须是应用定义的可选权限.
revoke package_name permission#
从应用中撤销权限. 在运行 Android 6.0(API 级别 23)及更高版本的设备上, 可以是应用清单中声明的任何权限. 在运行 Android 5.1(API 级别 22)和更低版本的设备上, 必须是应用定义的可选权限.
set-install-location location#
更改默认安装位置. 位置值:
- 0:自动—让系统决定最佳位置.
- 1:内部—安装在内部设备存储上.
- 2:外部—安装在外部介质上.
注:此命令仅用于调试目的;使用此命令会导致应用中断和其他意外行为.
get-install-location#
返回当前安装位置. 返回值:
- 0 [auto]:让系统决定最佳位置.
- 1 [internal]:安装在内部设备存储上
- 2 [external]:安装在外部介质上
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);
多媒体 (Media)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
media模块提供多媒体编程的支持. 目前仅支持音乐播放和媒体文件扫描. 后续会结合UI加入视频播放等功能.
需要注意是, 使用该模块播放音乐时是在后台异步播放的, 在脚本结束后会自动结束播放, 因此可能需要插入诸如sleep()的语句来使脚本保持运行. 例如:
//播放音乐
media.playMusic("/sdcard/1.mp3");
//让音乐播放完
sleep(media.getMusicDuration());
media.scanFile(path)#
path{ string } 媒体文件路径
扫描路径path的媒体文件, 将它加入媒体库中;或者如果该文件以及被删除, 则通知媒体库移除该文件.
媒体库包括相册、音乐库等, 因此该函数可以用于把某个图片文件加入相册.
//请求截图
requestScreenCapture(false);
//截图
var im = captureScreen();
var path = "/sdcard/screenshot.png";
//保存图片
im.saveTo(path);
//把图片加入相册
media.scanFile(path);
media.playMusic(path[, volume, looping])#
播放音乐文件path. 该函数不会显示任何音乐播放界面. 如果文件不存在或者文件不是受支持的音乐格式, 则抛出UncheckedIOException异常.
//播放音乐
media.playMusic("/sdcard/1.mp3");
//让音乐播放完
sleep(media.getMusicDuration());
如果要循环播放音乐, 则使用looping参数:
//传递第三个参数为true以循环播放音乐 media.playMusic("/sdcard/1.mp3", 1, true); //等待三次播放的时间 sleep(media.getMusicDuration() * 3);
如果要使用音乐播放器播放音乐, 调用app.viewFile(path)函数.
media.musicSeekTo(msec)#
msec{ number } 毫秒数, 表示音乐进度
把当前播放进度调整到时间msec的位置. 如果当前没有在播放音乐, 则调用函数没有任何效果.
例如, 要把音乐调到1分钟的位置, 为media.musicSeekTo(60 * 1000).
//播放音乐
media.playMusic("/sdcard/1.mp3");
//调整到30秒的位置
media.musicSeekTo(30 * 1000);
//等待音乐播放完成
sleep(media.getMusicDuration() - 30 * 1000);
media.pauseMusic()#
暂停音乐播放. 如果当前没有在播放音乐, 则调用函数没有任何效果.
media.resumeMusic()#
继续音乐播放. 如果当前没有播放过音乐, 则调用该函数没有任何效果.
media.stopMusic()#
停止音乐播放. 如果当前没有在播放音乐, 则调用函数没有任何效果.
media.isMusicPlaying()#
- 返回 { boolean }
返回当前是否正在播放音乐.
media.getMusicDuration()#
- 返回 { number }
返回当前音乐的时长. 单位毫秒.
media.getMusicCurrentPosition()#
- 返回 { number }
返回当前音乐的播放进度(已经播放的时间), 单位毫秒.
传感器 (Sensors)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
sensors模块提供了获取手机上的传感器的信息的支持, 这些传感器包括距离传感器、光线光感器、重力传感器、方向传感器等. 需要指出的是, 脚本只能获取传感器的数据, 不能模拟或伪造传感器的数据和事件, 因此诸如模拟摇一摇的功能是无法实现的.
要监听一个传感器时, 需要使用sensors.register()注册监听器, 之后才能开始监听;不需要监听时则调用sensors.unregister()注销监听器. 在脚本结束时会自动注销所有的监听器. 同时, 这种监听会使脚本保持运行状态, 如果不注销监听器, 脚本会一直保持运行状态.
例如, 监听光线传感器的代码为:
//光线传感器监听
sensors.register("light").on("change", (event, light)=>{
log("当前光强度为", light);
});
要注意的是, 每个传感器的数据并不相同, 所以对他们调用on()监听事件时的回调函数参数也不是相同, 例如光线传感器参数为(event, light), 加速度传感器参数为(event, ax, ay, az). 甚至在某些设备上的传感器参数有所增加, 例如华为手机的距离传感器为三个参数, 一般手机只有一个参数.
常用的传感器及其事件参数如下表:
accelerometer加速度传感器, 参数(event, ax, ay, az):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息ax{ number } x轴上的加速度, 单位m/s^2ay{ number } y轴上的加速度, 单位m/s^2az{ number } z轴上的加速度, 单位m/s^2 这里的x轴, y轴, z轴所属的坐标系统如下图(其中z轴垂直于设备屏幕表面):
!

orientation方向传感器, 参数(event, azimuth, pitch, roll):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息azimuth{ number } 方位角, 从地磁指北方向线起, 依顺时针方向到y轴之间的水平夹角, 单位角度, 范围0~359pitch{ number } 绕x轴旋转的角度, 当设备水平放置时该值为0, 当设备顶部翘起时该值为正数, 当设备尾部翘起时该值为负数, 单位角度, 范围-180~180roll{ number } 绕y轴顺时针旋转的角度, 单位角度, 范围-90~90
gyroscope陀螺仪传感器, 参数(event, wx, wy, wz):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息wx{ number } 绕x轴的角速度, 单位弧度/swy{ number } 绕y轴的角速度, 单位弧度/swz{ number } 绕z轴的角速度, 单位弧度/s
magnetic_field磁场传感器, 参数(event, bx, by, bz):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息bx{ number } x轴上的磁场强度, 单位uTby{ number } y轴上的磁场强度, 单位uTbz{ number } z轴上的磁场强度, 单位uT
gravity重力传感器, 参数(event, gx, gy, gz):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息gx{ number } x轴上的重力加速度, 单位m/s^2gy{ number } y轴上的重力加速度, 单位m/s^2gz{ number } z轴上的重力加速度, 单位m/s^2
linear_acceleration线性加速度传感器, 参数(event, ax, ay, az):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息ax{ number } x轴上的线性加速度, 单位m/s^2ay{ number } y轴上的线性加速度, 单位m/s^2az{ number } z轴上的线性加速度, 单位m/s^2
ambient_temperature环境温度传感器, 大部分设备并不支持, 参数(event, t):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息t{ number } 环境温度, 单位摄氏度.
light光线传感器, 参数(event, light):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息light{ number } 环境光强度, 单位lux
pressure压力传感器, 参数(event, p):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息p{ number } 大气压, 单位hPa
proximity距离传感器, 参数(event, distance):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息distance{ number } 一般指设备前置摄像头旁边的距离传感器到前方障碍物的距离, 并且很多设备上这个值只有两种情况:当障碍物较近时该值为0, 当障碍物较远或在范围内没有障碍物时该值为5
relative_humidity湿度传感器, 大部分设备并不支持, 参数(event, rh):eventSensorEvent 传感器事件, 用于获取传感器数据变化时的所有信息rh{ number } 相对湿度, 范围为0~100(百分比)
sensors.register(sensorName[, delay])#
sensorName{ string } 传感器名称, 常用的传感器名称如上面所述delay{ number } 传感器数据更新频率, 可选, 默认为sensors.delay.normal. 可用的值如下:sensors.delay.normal正常频率sensors.delay.ui适合于用户界面的更新频率sensors.delay.game适合于游戏的更新频率sensors.delay.fastest最快的更新频率】
- 返回 SensorEventEmiiter
注册一个传感器监听并返回SensorEventEmitter.
例如:
console.show();
//注册传感器监听
var sensor = sensors.register("gravity");
if(sensor == null){
toast("不支持重力传感器");
exit();
}
//监听数据
sensor.on("change", (gx, gy, gz)=>{
log("重力加速度: %d, %d, %d", gx, gy, gz);
});
可以通过delay参数来指定传感器数据的更新频率, 例如:
var sensor = sensors.register("gravity", sensors.delay.game);
另外, 如果不支持sensorName所指定的传感器, 那么该函数将返回null;但如果sensors.ignoresUnsupportedSensor的值被设置为true, 则该函数会返回一个不会分发任何传感器事件的SensorEventEmitter.
例如:
sensors.ignoresUnsupportedSensor = true;
//无需null判断
sensors.register("gravity").on("change", (gx, gy, gz)=>{
log("重力加速度: %d, %d, %d", gx, gy, gz);
});
更多信息, 参见SensorEventEmitter和sensors.ignoresUnsupportedSensor.
sensors.unregister(emitter)#
emiiterSensorEventEmitter
注销该传感器监听器. 被注销的监听器将不再能监听传感器数据.
//注册一个传感器监听器
var sensor = sensors.register("gravity");
if(sensor == null){
exit();
}
//2秒后注销该监听器
setTimeout(()=> {
sensors.unregister(sensor);
}, 2000);
sensors.unregisterAll()#
注销所有传感器监听器.
sensors.ignoresUnsupportedSensor#
- { boolean }
表示是否忽略不支持的传感器. 如果该值被设置为true, 则函数sensors.register()即使对不支持的传感器也会返回一个无任何数据的虚拟传感器监听, 也就是sensors.register()不会返回null从而避免非空判断, 并且此时会触发sensors的"unsupported_sensor"事件.
//忽略不支持的传感器
sensors.ignoresUnsupportedSensor = true;
//监听有不支持的传感器时的事件
sensors.on("unsupported_sensor", function(sensorName){
toastLog("不支持的传感器: " + sensorName);
});
//随便注册一个不存在的传感器.
log(sensors.register("aaabbb"));
事件: 'unsupported_sensor'#
sensorName{ string } 不支持的传感器名称
当sensors.ignoresUnsupportedSensor被设置为true并且有不支持的传感器被注册时触发该事件. 事件参数的传感器名称.
SensorEventEmitter#
注册传感器返回的对象, 其本身是一个EventEmmiter, 用于监听传感器事件.
事件: 'change'#
..args{ Any } 传感器参数
当传感器数据改变时触发该事件;该事件触发的最高频繁由sensors.register()指定的delay参数决定.
事件参数根据传感器类型不同而不同, 具体参见本章最前面的列表.
一个监听光线传感器和加速度传感器并且每0.5秒获取一个数据并最终写入一个csv表格文件的例子如下:
//csv文件路径
cosnt csvPath = "/sdcard/sensors_data.csv";
//记录光线传感器的数据
var light = 0;
//记录加速度传感器的数据
var ax = 0;
var ay = 0;
var az = 0;
//监听光线传感器
sensors.register("light", sensors.delay.fastest)
.on("change", l => {
light = l;
});
//监听加速度传感器
sensors.register("accelerometer", sensors.delay.fastest)
.on("change", (ax0, ay0, az0) => {
ax = ax0;
ay = ay0;
az = az0;
});
var file = open(csvPath, "w");
//写csv表格头
file.writeline("light,ax,ay,az")
//每0.5秒获取一次数据并写入文件
setInterval(()=>{
file.writeline(util.format("%d,%d,%d,%d", light, ax, ay, az));
}, 500);
//10秒后退出并打开文件
setTimeout(()=>{
file.close();
sensors.unregsiterAll();
app.viewFile(csvPath);
}, 10 * 1000);
事件: 'accuracy_change'#
accuracy{ number } 表示传感器精度. 为以下值之一:- -1 传感器未连接
- 0 传感器不可读
- 1 低精度
- 2 中精度
- 3 高精度
当传感器精度改变时会触发的事件. 比较少用.
记录器 (Recorder)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
记录器用于计时.
注: 为避免与 Timers (定时器) 混淆, 本条目不采用 "计时器" 定义.
recorder
[@] recorder#
recorder()#
recorder(key)#
recorder(key, timestamp)#
recorder(func)#
recorder(func, thisType)#
[m] save#
save()#
save(key)#
save(key, timestamp)#
[m] load#
load()#
load(key)#
load(key, timestamp)#
[m] isLessThan#
isLessThan(key, compare)#
[m] isGreaterThan#
isGreaterThan(key, compare)#
[m] has#
has(key)#
[m] remove#
remove(key)#
[m] clear#
clear()#
定时器 (Timers)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
timers 模块暴露了一个全局的 API, 用于在某个未来时间段调用调度函数. 因为定时器函数是全局的, 所以使用该 API 无需调用 timers.***
Auto.js 中的计时器函数实现了与 Web 浏览器提供的定时器类似的 API, 除了它使用了一个不同的内部实现, 它是基于 Android Looper-Handler消息循环机制构建的. 其实现机制与Node.js比较相似.
例如, 要在5秒后发出消息"hello":
setTimeout(function(){
toast("hello")
}, 5000);
需要注意的是, 这些定时器仍然是单线程的. 如果脚本主体有耗时操作或死循环, 则设定的定时器不能被及时执行, 例如:
setTimeout(function(){
//这里的语句会在15秒后执行而不是5秒后
toast("hello")
}, 5000);
//暂停10秒
sleep(10000);
再如:
setTimeout(function(){
//这里的语句永远不会被执行
toast("hello")
}, 5000);
//死循环
while(true);
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(callback[, ...args])#
callback{ Function } 在Looper循环的当前回合结束时要调用的函数....args{ any } 当调用 callback 时要传入的可选参数.
预定立即执行的 callback, 它是在 I/O 事件的回调之后被触发. 返回一个用于 clearImmediate() 的 id.
当多次调用 setImmediate() 时, callback 函数会按照它们被创建的顺序依次执行. 每次事件循环迭代都会处理整个回调队列. 如果一个立即定时器是被一个正在执行的回调排入队列的, 则该定时器直到下一次事件循环迭代才会被触发.
setImmediate()、setInterval() 和 setTimeout() 方法每次都会返回表示预定的计时器的id. 它们可用于取消定时器并防止触发.
clearInterval(id)#
id{ number } 一个 setInterval() 返回的 id.
取消一个由 setInterval() 创建的循环定时任务.
例如:
//每5秒就发出一次hello
var id = setInterval(function(){
toast("hello");
}, 5000);
//1分钟后取消循环
setTimeout(function(){
clearInterval(id);
}, 60 * 1000);
clearTimeout(id)#
id{ number } 一个 setTimeout() 返回的 id.
取消一个由 setTimeout() 创建的定时任务.
clearImmediate(id)#
id{ number } 一个 setImmediate() 返回的 id.
取消一个由 setImmediate() 创建的 Immediate 对象.
线程 (Threads)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
threads模块提供了多线程支持, 可以启动新线程来运行脚本.
脚本主线程会等待所有子线程执行完成后才停止执行, 因此如果子线程中有死循环, 请在必要的时候调用exit()来直接停止脚本或threads.shutDownAll()来停止所有子线程.
通过threads.start()启动的所有线程会在脚本被强制停止时自动停止.
由于JavaScript自身没有多线程的支持, 因此您可能会遇到意料之外的问题.
threads.start(action)#
启动一个新线程并执行action.
例如:
threads.start(function(){
//在新线程执行的代码
while(true){
log("子线程");
}
});
while(true){
log("脚本主线程");
}
通过该函数返回的Thread对象可以获取该线程的状态, 控制该线程的运行中. 例如:
var thread = threads.start(function(){
while(true){
log("子线程");
}
});
//停止线程执行
thread.interrupt();
更多信息参见Thread.
threads.shutDownAll()#
停止所有通过threads.start()启动的子线程.
threads.currentThread()#
- 返回 Thread
返回当前线程.
threads.disposable()#
- 返回 Disposable
新建一个Disposable对象, 用于等待另一个线程的某个一次性结果. 更多信息参见线程通信以及Disposable.
threads.atomic([initialValue])#
initialValue{ number } 初始整数值, 默认为0- 返回AtomicLong
新建一个整数原子变量. 更多信息参见线程安全以及AtomicLong.
threads.lock()#
新建一个可重入锁. 更多信息参见线程安全以及ReentrantLock.
Thread#
线程对象, threads.start()返回的对象, 用于获取和控制线程的状态, 与其他线程交互等.
Thread对象提供了和timers模块一样的API, 例如setTimeout(), setInterval()等, 用于在该线程执行相应的定时回调, 从而使线程之间可以直接交互. 例如:
var thread = threads.start(function(){
//在子线程执行的定时器
setInterval(function(){
log("子线程:" + threads.currentThread());
}, 1000);
});
log("当前线程为主线程:" + threads.currentThread());
//等待子线程启动
thread.waitFor();
//在子线程执行的定时器
thread.setTimeout(function(){
//这段代码会在子线程执行
log("当前线程为子线程:" + threads.currentThread());
}, 2000);
sleep(30 * 1000);
thread.interrupt();
Thread.interrupt()#
中断线程运行.
Thread.join([timeout])#
timeout{ number } 等待时间, 单位毫秒
等待线程执行完成. 如果timeout为0, 则会一直等待直至该线程执行完成;否则最多等待timeout毫秒的时间.
例如:
var sum = 0;
//启动子线程计算1加到10000
var thread = threads.start(function(){
for(var i = 0; i < 10000; i++){
sum += i;
}
});
//等待该线程完成
thread.join();
toast("sum = " + sum);
isAlive()#
- 返回 { boolean }
返回线程是否存活. 如果线程仍未开始或已经结束, 返回false; 如果线程已经开始或者正在运行中, 返回true.
waitFor()#
等待线程开始执行. 调用threads.start()以后线程仍然需要一定时间才能开始执行, 因此调用此函数会等待线程开始执行;如果线程已经处于执行状态则立即返回.
var thread = threads.start(function(){
//do something
});
thread.waitFor();
thread.setTimeout(function(){
//do something
}, 1000);
Thread.setTimeout(callback, delay[, ...args])#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
log("当前线程(主线程):" + threads.currentThread());
var thread = threads.start(function(){
//设置一个空的定时来保持线程的运行状态
setInterval(function(){}, 1000);
});
sleep(1000);
thread.setTimeout(function(){
log("当前线程(子线程):" + threads.currentThread());
exit();
}, 1000);
Thread.setInterval(callback, delay[, ...args])#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
Thread.setImmediate(callback[, ...args])#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
Thread.clearInterval(id)#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
Thread.clearTimeout(id)#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
Thread.clearImmediate(id)#
区别在于, 该定时器会在该线程执行. 如果当前线程仍未开始执行或已经执行结束, 则抛出IllegalStateException.
线程安全#
线程安全问题是一个相对专业的编程问题, 本章节只提供给有需要的用户.
引用维基百科的解释:
线程安全是编程中的术语, 指某个函数、函数库在多线程环境中被调用时, 能够正确地处理多个线程之间的共享变量, 使程序功能正确完成.
在Auto.js中, 线程间变量在符合JavaScript变量作用域规则的前提下是共享的, 例如全局变量在所有线程都能访问, 并且保证他们在所有线程的可见性. 但是, 不保证任何操作的原子性. 例如经典的自增"i++"将不是原子性操作.
Rhino和Auto.js提供了一些简单的设施来解决简单的线程安全问题, 如锁threads.lock(), 函数同步锁sync(), 整数原子变量threads.atomic()等.
例如, 对于多线程共享下的整数的自增操作(自增操作会导致问题, 是因为自增操作实际上为i = i + 1, 也就是先读取i的值, 把他加1, 再赋值给i, 如果两个线程同时进行自增操作, 可能出现i的值只增加了1的情况), 应该使用threads.atomic()函数来新建一个整数原子变量, 或者使用锁threads.lock()来保证操作的原子性, 或者用sync()来增加同步锁.
线程不安全的代码如下:
var i = 0;
threads.start(function(){
while(true){
log(i++);
}
});
while(true){
log(i++);
}
此段代码运行后打开日志, 可以看到日志中有重复的值出现.
使用threads.atomic()的线程安全的代码如下:
//atomic返回的对象保证了自增的原子性
var i = threads.atomic();
threads.start(function(){
while(true){
log(i.getAndIncrement());
}
});
while(true){
log(i.getAndIncrement());
}
或者:
//锁保证了操作的原子性
var lock = threads.lock();
var i = 0;
threads.start(function(){
while(true){
lock.lock();
log(i++);
lock.unlock();
}
});
while(true){
lock.lock();
log(i++);
lock.unlock();
}
或者:
//sync函数会把里面的函数加上同步锁, 使得在同一时刻最多只能有一个线程执行这个函数
var i = 0;
var getAndIncrement = sync(function(){
return i++;
});
threads.start(function(){
while(true){
log(getAndIncrement());
}
});
while(true){
log(getAndIncrement());
}
另外, 数组Array不是线程安全的, 如果有这种复杂的需求, 请用Android和Java相关API来实现. 例如CopyOnWriteList, Vector等都是代替数组的线程安全的类, 用于不同的场景. 例如:
var nums = new java.util.Vector();
nums.add(123);
nums.add(456);
toast("长度为" + nums.size());
toast("第一个元素为" + nums.get(0));
但很明显的是, 这些类不像数组那样简便易用, 也不能使用诸如slice()之类的方便的函数. 在未来可能会加入线程安全的数组来解决这个问题. 当然您也可以为每个数组的操作加锁来解决线程安全问题:
var nums = [];
var numsLock = threads.lock();
threads.start(function(){
//向数组添加元素123
numsLock.lock();
nums.push(123);
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.unlock();
});
threads.start(function(){
//向数组添加元素456
numsLock.lock();
nums.push(456);
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.unlock();
});
//删除数组最后一个元素
numsLock.lock();
nums.pop();
log("线程: %s, 数组: %s", threads.currentThread(), nums);
numsLock.unlock();
sync(func)#
给函数func加上同步锁并作为一个新函数返回.
var i = 0;
function add(x){
i += x;
}
var syncAdd = sync(add);
syncAdd(10);
toast(i);
线程通信#
Auto.js提供了一些简单的设施来支持简单的线程通信. threads.disposable()用于一个线程等待另一个线程的(一次性)结果, 同时Lock.newCondition()提供了Condition对象用于一般的线程通信(await, signal). 另外, events模块也可以用于线程通信, 通过指定EventEmiiter的回调执行的线程来实现.
使用threads.disposable()可以简单地等待和获取某个线程的执行结果. 例如要等待某个线程计算"1+.....+10000":
var sum = threads.disposable();
//启动子线程计算
threads.start(function(){
var s = 0;
//从1加到10000
for(var i = 1; i <= 10000; i++){
s += i;
}
//通知主线程接收结果
sum.setAndNotify(s);
});
//blockedGet()用于等待结果
toast("sum = " + sum.blockedGet());
如果上述代码用Condition实现:
//新建一个锁
var lock = threads.lock();
//新建一个条件, 即"计算完成"
var complete = lock.newCondition();
var sum = 0;
threads.start(function(){
//从1加到10000
for(var i = 1; i <= 10000; i++){
sum += i;
}
//通知主线程接收结果
lock.lock();
complete.signal();
lock.unlock();
});
//等待计算完成
lock.lock();
complete.await();
lock.unlock();
//打印结果
toast("sum = " + sum);
如果上诉代码用events模块实现:
//新建一个emitter, 并指定回调执行的线程为当前线程
var sum = events.emitter(threads.currentThread());
threads.start(function(){
var s = 0;
//从1加到10000
for(var i = 1; i <= 10000; i++){
s += i;
}
//发送事件result通知主线程接收结果
sum.emit('result', s);
});
sum.on('result', function(s){
toastLog("sum = " + s + ", 当前线程: " + threads.currentThread());
});
有关线程的其他问题, 例如生产者消费者等问题, 请用Java相关方法解决, 例如java.util.concurrent.BlockingQueue.
事件监听 (Events)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
events模块提供了监听手机通知、按键、触摸的接口. 您可以用他配合自动操作函数完成自动化工作.
events本身是一个EventEmiiter, 但内置了一些事件、包括按键事件、通知事件、Toast事件等.
需要注意的是, 事件的处理是单线程的, 并且仍然在原线程执行, 如果脚本主体或者其他事件处理中有耗时操作、轮询等, 则事件将无法得到及时处理(会进入事件队列等待脚本主体或其他事件处理完成才执行). 例如:
auto();
events.observeNotification();
events.on('toast', function(t){
//这段代码将得不到执行
log(t);
});
while(true){
//死循环
}
events.emitter()#
返回一个新的EventEmitter. 这个EventEmitter没有内置任何事件.
events.observeKey()#
启用按键监听, 例如音量键、Home键. 按键监听使用无障碍服务实现, 如果无障碍服务未启用会抛出异常并提示开启.
只有这个函数成功执行后, 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)#
keyName{ string } 按键名称
删除该按键的KeyDown(按下)事件的所有监听.
events.removeAllKeyUpListeners(keyName)#
keyName{ string } 按键名称
删除该按键的KeyUp(弹起)事件的所有监听.
events.setKeyInterceptionEnabled([key, ]enabled)#
设置按键屏蔽是否启用. 所谓按键屏蔽指的是, 屏蔽原有按键的功能, 例如使得音量键不再能调节音量, 但此时仍然能通过按键事件监听按键.
如果不加参数key则会屏蔽所有按键.
例如, 调用events.setKeyInterceptionEnabled(true)会使系统的音量、Home、返回等键不再具有调节音量、回到主页、返回的作用, 但此时仍然能通过按键事件监听按键.
该函数通常于按键监听结合, 例如想监听音量键并使音量键按下时不弹出音量调节框则为:
events.setKeyInterceptionEnabled("volume_up", true);
events.observeKey();
events.onKeyDown("volume_up", ()=>{
log("音量上键被按下");
});
只要有一个脚本屏蔽了某个按键, 该按键便会被屏蔽;当脚本退出时, 会自动解除所有按键屏蔽.
events.observeTouch()#
启用屏幕触摸监听. (需要root权限)
只有这个函数被成功执行后, 触摸事件的监听才有效.
没有root权限调用该函数则什么也不会发生.
events.setTouchEventTimeout(timeout)#
timeout{ number } 两个触摸事件的最小间隔. 单位毫秒. 默认为10毫秒. 如果number小于0, 视为0处理.
设置两个触摸事件分发的最小时间间隔.
例如间隔为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'#
keyCode{ number } 键值event{ KeyEvent } 事件
当有按键被按下或弹起时会触发该事件. 例如:
auto();
events.observeKey();
events.on("key", function(keyCode, event){
//处理按键事件
});
其中监听器的参数KeyCode包括:
keys.home主页键keys.back返回键keys.menu菜单键keys.volume_up音量上键keys.volume_down音量下键
例如:
auto();
events.observeKey();
events.on("key", function(keyCode, event){
if(keyCode == keys.menu && event.getAction() == event.ACTION_UP){
toast("菜单键按下");
}
});
事件: 'key_down'#
keyCode{ number } 键值event{ KeyEvent } 事件
当有按键被按下时会触发该事件.
auto();
events.observeKey();
events.on("key_down", function(keyCode, event){
//处理按键按下事件
});
事件: 'key_up'#
keyCode{ number } 键值event{ KeyEvent } 事件
当有按键弹起时会触发该事件.
auto();
events.observeKey();
events.on("key_up", function(keyCode, event){
//处理按键弹起事件
});
事件: 'exit`#
当脚本正常或者异常退出时会触发该事件. 事件处理中如果有异常抛出, 则立即中止exit事件的处理(即使exit事件有多个处理函数)并在控制台和日志中打印该异常.
一个脚本停止运行时, 会关闭该脚本的所有悬浮窗, 触发exit事件, 之后再回收资源. 如果exit事件的处理中有死循环, 则后续资源无法得到及时回收. 此时脚本会停留在任务列表, 如果在任务列表中关闭, 则会强制结束exit事件的处理并回收后续资源.
log("开始运行")
events.on("exit", function(){
log("结束运行");
});
log("即将结束运行");
events.observeNotification()#
开启通知监听. 例如QQ消息、微信消息、推送等通知.
通知监听依赖于通知服务, 如果通知服务没有运行, 会抛出异常并跳转到通知权限开启界面. (有时即使通知权限已经开启通知服务也没有运行, 这时需要关闭权限再重新开启一次)
例如:
events.observeNotification();
events.onNotification(function(notification){
log(notification.getText());
});
events.observeToast()#
开启Toast监听.
Toast监听依赖于无障碍服务, 因此此函数会确保无障碍服务运行.
事件: 'toast'#
toast{ Object }getText()获取Toast的文本内容getPackageName()获取发出Toast的应用包名
当有应用发出toast(气泡消息)时会触发该事件. 但Auto.js软件本身的toast除外.
例如, 要记录发出所有toast的应用:
events.observeToast();
events.onToast(function(toast){
log("Toast内容: " + toast.getText() + " 包名: " + toast.getPackageName());
});
事件: 'notification'#
notificationNotification 通知对象
当有应用发出通知时会触发该事件, 参数为Notification.
例如:
events.observeNotification();
events.on("notification", function(n){
log("收到新通知:\n 标题: %s, 内容: %s, \n包名: %s", n.getTitle(), n.getText(), n.getPackageName());
});
Notification#
通知对象, 可以获取通知详情, 包括通知标题、内容、发出通知的包名、时间等, 也可以对通知进行操作, 比如点击、删除.
Notification.number#
- { number }
通知数量. 例如QQ连续收到两条消息时number为2.
Notification.when#
- { number }
通知发出时间的时间戳, 可以用于构造Date对象. 例如:
events.observeNotification();
events.on("notification", function(n){
log("通知时间为}" + new Date(n.when));
});
Notification.getPackageName()#
- 返回 { string }
获取发出通知的应用包名.
Notification.getTitle()#
- 返回 { string }
获取通知的标题.
Notification.getText()#
- 返回 { string }
获取通知的内容.
Notification.click()#
点击该通知. 例如对于一条QQ消息, 点击会进入具体的聊天界面.
Notification.delete()#
删除该通知. 该通知将从通知栏中消失.
KeyEvent#
KeyEvent.getAction()#
返回事件的动作. 包括:
KeyEvent.ACTION_DOWN按下事件KeyEvent.ACTION_UP弹起事件
KeyEvent.getKeyCode()#
返回按键的键值. 包括:
KeyEvent.KEYCODE_HOME主页键KeyEvent.KEYCODE_BACK返回键KeyEvent.KEYCODE_MENU菜单键KeyEvent.KEYCODE_VOLUME_UP音量上键KeyEvent.KEYCODE_VOLUME_DOWN音量下键
KeyEvent.getEventTime()#
- 返回 { number }
返回事件发生的时间戳.
KeyEvent.getDownTime()#
返回最近一次按下事件的时间戳. 如果本身是按下事件, 则与getEventTime()相同.
KeyEvent.keyCodeToString(keyCode)#
把键值转换为字符串. 例如KEYCODE_HOME转换为"KEYCODE_HOME".
keys#
按键事件中所有可用的按键名称为:
volume_up音量上键volume_down音量下键home主屏幕键back返回键menu菜单键
EventEmitter#
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)#
eventName{ any }listener{ Function }
emitter.on(eventName, listener) 的别名.
EventEmitter.emit(eventName[, ...args])#
eventName{ any }args{ any }
按监听器的注册顺序, 同步地调用每个注册到名为 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{ string } 正在被监听的事件名
返回正在监听名为 eventName 的事件的监听器的数量.
EventEmitter.listeners(eventName)#
eventName{ string }
返回名为 eventName 的事件的监听器数组的副本.
server.on('connection', (stream) => {
console.log('someone connected!');
});
console.log(util.inspect(server.listeners('connection')));
// 打印: [ [Function] ]
EventEmitter.on(eventName, listener)#
eventName{ any } 事件名listener{ Function } 回调函数
添加 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)#
eventName{ any } 事件名listener{ Function } 回调函数
添加一个单次 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)#
eventName{ any } 事件名listener{ Function } 回调函数
添加 listener 函数到名为 eventName 的事件的监听器数组的开头. 不会检查 listener 是否已被添加. 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次.
server.prependListener('connection', (stream) => {
console.log('有连接!');
});
返回一个 EventEmitter 引用, 可以链式调用.
EventEmitter.prependOnceListener(eventName, listener)#
eventName{ any } 事件名listener{ Function } 回调函数
添加一个单次 listener 函数到名为 eventName 的事件的监听器数组的开头. 下次触发 eventName 事件时, 监听器会被移除, 然后调用.
server.prependOnceListener('connection', (stream) => {
console.log('首次调用!');
});
返回一个 EventEmitter 引用, 可以链式调用.
EventEmitter.removeAllListeners([eventName])#
eventName{ any }
移除全部或指定 eventName 的监听器.
注意, 在代码中移除其他地方添加的监听器是一个不好的做法, 尤其是当 EventEmitter 实例是其他组件或模块创建的.
返回一个 EventEmitter 引用, 可以链式调用.
EventEmitter.removeListener(eventName, listener)#
eventName{ any }listener{ Function }
从名为 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)#
n{ number }
默认情况下, 如果为特定事件添加了超过 10 个监听器, 则 EventEmitter 会打印一个警告. 此限制有助于寻找内存泄露. 但是, 并不是所有的事件都要被限为 10 个. emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制. 值设为 Infinity(或 0)表明不限制监听器的数量.
返回一个 EventEmitter 引用, 可以链式调用.
events.broadcast: 脚本间广播#
脚本间通信除了使用engines模块提供的ScriptEngine.emit()方法以外, 也可以使用events模块提供的broadcast广播.
events.broadcast本身是一个EventEmitter, 但它的事件是在脚本间共享的, 所有脚本都能发送和监听这些事件;事件处理会在脚本主线程执行(后续可能加入函数onThisThread(eventName, ...args)来提供在其他线程执行的能力).
例如在一个脚本发送一个广播hello:
events.broadcast.emit("hello", "小明");
在其他脚本中监听并处理:
events.broadcast.on("hello", function(name){
toast("你好, " + name);
});
//保持脚本运行
setInterval(()=>{}, 1000);
对话框 (Dialogs)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
dialogs 模块提供了简单的对话框支持, 可以通过对话框和用户进行交互. 最简单的例子如下:
alert("您好");
这段代码会弹出一个消息提示框显示"您好", 并在用户点击"确定"后继续运行. 稍微复杂一点的例子如下:
var clear = confirm("要清除所有缓存吗?");
if(clear){
alert("清除成功!");
}
confirm()会弹出一个对话框并让用户选择"是"或"否", 如果选择"是"则返回true.
需要特别注意的是, 对话框在ui模式下不能像通常那样使用, 应该使用回调函数或者Promise的形式. 理解这一点可能稍有困难. 举个例子:
"ui";
//回调形式
confirm("要清除所有缓存吗?", function(clear){
if(clear){
alert("清除成功!");
}
});
//Promise形式
confirm("要清除所有缓存吗?")
.then(clear => {
if(clear){
alert("清除成功!");
}
});
dialogs.alert(title[, content, callback])#
显示一个只包含“确定”按钮的提示对话框. 直至用户点击确定脚本才继续运行.
该函数也可以作为全局函数使用.
alert("出现错误~", "出现未知错误, 请联系脚本作者”);
在ui模式下该函数返回一个Promise. 例如:
"ui";
alert("嘿嘿嘿").then(()=>{
//当点击确定后会执行这里
});
dialogs.confirm(title[, content, callback])#
显示一个包含“确定”和“取消”按钮的提示对话框. 如果用户点击“确定”则返回 true , 否则返回 false .
该函数也可以作为全局函数使用.
在ui模式下该函数返回一个Promise. 例如:
"ui";
confirm("确定吗").then(value=>{
//当点击确定后会执行这里, value为true或false, 表示点击"确定"或"取消"
});
dialogs.rawInput(title[, prefill, callback])#
显示一个包含输入框的对话框, 等待用户输入内容, 并在用户点击确定时将输入的字符串返回. 如果用户取消了输入, 返回null.
该函数也可以作为全局函数使用.
var name = rawInput("请输入您的名字", "小明");
alert("您的名字是" + name);
在ui模式下该函数返回一个Promise. 例如:
"ui";
rawInput("请输入您的名字", "小明").then(name => {
alert("您的名字是" + name);
});
当然也可以使用回调函数, 例如:
rawInput("请输入您的名字", "小明", name => {
alert("您的名字是" + name);
});
dialogs.input(title[, prefill, callback])#
等效于 eval(dialogs.rawInput(title, prefill, callback)), 该函数和rawInput的区别在于, 会把输入的字符串用eval计算一遍再返回, 返回的可能不是字符串.
可以用该函数输入数字、数组等. 例如:
var age = dialogs.input("请输入您的年龄", "18");
// new Date().getYear() + 1900 可获取当前年份
var year = new Date().getYear() + 1900 - age;
alert("您的出生年份是" + year);
在ui模式下该函数返回一个Promise. 例如:
"ui";
dialogs.input("请输入您的年龄", "18").then(age => {
var year = new Date().getYear() + 1900 - age;
alert("您的出生年份是" + year);
});
dialogs.prompt(title[, prefill, callback])#
相当于 dialogs.rawInput();
dialogs.select(title, items, callback)#
显示一个带有选项列表的对话框, 等待用户选择, 返回用户选择的选项索引(0 ~ item.length - 1). 如果用户取消了选择, 返回-1.
var options = ["选项A", "选项B", "选项C", "选项D"]
var i = dialogs.select("请选择一个选项", options);
if(i >= 0){
toast("您选择的是" + options[i]);
}else{
toast("您取消了选择");
}
在ui模式下该函数返回一个Promise. 例如:
"ui";
dialogs.select("请选择一个选项", ["选项A", "选项B", "选项C", "选项D"])
.then(i => {
toast(i);
});
dialogs.singleChoice(title, items[, index, callback])#
显示一个单选列表对话框, 等待用户选择, 返回用户选择的选项索引(0 ~ item.length - 1). 如果用户取消了选择, 返回-1.
在ui模式下该函数返回一个Promise.
dialogs.multiChoice(title, items[, indices, callback])#
显示一个多选列表对话框, 等待用户选择, 返回用户选择的选项索引的数组. 如果用户取消了选择, 返回[].
在ui模式下该函数返回一个Promise.
dialogs.build(properties)#
properties{ Object } 对话框属性, 用于配置对话框.- 返回 { Dialog }
创建一个可自定义的对话框, 例如:
dialogs.build({
//对话框标题
title: "发现新版本",
//对话框内容
content: "更新日志: 新增了若干了BUG",
//确定键内容
positive: "下载",
//取消键内容
negative: "取消",
//中性键内容
neutral: "到浏览器下载",
//勾选框内容
checkBoxPrompt: "不再提示"
}).on("positive", ()=>{
//监听确定键
toast("开始下载....");
}).on("neutral", ()=>{
//监听中性键
app.openUrl("https://www.autojs.org");
}).on("check", (checked)=>{
//监听勾选框
log(checked);
}).show();
选项properties可供配置的项目为:
title{ string } 对话框标题titleColor{ string } | { number } 对话框标题的颜色buttonRippleColor{ string } | { number } 对话框按钮的波纹效果颜色icon{ string } | { Image } 对话框的图标, 是一个URL或者图片对象content{ string } 对话框文字内容contentColor{ string } | { number } 对话框文字内容的颜色contentLineSpacing{ number } 对话框文字内容的行高倍数, 1.0为一倍行高items{ Array } 对话框列表的选项itemsColor{ string } | { number } 对话框列表的选项的文字颜色itemsSelectMode{ string } 对话框列表的选项选择模式, 可以为:select普通选择模式single单选模式multi多选模式
itemsSelectedIndex{ number } | { Array } 对话框列表中预先选中的项目索引, 如果是单选模式为一个索引;多选模式则为数组positive{ string } 对话框确定按钮的文字内容(最右边按钮)positiveColor{ string } | { number } 对话框确定按钮的文字颜色(最右边按钮)neutral{ string } 对话框中立按钮的文字内容(最左边按钮)neutralColor{ string } | { number } 对话框中立按钮的文字颜色(最左边按钮)negative{ string } 对话框取消按钮的文字内容(确定按钮左边的按钮)negativeColor{ string } | { number } 对话框取消按钮的文字颜色(确定按钮左边的按钮)checkBoxPrompt{ string } 勾选框文字内容checkBoxChecked{ boolean } 勾选框是否勾选progress{ Object } 配置对话框进度条的对象:cancelable{ boolean } 对话框是否可取消, 如果为false, 则对话框只能用代码手动取消canceledOnTouchOutside{ boolean } 对话框是否在点击对话框以外区域时自动取消, 默认为trueinputHint{ string } 对话框的输入框的输入提示inputPrefill{ string } 对话框输入框的默认输入内容
通过这些选项可以自定义一个对话框, 并通过监听返回的Dialog对象的按键、输入事件来实现交互. 下面是一些例子.
模拟alert对话框:
dialogs.build({
title: "你好",
content: "今天也要元气满满哦",
positive: "好的"
}).show();
模拟confirm对话框:
dialogs.build({
title: "你好",
content: "请问你是笨蛋吗?",
positive: "是的",
negative: "我是大笨蛋"
}).on("positive", ()=>{
alert("哈哈哈笨蛋");
}).on("negative", ()=>{
alert("哈哈哈大笨蛋");
}).show();
模拟单选框:
dialogs.build({
title: "单选",
items: ["选项1", "选项2", "选项3", "选项4"],
itemsSelectMode: "single",
itemsSelectedIndex: 3
}).on("single_choice", (index, item)=>{
toast("您选择的是" + item);
}).show();
"处理中"对话框:
var d = dialogs.build({
title: "下载中...",
progress: {
max: -1
},
cancelable: false
}).show();
setTimeout(()=>{
d.dismiss();
}, 3000);
输入对话框:
dialogs.build({
title: "请输入您的年龄",
inputPrefill: "18"
}).on("input", (input)=>{
var age = parseInt(input);
toastLog(age);
}).show();
使用这个函数来构造对话框, 一个明显的不同是需要使用回调函数而不能像dialogs其他函数一样同步地返回结果;但也可以通过threads模块的方法来实现. 例如显示一个输入框并获取输入结果为:
var input = threads.disposable();
dialogas.build({
title: "请输入您的年龄",
inputPrefill: "18"
}).on("input", text => {
input.setAndNotify(text);
}).show();
var age = parseInt(input.blockedGet());
tosatLog(age);
Dialog#
dialogs.build()返回的对话框对象, 内置一些事件用于响应用户的交互, 也可以获取对话框的状态和信息.
事件: show#
dialog{ Dialog } 对话框
对话框显示时会触发的事件. 例如:
dialogs.build({
title: "标题"
}).on("show", (dialog)=>{
toast("对话框显示了");
}).show();
事件: cancel#
dialog{ Dialog } 对话框
对话框被取消时会触发的事件. 一个对话框可能按取消按钮、返回键取消或者点击对话框以外区域取消. 例如:
dialogs.build({
title: "标题",
positive: "确定",
negative: "取消"
}).on("cancel", (dialog)=>{
toast("对话框取消了");
}).show();
事件: dismiss#
dialog{ Dialog } 对话框
对话框消失时会触发的事件. 对话框被取消或者手动调用dialog.dismiss()函数都会触发该事件. 例如:
var d = dialogs.build({
title: "标题",
positive: "确定",
negative: "取消"
}).on("dismiss", (dialog)=>{
toast("对话框消失了");
}).show();
setTimeout(()=>{
d.dismiss();
}, 5000);
事件: positive#
dialog{ Dialog } 对话框
确定按钮按下时触发的事件. 例如:
var d = dialogs.build({
title: "标题",
positive: "确定",
negative: "取消"
}).on("positive", (dialog)=>{
toast("你点击了确定");
}).show();
事件: negative#
dialog{ Dialog } 对话框
取消按钮按下时触发的事件. 例如:
var d = dialogs.build({
title: "标题",
positive: "确定",
negative: "取消"
}).on("negative", (dialog)=>{
toast("你点击了取消");
}).show();
事件: neutral#
dialog{ Dialog } 对话框
中性按钮按下时触发的事件. 例如:
var d = dialogs.build({
title: "标题",
positive: "确定",
negative: "取消",
neutral: "稍后提示"
}).on("positive", (dialog)=>{
toast("你点击了稍后提示");
}).show();
事件: any#
dialog{ Dialog } 对话框action{ string } 被点击的按钮, 可能的值为:positive确定按钮negative取消按钮neutral中性按钮
任意按钮按下时触发的事件. 例如:
var d = dialogs.build({
title: "标题",
positive: "确定",
negative: "取消",
neutral: "稍后提示"
}).on("any", (action, dialog)=>{
if(action == "positive"){
toast("你点击了确定");
}else if(action == "negative"){
toast("你点击了取消");
}
}).show();
事件: item_select#
对话框列表(itemsSelectMode为"select")的项目被点击选中时触发的事件. 例如:
var d = dialogs.build({
title: "请选择",
positive: "确定",
negative: "取消",
items: ["A", "B", "C", "D"],
itemsSelectMode: "select"
}).on("item_select", (index, item, dialog)=>{
toast("您选择的是第" + (index + 1) + "项, 选项为" + item);
}).show();
事件: single_choice#
对话框单选列表(itemsSelectMode为"singleChoice")的项目被选中并点击确定时触发的事件. 例如:
var d = dialogs.build({
title: "请选择",
positive: "确定",
negative: "取消",
items: ["A", "B", "C", "D"],
itemsSelectMode: "singleChoice"
}).on("item_select", (index, item, dialog)=>{
toast("您选择的是第" + (index + 1) + "项, 选项为" + item);
}).show();
事件: multi_choice#
对话框多选列表(itemsSelectMode为"multiChoice")的项目被选中并点击确定时触发的事件. 例如:
var d = dialogs.build({
title: "请选择",
positive: "确定",
negative: "取消",
items: ["A", "B", "C", "D"],
itemsSelectMode: "multiChoice"
}).on("item_select", (indices, items, dialog)=>{
toast(util.format("您选择的项目为%o, 选项为%o", indices, items);
}).show();
事件: input#
text{ string } 输入框的内容dialog{ Dialog } 对话框
带有输入框的对话框当点击确定时会触发的事件. 例如:
dialogs.build({
title: "请输入",
positive: "确定",
negative: "取消",
inputPrefill: ""
}).on("input", (text, dialog)=>{
toast("你输入的是" + text);
}).show();
事件: input_change#
text{ string } 输入框的内容dialog{ Dialog } 对话框
对话框的输入框的文本发生变化时会触发的事件. 例如:
dialogs.build({
title: "请输入",
positive: "确定",
negative: "取消",
inputPrefill: ""
}).on("input_change", (text, dialog)=>{
toast("你输入的是" + text);
}).show();
dialog.getProgress()#
- 返回 { number }
获取当前进度条的进度值, 是一个整数
dialog.getMaxProgress()#
- 返回 { number }
获取当前进度条的最大进度值, 是一个整数
dialog.getActionButton(action)#
action{ string } 动作, 包括:positivenegativeneutral
悬浮窗 (Floaty)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
floaty模块提供了悬浮窗的相关函数, 可以在屏幕上显示自定义悬浮窗, 控制悬浮窗大小、位置等.
悬浮窗在脚本停止运行时会自动关闭, 因此, 要保持悬浮窗不被关闭, 可以用一个空的setInterval来实现, 例如:
setInterval(()=>{}, 1000);
floaty.window(layout)#
layout{ xml } | { View } 悬浮窗界面的XML或者View
指定悬浮窗的布局, 创建并显示一个悬浮窗, 返回一个FloatyWindow对象.
该悬浮窗自带关闭、调整大小、调整位置按键, 可根据需要调用setAdjustEnabled()函数来显示或隐藏.
其中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("文本");
});
有关返回的FloatyWindow对象的说明, 参见下面的FloatyWindow章节.
floaty.rawWindow(layout)#
layout{ xml } | { View } 悬浮窗界面的XML或者View
指定悬浮窗的布局, 创建并显示一个原始悬浮窗, 返回一个FloatyRawWindow对象.
与floaty.window()函数不同的是, 该悬浮窗不会增加任何额外设施(例如调整大小、位置按钮), 您可以根据自己需要编写任何布局.
而且, 该悬浮窗支持完全全屏, 可以覆盖状态栏, 因此可以做护眼模式之类的应用.
var w = floaty.rawWindow(
<frame gravity="center">
<text id="text">悬浮文字</text>
</frame>
);
w.setPosition(500, 500);
setTimeout(()=>{
w.close();
}, 2000);
这段代码运行后将会在屏幕上显示悬浮文字, 并在两秒后消失.
有关返回的FloatyRawWindow对象的说明, 参见下面的FloatyRawWindow章节.
floaty.closeAll()#
关闭所有本脚本的悬浮窗.
FloatyWindow#
悬浮窗对象, 可通过FloatyWindow.{id}获取悬浮窗界面上的元素. 例如, 悬浮窗window上一个控件的id为aaa, 那么window.aaa即可获取到该控件, 类似于ui.
window.setAdjustEnabled(enabled)#
enabled{ boolean } 是否启用悬浮窗调整(大小、位置)
如果enabled为true, 则在悬浮窗左上角、右上角显示可供位置、大小调整的标示, 就像控制台一样; 如果enabled为false, 则隐藏上述标示.
window.setPosition(x, y)#
设置悬浮窗位置.
window.getX()#
返回悬浮窗位置的X坐标.
window.getY()#
返回悬浮窗位置的Y坐标.
window.setSize(width, height)#
设置悬浮窗宽高.
window.getWidht()#
返回悬浮窗宽度.
window.getHeight()#
返回悬浮窗高度.
window.close()#
关闭悬浮窗. 如果悬浮窗已经是关闭状态, 则此函数将不执行任何操作.
被关闭后的悬浮窗不能再显示.
window.exitOnClose()#
使悬浮窗被关闭时自动结束脚本运行.
FloatyRawWindow#
原始悬浮窗对象, 可通过window.{id}获取悬浮窗界面上的元素. 例如, 悬浮窗window上一个控件的id为aaa, 那么window.aaa即可获取到该控件, 类似于ui.
window.setTouchable(touchable)#
touchable{ Boolean } 是否可触摸
设置悬浮窗是否可触摸, 如果为true, 则悬浮窗将接收到触摸、点击等事件并且无法继续传递到悬浮窗下面;如果为false, 悬浮窗上的触摸、点击等事件将被直接传递到悬浮窗下面. 处于安全考虑, 被悬浮窗接收的触摸事情无法再继续传递到下层.
可以用此特性来制作护眼模式脚本.
var w = floaty.rawWindow(
<frame gravity="center" bg="#44ffcc00"/>
);
w.setSize(-1, -1);
w.setTouchable(false);
setTimeout(()=>{
w.close();
}, 4000);
window.setPosition(x, y)#
设置悬浮窗位置.
window.getX()#
返回悬浮窗位置的X坐标.
window.getY()#
返回悬浮窗位置的Y坐标.
window.setSize(width, height)#
设置悬浮窗宽高.
特别地, 如果设置为-1, 则为占满全屏;设置为-2则为根据悬浮窗内容大小而定. 例如:
var w = floaty.rawWindow(
<frame gravity="center" bg="#77ff0000">
<text id="text">悬浮文字</text>
</frame>
);
w.setSize(-1, -1);
setTimeout(()=>{
w.close();
}, 2000);
window.getWidht()#
返回悬浮窗宽度.
window.getHeight()#
返回悬浮窗高度.
window.close()#
关闭悬浮窗. 如果悬浮窗已经是关闭状态, 则此函数将不执行任何操作.
被关闭后的悬浮窗不能再显示.
window.exitOnClose()#
使悬浮窗被关闭时自动结束脚本运行.
画布 (Canvas)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
canvas提供了使用画布进行2D画图的支持, 可用于简单的小游戏开发或者图片编辑. 使用canvas可以轻松地在一张图片或一个界面上绘制各种线与图形.
canvas的坐标系为平面直角坐标系, 以控件左上角为原点, 控件上边沿为x轴正方向, 控件左边沿为y轴正方向. 例如分辨率为1920*1080的屏幕上, canvas控件覆盖全屏, 画一条从屏幕左上角到屏幕右下角的线段为:
canvas.drawLine(0, 0, 1080, 1920, paint);
canvas的绘制依赖于画笔Paint, 通过设置画笔的粗细、颜色、填充等可以改变绘制出来的图形. 例如绘制一个红色实心正方形为:
var paint = new Paint();
//设置画笔为填充, 则绘制出来的图形都是实心的
paint.setStyle(Paint.STYLE.FILL);
//设置画笔颜色为红色
paint.setColor(colors.RED);
//绘制一个从坐标(0, 0)到坐标(100, 100)的正方形
canvas.drawRect(0, 0, 100, 100, paint);
如果要绘制正方形的边框, 则通过设置画笔的Style来实现:
var paint = new Paint();
//设置画笔为描边, 则绘制出来的图形都是轮廓
paint.setStyle(Paint.STYLE.STROKE);
//设置画笔颜色为红色
paint.setColor(colors.RED);
//绘制一个从坐标(0, 0)到坐标(100, 100)的正方形
canvas.drawRect(0, 0, 100, 100, paint);
结合画笔, canvas可以绘制基本图形、图片等.
canvas.getWidth()#
- 返回 { number }
返回画布当前图层的宽度.
canvas.getHeight()#
- 返回 { number }
返回画布当前图层的高度.
canvas.drawRGB(r, int g, int b)#
将整个可绘制区域填充为r、g、b指定的颜色. 相当于 canvas.drawColor(colors.rgb(r, g, b)).
canvas.drawARGB(a, r, g, b)#
将整个可绘制区域填充为a、r、g、b指定的颜色. 相当于 canvas.drawColor(colors.argb(a, r, g, b)).
canvas.drawColor(color)#
color{ number } 颜色值
将整个可绘制区域填充为color指定的颜色.
canvas.drawColor(color, mode)#
color{ number } 颜色值mode{ PorterDuff.Mode } Porter-Duff操作
将整个可绘制区域填充为color指定的颜色.
canvas.drawPaint(paint)#
paint{ Paint } 画笔
将整个可绘制区域用paint指定的画笔填充. 相当于绘制一个无限大的矩形, 但是更快. 通过该方法可以绘制一个指定的着色器的图案.
canvas.drawPoint(x, y, paint)#
在可绘制区域绘制由坐标(x, y)指定的点. 点的形状由画笔的线帽决定(参见paint.setStrokeCap(cap)). 点的大小由画笔的宽度决定(参见paint.setStrokeWidth(width)).
如果画笔宽度为0, 则也会绘制1个像素至4个(若抗锯齿启用).
相当于 canvas.drawPoints([x, y], paint).
canvas.drawPoints(pts, paint)#
pts{ Array} 点坐标数组 [x0, y0, x1, y1, x2, y2, ...] paint{ Paint } 画笔
在可绘制区域绘制由坐标数组指定的多个点.
canvas.drawLine(startX, startY, stopX, stopY, paint)#
在可绘制区域绘制由起点坐标(startX, startY)和终点坐标(endX, endY)指定的线. 绘制时会忽略画笔的样式(Style). 也就是说, 即使样式设为“仅填充(FILL)”也会绘制. 退化为点的线(长度为0)不会被绘制.
canvas.drawRect(r, paint)#
r{ Rect } 矩形边界paint{ Paint } 画笔
在可绘制区域绘制由矩形边界r指定的矩形. 绘制时画笔的样式(Style)决定了是否绘制矩形界线和填充矩形.
canvas.drawRect(left, top, right, bottom, android.graphics.Paint paint)#
在可绘制区域绘制由矩形边界(left, top, right, bottom)指定的矩形. 绘制时画笔的样式(Style)决定了是否绘制矩形界线和填充矩形.
canvas.drawOval(android.graphics.RectF oval, android.graphics.Paint paint)#
canvas.drawOval(float left, float top, float right, float bottom, android.graphics.Paint paint)#
canvas.drawCircle(float cx, float cy, float radius, android.graphics.Paint paint)#
canvas.drawArc(android.graphics.RectF oval, float startAngle, float sweepAngle, boolean useCenter, android.graphics.Paint paint)#
canvas.drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, android.graphics.Paint paint)#
canvas.drawRoundRect(android.graphics.RectF rect, float rx, float ry, android.graphics.Paint paint)#
canvas.drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, android.graphics.Paint paint)#
canvas.drawPath(android.graphics.Path path, android.graphics.Paint paint)#
canvas.drawBitmap(android.graphics.Bitmap bitmap, float left, float top, android.graphics.Paint paint)#
canvas.drawText(java.lang.String text, float x, float y, android.graphics.Paint paint)#
canvas.drawTextOnPath(java.lang.String text, android.graphics.Path path, float hOffset, float vOffset, android.graphics.Paint paint)#
canvas.translate(dx, dy)#
平移指定距离.
canvas.scale(sx, sy)#
以原点为中心, 将坐标系平移缩放指定倍数.
canvas.scale(float sx, float sy, float px, float py)#
canvas.rotate(float degrees)#
canvas.rotate(float degrees, float px, float py)#
canvas.skew(float sx, float sy)#
画笔#
变换矩阵#
路径#
Porter-Duff操作#
着色器#
遮罩过滤器#
颜色过滤器#
路径特效#
区域#
用户界面 (UI)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
ui模块提供了编写用户界面的支持.
给Android开发者或者高阶用户的提醒, Auto.js的UI系统来自于Android, 所有属性和方法都能在Android源码中找到. 如果某些代码或属性没有出现在Auto.js的文档中, 可以参考Android的文档.
View: https://developer.android.google.cn/reference/android/view/View?hl=cn
Widget: https://developer.android.google.cn/reference/android/widget/package-summary?hl=cn
带有ui的脚本的的最前面必须使用"ui";指定ui模式, 否则脚本将不会以ui模式运行. 正确示范:s
"ui";
//脚本的其他代码
字符串"ui"的前面可以有注释、空行和空格[v4.1.0新增], 但是不能有其他代码.
界面是由视图(View)组成的. View分成两种, 控件(Widget)和布局(Layout). 控件(Widget)用来具体显示文字、图片、网页等, 比如文本控件(text)用来显示文字, 按钮控件(button)则可以显示一个按钮并提供点击效果, 图片控件(img)则用来显示来自网络或者文件的图片, 除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器", 用于控制在他里面的控件的位置, 比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列), 水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列), 以及帧布局(frame), 他会把他里面的控件直接在左上角显示, 如果有多个控件, 后面的控件会重叠在前面的控件上.
我们使用xml来编写界面, 并通过ui.layout()函数指定界面的布局xml. 举个例子:
"ui";
$ui.layout(
<vertical>
<button text="第一个按钮"/>
<button text="第二个按钮"/>
</vertical>
);
在这个例子中, 第3~6行的部分就是xml, 指定了界面的具体内容. 代码的第3行的标签<vertical> ... </vertical>表示垂直布局, 布局的标签通常以<...>开始, 以</...>结束, 两个标签之间的内容就是布局里面的内容, 例如<frame> ... </frame>. 在这个例子中第4, 5行的内容就是垂直布局(vertical)里面的内容. 代码的第4行是一个按钮控件(button), 控件的标签通常以<...开始, 以/>结束, 他们之间是控件的具体属性, 例如<text ... />. 在这个例子中text="第一个按钮"的部分就是按钮控件(button)的属性, 这个属性指定了这个按钮控件的文本内容(text)为"第一个按钮".
代码的第5行和第4行一样, 也是一个按钮控件, 只不过他的文本内容为"第二个按钮". 这两个控件在垂直布局中, 因此会纵向排列, 效果如图:

如果我们把这个例子的垂直布局(vertical)改成水平布局(horizontal), 也即:
"ui";
ui.layout(
<horizontal>
<button text="第一个按钮"/>
<button text="第二个按钮"/>
</horizontal>
);
则这两个按钮会横向排列, 效果如图:

一个控件可以指定多个属性(甚至可以不指定任何属性), 用空格隔开即可;布局同样也可以指定属性, 例如:
"ui";
ui.layout(
<vertical bg="#ff0000">
<button text="第一个按钮" textSize="20sp"/>
<button text="第二个按钮"/>
</vertical>
);
第三行bg="#ff0000"指定了垂直布局的背景色(bg)为"#ff0000", 这是一个RGB颜色, 表示红色(有关RGB的相关知识参见RGB颜色对照表). 第四行的textSize="20sp"则指定了按钮控件的字体大小(textSize)为"20sp", sp是一个字体单位, 暂时不用深入理会. 上述代码的效果如图:

一个界面便由一些布局和控件组成. 为了便于文档阅读, 我们再说明一下以下术语:
- 子视图, 子控件: 布局里面的控件是这个布局的子控件/子视图. 实际上布局里面不仅仅只能有控件, 还可以是嵌套的布局. 因此用子视图(Child View)更准确一些. 在上面的例子中, 按钮便是垂直布局的子控件.
- 父视图, 父布局:直接包含一个控件的布局是这个控件的父布局/父视图(Parent View). 在上面的例子中, 垂直布局便是按钮的父布局.
视图: View#
控件和布局都属于视图(View). 在这个章节中将介绍所有控件和布局的共有的属性和函数. 例如属性背景, 宽高等(所有控件和布局都能设置背景和宽高), 函数click()设置视图(View)被点击时执行的动作.
attr(name, value)#
设置属性的值. 属性指定是View在xml中的属性. 例如可以通过语句attr("text", "文本")来设置文本控件的文本值.
"ui";
$ui.layout(
<frame>
<text id="example" text="Hello"/>
</frame>
);
// 5秒后执行
$ui.post(() => {
// 修改文本
$ui.example.attr("text", "Hello, Auto.js UI");
// 修改背景
$ui.example.attr("bg", "#ff00ff");
// 修改高度
$ui.example.attr("h", "500dp");
}, 5000);
注意:并不是所有属性都能在js代码设置, 有一些属性只能在布局创建时设置, 例如style属性;还有一些属性虽然能在代码中设置, 但是还没支持;对于这些情况, 在Auto.js Pro 8.1.0+会抛出异常, 其他版本则不会抛出异常.
attr(name)#
获取属性的值.
"ui";
$ui.layout(
<frame>
<text id="example" text="1"/>
</frame>
);
plusOne();
function plusOne() {
// 获取文本
let text = $ui.example.attr("text");
// 解析为数字
let num = parseInt(text);
// 数字加1
num++;
// 设置文本
$ui.example.attr("text", String(num));
// 1秒后继续
$ui.post(plusOne, 1000);
}
w#
View的宽度, 是属性width的缩写形式. 可以设置的值为*, auto和具体数值. 其中*表示宽度尽量填满父布局, 而auto表示宽度将根据View的内容自动调整(自适应宽度). 例如:
"ui";
ui.layout(
<horizontal>
<button w="auto" text="自适应宽度"/>
<button w="*" text="填满父布局"/>
</horizontal>
);
在这个例子中, 第一个按钮为自适应宽度, 第二个按钮为填满父布局, 显示效果为:

如果不设置该属性, 则不同的控件和布局有不同的默认宽度, 大多数为auto.
宽度属性也可以指定一个具体数值. 例如w="20", w="20px"等. 不加单位的情况下默认单位为dp, 其他单位包括px(像素), mm(毫米), in(英寸). 有关尺寸单位的更多内容, 参见尺寸的单位: Dimension.
"ui";
ui.layout(
<horizontal>
<button w="200" text="宽度200dp"/>
<button w="100" text="宽度100dp"/>
</horizontal>
);
h#
View的高度, 是属性height的缩写形式. 可以设置的值为*, auto和具体数值. 其中*表示宽度尽量填满父布局, 而auto表示宽度将根据View的内容自动调整(自适应宽度).
如果不设置该属性, 则不同的控件和布局有不同的默认高度, 大多数为auto.
宽度属性也可以指定一个具体数值. 例如h="20", h="20px"等. 不加单位的情况下默认单位为dp, 其他单位包括px(像素), mm(毫米), in(英寸). 有关尺寸单位的更多内容, 参见尺寸的单位: Dimension.
id#
View的id, 用来区分一个界面下的不同控件和布局, 一个界面的id在同一个界面下通常是唯一的, 也就是一般不存在两个View有相同的id. id属性也是连接xml布局和JavaScript代码的桥梁, 在代码中可以通过一个View的id来获取到这个View, 并对他进行操作(设置点击动作、设置属性、获取属性等). 例如:
"ui";
ui.layout(
<frame>
<button id="ok" text="确定"/>
</frame>
);
//通过ui.ok获取到按钮控件
toast(ui.ok.getText());
这个例子中有一个按钮控件"确定", id属性为"ok", 那么我们可以在代码中使用ui.ok来获取他, 再通过getText()函数获取到这个按钮控件的文本内容.
另外这个例子中使用帧布局(frame)是因为, 我们只有一个控件, 因此用于最简单的布局帧布局.
gravity#
View的"重力". 用于决定View的内容相对于View的位置, 可以设置的值为:
left靠左right靠右top靠顶部bottom靠底部center居中center_vertical垂直居中center_horizontal水平居中
例如对于一个按钮控件, gravity="right"会使其中的文本内容靠右显示. 例如:
"ui";
ui.layout(
<frame>
<button gravity="right" w="*" h="auto" text="靠右的文字"/>
</frame>
);
显示效果为:

这些属性是可以组合的, 例如gravity="right|bottom"的View他的内容会在右下角.
layout_gravity#
View在布局中的"重力", 用于决定View本身在他的父布局的位置, 可以设置的值和gravity属性相同. 注意把这个属性和gravity属性区分开来.
"ui";
ui.layout(
<frame w="*" h="*">
<button layout_gravity="center" w="auto" h="auto" text="居中的按钮"/>
<button layout_gravity="right|bottom" w="auto" h="auto" text="右下角的按钮"/>
</frame>
);
在这个例子中, 我们让帧布局(frame)的大小占满整个屏幕, 通过给第一个按钮设置属性layout_gravity="center"来使得按钮在帧布局中居中, 通过给第二个按钮设置属性layout_gravity="right|bottom"使得他在帧布局中位于右下角. 效果如图:

要注意的是, layout_gravity的属性不一定总是生效的, 具体取决于布局的类别. 例如不能让水平布局中的第一个子控件靠底部显示(否则和水平布局本身相违背).
margin#
margin为View和其他View的间距, 即外边距. margin属性包括四个值:
marginLeft左外边距marginRight右外边距marginTop上外边距marginBottom下外边距
而margin属性本身的值可以有三种格式:
margin="marginAll"指定各个外边距都是该值. 例如margin="10"表示左右上下边距都是10dp.margin="marginLeft marginTop marginRight marginBottom"分别指定各个外边距. 例如margin="10 20 30 40"表示左边距为10dp, 上边距为20dp, 右边距为30dp, 下边距为40dpmargin="marginHorizontal marginVertical"指定水平外边距和垂直外边距. 例如margin="10 20"表示左右边距为10dp, 上下边距为20dp.
用一个例子来具体理解外边距的含义:
"ui";
ui.layout(
<horizontal>
<button margin="30" text="距离四周30"/>
<button text="普通的按钮"/>
</horizontal>
);
第一个按钮的margin属性指定了他的边距为30dp, 也就是他与水平布局以及第二个按钮的间距都是30dp, 其显示效果如图:

如果把margin="30"改成margin="10 40"那么第一个按钮的左右间距为10dp, 上下间距为40dp, 效果如图:

有关margin属性的单位, 参见尺寸的单位: Dimension.
marginLeft#
View的左外边距. 如果该属性和margin属性指定的值冲突, 则在后面的属性生效, 前面的属性无效, 例如margin="20" marginLeft="10"的左外边距为10dp, 其他外边距为20dp.
"ui";
ui.layout(
<horizontal>
<button marginLeft="50" text="距离左边50"/>
<button text="普通的按钮"/>
</horizontal>
);
第一个按钮指定了左外边距为50dp, 则他和他的父布局水平布局(horizontal)的左边的间距为50dp, 效果如图:

marginRight#
View的右外边距. 如果该属性和margin属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
marginTop#
View的上外边距. 如果该属性和margin属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
marginBottom#
View的下外边距. 如果该属性和margin属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
padding#
View和他的自身内容的间距, 也就是内边距. 注意和margin属性区分开来, margin属性是View之间的间距, 而padding是View和他自身内容的间距. 举个例子, 一个文本控件的padding也即文本控件的边缘和他的文本内容的间距, paddingLeft即文本控件的左边和他的文本内容的间距.
paddding属性的值同样有三种格式:
padding="paddingAll"指定各个内边距都是该值. 例如padding="10"表示左右上下内边距都是10dp.padding="paddingLeft paddingTop paddingRight paddingBottom"分别指定各个内边距. 例如padding="10 20 30 40"表示左内边距为10dp, 上内边距为20dp, 右内边距为30dp, 下内边距为40dppadding="paddingHorizontal paddingVertical"指定水平内边距和垂直内边距. 例如padding="10 20"表示左右内边距为10dp, 上下内边距为20dp.
用一个例子来具体理解内边距的含义:
"ui";
ui.layout(
<frame w="*" h="*" gravity="center">
<text padding="10 20 30 40" bg="#ff0000" w="auto" h="auto" text="HelloWorld"/>
</frame>
);
这个例子是一个居中的按钮(通过父布局的gravity="center"属性设置), 背景色为红色(bg="#ff0000"), 文本内容为"HelloWorld", 左边距为10dp, 上边距为20dp, 下边距为30dp, 右边距为40dp, 其显示效果如图:

paddingLeft#
View的左内边距. 如果该属性和padding属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
paddingRight#
View的右内边距. 如果该属性和padding属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
paddingTop#
View的上内边距. 如果该属性和padding属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
paddingBottom#
View的下内边距. 如果该属性和padding属性指定的值冲突, 则在后面的属性生效, 前面的属性无效.
bg#
View的背景. 其值可以是一个链接或路径指向的图片, 或者RGB格式的颜色, 或者其他背景. 具体参见Drawables.
例如, bg="#00ff00"设置背景为绿色, bg="file:///sdcard/1.png"设置背景为图片"1.png", bg="?attr/selectableItemBackground"设置背景为点击时出现的波纹效果(可能需要同时设置clickable="true"才生效).
alpha#
View的透明度, 其值是一个0~1之间的小数, 0表示完全透明, 1表示完全不透明. 例如alpha="0.5"表示半透明.
foreground#
View的前景. 前景即在一个View的内容上显示的内容, 可能会覆盖掉View本身的内容. 其值和属性bg的值类似.
minHeight#
View的最小高度. 该值不总是生效的, 取决于其父布局是否有足够的空间容纳.
例:<text height="auto" minHeight="50"/>
有关该属性的单位, 参见尺寸的单位: Dimension.
minWidth#
View的最小宽度. 该值不总是生效的, 取决于其父布局是否有足够的空间容纳.
例:<input width="auto" minWidth="50"/>
有关该属性的单位, 参见尺寸的单位: Dimension.
visibility#
View的可见性, 该属性可以决定View是否显示出来. 其值可以为:
gone不可见.visible可见. 默认情况下View都是可见的.invisible不可见, 但仍然占用位置.
rotation#
View的旋转角度. 通过该属性可以让这个View顺时针旋转一定的角度. 例如rotation="90"可以让他顺时针旋转90度.
如果要设置旋转中心, 可以通过transformPivotX, transformPivotY属性设置. 默认的旋转中心为View的中心.
transformPivotX#
View的变换中心坐标x. 用于View的旋转、放缩等变换的中心坐标. 例如transformPivotX="10".
该坐标的坐标系以View的左上角为原点. 也就是x值为变换中心到View的左边的距离.
有关该属性的单位, 参见尺寸的单位: Dimension.
transformPivotY#
View的变换中心坐标y. 用于View的旋转、放缩等变换的中心坐标. 例如transformPivotY="10".
该坐标的坐标系以View的左上角为原点. 也就是y值为变换中心到View的上边的距离.
有关该属性的单位, 参见尺寸的单位: Dimension.
style#
设置View的样式. 不同控件有不同的可选的内置样式. 具体参见各个控件的说明.
需要注意的是, style属性只支持安卓5.1及其以上.
文本控件: text#
文本控件用于显示文本, 可以控制文本的字体大小, 字体颜色, 字体等.
以下介绍该控件的主要属性和方法, 如果要查看他的所有属性和方法, 请阅读TextView.
text#
设置文本的内容. 例如text="一段文本".
textColor#
设置字体的颜色, 可以是RGB格式的颜色(例如#ff00ff), 或者颜色名称(例如red, green等), 具体参见颜色.
示例, 红色字体:<text text="红色字体" textColor="red"/>
textSize#
设置字体的大小, 单位一般是sp. 按照Material Design的规范, 正文字体大小为14sp, 标题字体大小为18sp, 次标题为16sp.
示例, 超大字体: <text text="超大字体" textSize="40sp"/>
textStyle#
设置字体的样式, 比如斜体、粗体等. 可选的值为:
- bold 加粗字体
- italic 斜体
- normal 正常字体
可以用或("|")把他们组合起来, 比如粗斜体为"bold|italic".
例如, 粗体:`
lines#
设置文本控件的行数. 即使文本内容没有达到设置的行数, 控件也会留出相应的宽度来显示空白行;如果文本内容超出了设置的行数, 则超出的部分不会显示.
另外在xml中是不能设置多行文本的, 要在代码中设置. 例如:
"ui";
ui.layout(
<vertical>
<text id="myText" line="3">
</vertical>
)
//通过\n换行
ui.myText.setText("第一行\n第二行\n第三行\n第四行");
maxLines#
设置文本控件的最大行数.
typeface#
设置字体. 可选的值为:
normal正常字体sans衬线字体serif非衬线字体monospace等宽字体
示例, 等宽字体: <text text="等宽字体" typeface="monospace"/>
ellipsize#
设置文本的省略号位置. 文本的省略号会在文本内容超出文本控件时显示. 可选的值为:
end在文本末尾显示省略号marquee跑马灯效果, 文本将滚动显示middle在文本中间显示省略号none不显示省略号start在文本开头显示省略号
ems#
当设置该属性后,TextView显示的字符长度(单位是em),超出的部分将不显示, 或者根据ellipsize属性的设置显示省略号.
例如, 限制文本最长为5em: `
autoLink#
控制是否自动找到url和电子邮件地址等链接, 并转换为可点击的链接. 默认值为“none”.
设置该值可以让文本中的链接、电话等变成可点击状态.
可选的值为以下的值以其通过或("|")的组合:
all匹配所有连接、邮件、地址、电话email匹配电子邮件地址map匹配地图地址none不匹配 (默认)phone匹配电话号码web匹配URL地址
示例:<text autoLink="web|phone" text="百度: http://www.baidu.com 电信电话: 10000"/>
按钮控件: button#
按钮控件是一个特殊的文本控件, 因此所有文本控件的函数的属性都适用于按钮控件.
除此之外, 按钮控件有一些内置的样式, 通过style属性设置, 包括:
- Widget.AppCompat.Button.Colored 带颜色的按钮
- Widget.AppCompat.Button.Borderless 无边框按钮
- Widget.AppCompat.Button.Borderless.Colored 带颜色的无边框按钮
这些样式的具体效果参见"示例/界面控件/按钮控件.js".
例如:<button style="Widget.AppCompat.Button.Colored" text="漂亮的按钮"/>
输入框控件: input#
输入框控件也是一个特殊的文本控件, 因此所有文本控件的函数的属性和函数都适用于按钮控件. 输入框控件有自己的属性和函数, 要查看所有这些内容, 阅读EditText.
对于一个输入框控件, 我们可以通过text属性设置他的内容, 通过lines属性指定输入框的行数;在代码中通过getText()函数获取输入的内容. 例如:
"ui";
ui.layout(
<vertical padding="16">
<text textSize="16sp" textColor="black" text="请输入姓名"/>
<input id="name" text="小明"/>
<button id="ok" text="确定"/>
</vertical>
);
//指定确定按钮点击时要执行的动作
ui.ok.click(function(){
//通过getText()获取输入的内容
var name = ui.name.getText();
toast(name + "您好!");
});
效果如图:

除此之外, 输入框控件有另外一些主要属性(虽然这些属性对于文本控件也是可用的但一般只用于输入框控件):
hint#
输入提示. 这个提示会在输入框为空的时候显示出来. 如图所示:

上面图片效果的代码为:
"ui";
ui.layout(
<vertical>
<input hint="请输入姓名"/>
</vertical>
)
textColorHint#
指定输入提示的字体颜色.
textSizeHint#
指定输入提示的字体大小.
inputType#
指定输入框可以输入的文本类型. 可选的值为以下值及其用"|"的组合:
date用于输入日期.datetime用于输入日期和时间.none没有内容类型. 此输入框不可编辑.number仅可输入数字.numberDecimal可以与number和它的其他选项组合, 以允许输入十进制数(包括小数).numberPassword仅可输入数字密码.numberSigned可以与number和它的其他选项组合, 以允许输入有符号的数.phone用于输入一个电话号码.text只是普通文本.textAutoComplete可以与text和它的其他选项结合, 以指定此字段将做自己的自动完成, 并适当地与输入法交互.textAutoCorrect可以与text和它的其他选项结合, 以请求自动文本输入纠错.textCapCharacters可以与text和它的其他选项结合, 以请求大写所有字符.textCapSentences可以与text和它的其他选项结合, 以请求大写每个句子里面的第一个字符.textCapWords可以与text和它的其他选项结合, 以请求大写每个单词里面的第一个字符.textEmailAddress用于输入一个电子邮件地址.textEmailSubject用于输入电子邮件的主题.textImeMultiLine可以与text和它的其他选项结合, 以指示虽然常规文本视图不应为多行, 但如果可以, 则IME应提供多行支持.textLongMessage用于输入长消息的内容.textMultiLine可以与text和它的其他选项结合, 以便在该字段中允许多行文本. 如果未设置此标志, 则文本字段将被限制为单行.textNoSuggestions可以与text及它的其他选项结合, 以指示输入法不应显示任何基于字典的单词建议.textPassword用于输入密码.textPersonName用于输入人名.textPhonetic用于输入拼音发音的文本, 如联系人条目中的拼音名称字段.textPostalAddress用于输入邮寄地址.textShortMessage用于输入短的消息内容.textUri用于输入一个URI.textVisiblePassword用于输入可见的密码.textWebEditText用于输入在web表单中的文本.textWebEmailAddress用于在web表单里输入一个电子邮件地址.textWebPassword用于在web表单里输入一个密码.time用于输入时间.
例如, 想指定一个输入框的输入类型为小数数字, 为: <input inputType="number|numberDecimal"/>
password#
指定输入框输入框是否为密码输入框. 默认为false.
例如:<input password="true"/>
numeric#
指定输入框输入框是否为数字输入框. 默认为false.
例如:<input numeric="true"/>
phoneNumber#
指定输入框输入框是否为电话号码输入框. 默认为false.
例如:<input phoneNumber="true"/>
digits#
指定输入框可以输入的字符. 例如, 要指定输入框只能输入"1234567890+-", 为<input digits="1234567890+-"/>.
singleLine#
指定输入框是否为单行输入框. 默认为false. 您也可以通过lines="1"来指定单行输入框.
例如:<input singleLine="true"/>
图片控件: img#
图片控件用于显示来自网络、本地或者内嵌数据的图片, 并可以指定图片以圆角矩形、圆形等显示. 但是不能用于显示gif动态图.
这里只介绍他的主要方法和属性, 如果要查看他的所有方法和属性, 阅读ImageView.
src#
使用一个Uri指定图片的来源. 可以是图片的地址(http://....), 本地路径(file://....)或者base64数据("data:image/png;base64,...").
如果使用图片地址或本地路径, Auto.js会自动使用适当的缓存来储存这些图片, 减少下次加载的时间.
例如, 显示百度的logo:
"ui";
ui.layout(
<frame>
<img src="https://www.baidu.com/img/bd_logo1.png"/>
</frame>
);
再例如, 显示文件/sdcard/1.png的图片为 <img src="file:///sdcard/1.png"/>.
再例如, 使base64显示一张钱包小图片为:
"ui";
ui.layout(
<frame>
<img w="40" h="40" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEu0lEQVRoge3bW4iVVRQH8N+ZnDKxvJUGCSWUlXYle/ChiKAkIiu7UXQjonwNIopM8cHoAhkRGQXdfIiE0Ep8KalQoptRTiFFZiRlOo6TPuSk4zk97G9w5vidc77LPjNi84f1MN+391rrf9a+rL32N4xiFMcUjouo5zyciYPYH0FnBadiNiZiD2oR9JbGRdgiOFPDIXRhCWYU0Dcj6duV6BrQuyWxNaLowBcOO1Uv+7EKc4WINUIlabMq6dNI35eJzRHDWOzS2MEB6cd6XI/OQf07k2frkzat9HQnNkcUG7R2dECq2I53EtmePMvaf+MwcWqKu+RzuqhUcfcwcWqKTvmiXFQ2GDodRhQz0aN9ZHsSG0cVrkGf+GT7MG8YeeTCHeKS7sOdMR1stjcWxY2YH0nXh1gdSdf/E+2I8KVYigkl9ewVUsxNpT1qMzaKN4ejJxrtyEt7IuraE1EX2jOkp+JBnFxSzz68KuTqoyiK2BHuxDO4NpK+j/GoOAWF6BiH98Q/SHyCycPIIxMm4FPZCPTj30SynIFr+A7ThotMK4wXopA1Ym9gSiKv5Oj3bdKnFMpuS514E1fm6NMnbF098s3NS4QS0Ik5+hyBsoSXYkGO9jvxy6C/t+IPIYJZcBWW57AXFfMNrSo2kqqw2l4hvSzcIRTw1sm24FVxb5s4NcR0/JXBuUNYJttI6sDjsi1kvTgrGpsMjq3O4FQNa+SbNhWsyKj7I4wpzSYDbpFtKB/EOSn9ZwpRfx5Xp7yfhN0Z9FdxXxxKjTEe2zI4U8NnKf3PNrT2VcWTKe1eyGjjT+Eapm14IqMjNTyd0n9JSrsDwhmaEN2H8GMOO8viUjyMSfJVJh9O0bGoQdt1eFm2oVwve7UpC1ssX568KEXH6fghp54s8lRkrk7CjpxOrGqg6wQ8IKSKWXPpVtIt8ly+v4ATf2t+yqlgDl5SbCjXy8JIXFXweQEHqngxo43JeEw54l+JVLKaJeypRZzoFxavrIWG6cKPW2SO9+PCMkQHsLiA8fpIv5/DmUn4qaCtpWWIEiLzdUHj9XJA2H5uFRbBZriuoI1NSpatpio+nJtFvFvYd2c1sDsGvxfQ3a/knrwgMtm0qD8rPSprCuq8uRmhVqvanBbvm+EQfsNKIcnvTmnTiUdwQcq73oJ2L2v2stXx6vyCRr8RDuk/C8OMUK24J6VtBaekPG81zxuh0TTJhC7FhtUOHF+n61whGalvu8uRWVJFvgPEYOkqQzhLVSPPXLoYa4Xh3Stcls1NaTdb8Xx7ZxnCvSUIfy/kzWno0Pyzx3dL2C0695Hto7NGUhXy5Lzp3kLZKiqNpNTl2+YShgdIvyXbVck44TB/oKTNzWUIv13S+IDsFmpY84QvZAcwTbh4e04o18SwtbIM4dsiOTFYVgzSv7wN+m9vRqjV/PrA0JuCox1bhYNKQ7Qi3CcU1fpiedRG9AkLXhRfbxCnKlET0s21ifwaSWcPbopBdDDOwGtClTD2vCsq+/C68K8HmVDk7DhFyIsvFzKnGThN+689+oU9dptwQb5B+LB8dx4lMb7xqAhkJwo/xljhFFSfSdUc3mPrcbwj15P+pP0/QiR7hYSkGsHnUYziWMF/mXV4JVcZ8G0AAAAASUVORK5CYII="/>
</frame>
);
tint#
图片着色, 其值是一个颜色名称或RGB颜色值. 使用该属性会将图片中的非透明区域都涂上同一颜色. 可以用于改变图片的颜色.
例如, 对于上面的base64的图片: <img w="40" h="40" tint="red" src="data:image/png;base64,..."/>, 则钱包图标颜色会变成红色.
scaleType#
控制图片根据图片控件的宽高放缩时的模式. 可选的值为:
center在控件中居中显示图像, 但不执行缩放.centerCrop保持图像的长宽比缩放图片, 使图像的尺寸 (宽度和高度) 等于或大于控件的相应尺寸 (不包括内边距padding)并且使图像在控件中居中显示.centerInside保持图像的长宽比缩放图片, 使图像的尺寸 (宽度和高度) 小于视图的相应尺寸 (不包括内边距padding)并且图像在控件中居中显示.fitCenter保持图像的长宽比缩放图片, 使图片的宽或高和控件的宽高相同并使图片在控件中居中显示fitEnd保持图像的长宽比缩放图片, 使图片的宽或高和控件的宽高相同并使图片在控件中靠右下角显示fitStart保持图像的长宽比缩放图片, 使图片的宽或高和控件的宽高相同并使图片在控件靠左上角显示fitXY使图片和宽高和控件的宽高完全匹配, 但图片的长宽比可能不能保持一致matrix绘制时使用图像矩阵进行缩放. 需要在代码中使用setImageMatrix(Matrix)函数才能生效.
默认的scaleType为fitCenter;除此之外最常用的是fitXY, 他能使图片放缩到控件一样的大小, 但图片可能会变形.
radius#
图片控件的半径. 如果设置为控件宽高的一半并且控件的宽高相同则图片将剪切为圆形显示;否则图片为圆角矩形显示, 半径即为四个圆角的半径, 也可以通过radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight等属性分别设置四个圆角的半径.
例如, 圆角矩形的Auto.js图标:<img w="100" h="100" radius="20" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" />
有关该属性的单位, 参见尺寸的单位: Dimension.
radiusTopLeft#
图片控件的左上角圆角的半径. 有关该属性的单位, 参见尺寸的单位: Dimension.
radiusTopRight#
图片控件的右上角圆角的半径. 有关该属性的单位, 参见尺寸的单位: Dimension.
radiusBottomLeft#
图片控件的左下角圆角的半径. 有关该属性的单位, 参见尺寸的单位: Dimension.
radiusBottomRight#
图片控件的右下角圆角的半径. 有关该属性的单位, 参见尺寸的单位: Dimension.
borderWidth#
图片控件的边框宽度. 用于在图片外面显示一个边框, 边框会随着图片控件的外形(圆角等)改变而相应变化.
例如, 圆角矩形带灰色边框的Auto.js图标:<img w="100" h="100" radius="20" borderWidth="5" borderColor="gray" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" />
borderColor#
图片控件的边框颜色.
circle#
指定该图片控件的图片是否剪切为圆形显示. 如果为true, 则图片控件会使其宽高保持一致(如果宽高不一致, 则保持高度等于宽度)并使圆形的半径为宽度的一半.
例如, 圆形的Auto.js图标:<img w="100" h="100" circle="true" bg="white" src="http://www.autojs.org/assets/uploads/profile/3-profileavatar.png" />
垂直布局: vertical#
垂直布局是一种比较简单的布局, 会把在它里面的控件按照垂直方向依次摆放, 如下图所示:
垂直布局:
—————
| 控件1 |
| 控件2 |
| 控件3 |
| ............ |
——————
layout_weight#
垂直布局中的控件可以通过layout_weight属性来控制控件高度占垂直布局高度的比例. 如果为一个控件指定layout_weight, 则这个控件的高度=垂直布局剩余高度 * layout_weight / weightSum;如果不指定weightSum, 则weightSum为所有子控件的layout_weight之和. 所谓"剩余高度", 指的是垂直布局中减去没有指定layout_weight的控件的剩余高度.
例如:
"ui";
ui.layout(
<vertical h="100dp">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="1" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);
在这个布局中, 三个控件的layout_weight都是1, 也就是他们的高度都会占垂直布局高度的1/3, 都是33.3dp. 再例如:
"ui";
ui.layout(
<vertical h="100dp">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);
在这个布局中, 第一个控件高度为1/4, 第二个控件为2/4, 第三个控件为1/4. 再例如:
"ui";
ui.layout(
<vertical h="100dp" weightSum="5">
<text layout_weight="1" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);
在这个布局中, 因为指定了weightSum为5, 因此第一个控件高度为1/5, 第二个控件为2/5, 第三个控件为1/5. 再例如:
"ui";
ui.layout(
<vertical h="100dp">
<text h="40dp" text="控件1" bg="#ff0000"/>
<text layout_weight="2" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);
在这个布局中, 第一个控件并没有指定layout_weight, 而是指定高度为40dp, 因此不加入比例计算, 此时布局剩余高度为60dp. 第二个控件高度为剩余高度的2/3, 也就是40dp, 第三个控件高度为剩余高度的1/3, 也就是20dp.
垂直布局的layout_weight属性还可以用于控制他的子控件高度占满剩余空间, 例如:
"ui";
ui.layout(
<vertical h="100dp">
<text h="40dp" text="控件1" bg="#ff0000"/>
<text h="40dp" text="控件2" bg="#00ff00"/>
<text layout_weight="1" text="控件3" bg="#0000ff"/>
</vertical>
);
在这个布局中, 第三个控件的高度会占满除去控件1和控件2的剩余空间.
水平布局: horizontal#
水平布局是一种比较简单的布局, 会把在它里面的控件按照水平方向依次摆放, 如下图所示: 水平布局: ————————————————————————————
| 控件1 | 控件2 | 控件3 | ... |
————————————————————————————
layout_weight#
水平布局中也可以使用layout_weight属性来控制子控件的宽度占父布局的比例. 和垂直布局中类似, 不再赘述.
线性布局: linear#
实际上, 垂直布局和水平布局都属于线性布局. 线性布局有一个orientation的属性, 用于指定布局的方向, 可选的值为vertical和horizontal.
例如<linear orientation="vertical"></linear>相当于<vertical></vertical>.
线性布局的默认方向是横向的, 因此, 一个没有指定orientation属性的线性布局就是横向布局.
帧布局: frame#
帧布局
相对布局: relative#
勾选框控件: checkbox#
选择框控件: radio#
选择框布局: radiogroup#
开关控件: Switch#
开关控件用于表示一个选项是否被选中.
checked#
表示开关是否被选中. 可选的值为:
true打开开关false关闭开关
text#
对开关进行描述的文字.
进度条控件: progressbar#
拖动条控件: seekbar#
下来菜单控件: spinner#
时间选择控件: timepicker#
日期选择控件: datepicker#
浮动按钮控件: fab#
标题栏控件: toolbar#
卡片: card#
卡片控件是一个拥有圆角、阴影的控件.
cardBackgroundColor#
卡片的背景颜色.
cardCornerRadius#
卡片的圆角半径.
cardElevation#
设置卡片在z轴上的高度, 来控制阴影的大小.
contentPadding#
设置卡片的内边距. 该属性包括四个值:
contentPaddingLeft左内边距contentPaddingRight右内边距contentPaddingTop上内边距contentPaddingBottom下内边距
foreground#
使用foreground="?selectableItemBackground"属性可以为卡片添加点击效果.
抽屉布局: drawer#
列表: list#
Tab: tab#
ui#
ui.layout(xml)#
xml{ XML } | { string } 布局XML或者XML字符串
将布局XML渲染为视图(View)对象, 并设置为当前视图.
ui.layoutFile(xmlFile)#
xml{ string } 布局XML文件的路径
此函数和ui.layout相似, 只不过允许传入一个xml文件路径来渲染布局.
ui.inflate(xml[, parent = null, attachToParent = false])#
将布局XML渲染为视图(View)对象. 如果该View将作为某个View的子View, 我们建议传入parent参数, 这样在渲染时依赖于父视图的一些布局属性能够正确应用.
此函数用于动态创建、显示View.
"ui";
$ui.layout(
<linear id="container">
</linear>
);
// 动态创建3个文本控件, 并加到container容器中
// 这里仅为实例, 实际上并不推荐这种做法, 如果要展示列表,
// 使用list组件;动态创建十几个、几十个View会让界面卡顿
for (let i = 0; i < 3; i++) {
let textView = $ui.inflate(
<text textColor="#000000" textSize="14sp"/>
, $ui.container);
textView.attr("text", "文本控件" + i);
$ui.container.addView(textView);
}
ui.registerWidget(name, widget)#
注册一个自定义组件. 参考示例->界面控件->自定义控件.
ui.isUiThread()#
- 返回 { boolean }
返回当前线程是否是UI线程.
"ui";
log($ui.isUiThread()); // => true
$threads.start(function () {
log($ui.isUiThread()); // => false
});
ui.findView(id)#
id{ string } View的ID- 返回 { View }
在当前视图中根据ID查找相应的视图对象并返回. 如果当前未设置视图或找不到此ID的视图时返回null.
一般我们都是通过ui.xxx来获取id为xxx的控件, 如果xxx是一个ui已经有的属性, 就可以通过$ui.findView()来获取这个控件.
ui.finish()#
结束当前活动并销毁界面.
ui.setContentView(view)#
view{ View }
将视图对象设置为当前视图.
ui.post(callback[, delay = 0])#
将callback加到UI线程的消息循环中, 并延迟delay毫秒后执行(不能准确保证一定在delay毫秒后执行).
此函数可以用于UI线程中延时执行动作(sleep不能在UI线程中使用), 也可以用于子线程中更新UI.
"ui";
ui.layout(
<frame>
<text id="result"/>
</frame>
);
ui.result.attr("text", "计算中");
// 在子线程中计算1+ ... + 10000000
threads.start({
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i;
}
// 由于不能在子线程操作UI, 所以要抛到UI线程执行
ui.post(() => {
ui.result.attr("text", String(sum));
});
});
ui.run(callback)#
callback{ Function } 回调函数- 返回 callback的执行结果
将callback在UI线程中执行. 如果当前已经在UI线程中, 则直接执行callback;否则将callback抛到UI线程中执行(加到UI线程的消息循环的末尾), 并等待callback执行结束(阻塞当前线程).
ui.statusBarColor(color)#
设置当前界面的状态栏颜色.
"ui";
ui.statusBarColor("#000000");
ui.useAndroidResources()#
启用使用Android的布局(layout)、绘图(drawable)、动画(anim)、样式(style)等资源的特性. 启用该特性后, 在project.json中进行以下配置, 就可以像写Android原生一样写界面:
{
// ...
androidResources: {
"resDir": "res", // 资源文件夹
"manifest": "AndroidManifest.xml" // AndroidManifest文件路径
}
}
res文件夹通常为以下结构:
- res
- layout // 布局资源
- drawable // 图片、形状等资源
- menu // 菜单资源
- values // 样式、字符串等资源
// ...
可参考示例->复杂界面->Android原生界面.
尺寸的单位: Dimension#
Drawables#
颜色#
(完善中...)
万维网 (Web)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
HTTP#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
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 = " + res.statusCode);
log("html = " + res.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;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/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函数的默认方式.
一个调用图灵机器人接口的例子如下:
var url = "http://www.tuling123.com/openapi/api";
r = http.postJson(url, {
key: "65458a5df537443b89b31f1c03202a80",
info: "你好啊",
userid: "1",
});
toastLog(r.body.string());
http.postMultipart(url, files[, options, callback])#
向目标地址发起类型为multipart/form-data的请求(通常用于文件上传等), 其中files参数是{ name1: value1, name2: value2, ... }的键值对, value的格式可以是以下几种情况:
string- 文件类型, 即open()返回的类型
- [fileName, filePath]
- [fileName, mimeType, filePath]
其中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可以包含以下属性:
headers{ Object } 键值对形式的HTTP头部信息. 有关HTTP头部信息, 参见菜鸟教程:HTTP响应头信息.method{ string } HTTP请求方法. 包括"GET", "POST", "PUT", "DELET", "PATCH".contentType{ string } HTTP头部信息中的"Content-Type", 表示HTTP请求的内容类型. 例如"text/plain", "application/json". 更多信息参见菜鸟教程:HTTP contentType.body{ string } | { Array } | { Function } HTTP请求的内容. 可以是一个字符串, 也可以是一个字节数组;或者是一个以BufferedSink为参数的函数.
该函数是get, post, postJson等函数的基础函数. 因此除非是PUT, DELET等请求, 或者需要更高定制的HTTP请求, 否则直接使用get, post, postJson等函数会更加方便.
Response#
HTTP请求的响应.
Response.statusCode#
- { number }
当前响应的HTTP状态码. 例如200(OK), 404(Not Found)等.
有关HTTP状态码的信息, 参见菜鸟教程:HTTP状态码.
Response.statusMessage#
- { string }
当前响应的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#
- { Object }
当前响应的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#
- { Object }
当前响应的内容. 他有以下属性和函数:
- bytes() { Array } 以字节数组形式返回响应内容
- string() { string } 以字符串形式返回响应内容
- json() { Object } 把响应内容作为JSON格式的数据并调用JSON.parse, 返回解析后的对象
- contentType { string } 当前响应的内容类型
Response.request#
- { Request } 当前响应所对应的请求. 参见[Request][].
Response.url#
- { number } 当前响应所对应的请求URL.
Response.method#
- { string } 当前响应所对应的HTTP请求的方法. 例如"GET", "POST", "PUT"等.
Base64#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
密文 (Crypto)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
$crypto模块提供了对称加密(例如AES)、非对称加密(例如RSA)、消息摘要(例如MD5, SHA)等支持.
$crypto.digest(message, algorithm[, options])#
message{ any }algorithm{ string } 消息摘要算法, 包括:- MD5
- SHA-1
- SHA-256
- SHA-384
- SHA-512
options{ any }
对信息message使用消息摘要算法algorithm进行摘要并返回结果, 默认的输出格式为hex.
参数message的类型默认为字符串, 返回值默认为hex;可以通过options来指定参数message的类型和返回值的类型、格式, 比如文件、base64、字节数组、hex等. 参见《输入和输出的类型和格式》.
// 计算字符串abc的md5
toastLog($crypto.digest("abc", "MD5"));
// 计算字符串abc的sha-256
toastLog($crypto.digest("abc", "SHA-256"));
// 计算文件/sdcard/1.txt的md5
toastLog($crypto.digest("/sdcard/1.txt", "MD5", {
input: "file"
}));
$crypto.encrypt(data, key, algorithm, options)#
data{ any } 明文消息key{ Key } 密钥algorithm{ string } 加密算法, 包括:- AES
- AES/ECB/NoPadding
- AES/ECB/PKCS5Padding
- AES/CBC/NoPadding
- AES/CBC/PKCS5Padding
- AES/CFB/NoPadding
- AES/CFB/PKCS5Padding
- AES/CTR/NoPadding
- AES/CTR/PKCS5Padding
- AES/OFB/PKCS5Padding
- AES/OFB/PKCS5Padding
- RSA/ECB/PKCS1Padding
- RSA/ECB/NoPadding
- ... 具体可参阅 javax.crypto.Cipher
options{ Object } 加密选项
输入和输出的类型和格式#
国际化 (Internationalization)#
此章节待补充或完善...
Marked by SuperMonster003 on Oct 22, 2022.
E4X#
注: E4X 已弃用.
尽管少数浏览器依然支持, 但随着件更新正逐步被废除, 应尽量避免使用.
AutoJs6 使用 Rhino 引擎, 因此依然保持对 E4X 的支持.本章节仅用于技术概念的归档及溯源, 不建议用于脚本编写.
ECMAScript for XML (E4X) 是对 ECMAScript 的扩展, 增加对 XML 的内在支持.
其目标是在访问 XML 文档时, 提供一种更直观且语法更简洁的的 DOM 接口, 成为处理 XML 文档的新方式.
var sales = <sales vendor="John">
<item type="peas" price="4" quantity="6"/>
<item type="carrot" price="3" quantity="10"/>
<item type="chips" price="5" quantity="3"/>
</sales>;
alert( sales.item.(@type == "carrot").@quantity );
alert( sales.@vendor );
for each( var price in sales..@price ) {
alert( price );
}
delete sales.item[0];
sales.item += <item type="oranges" price="4"/>;
sales.item.(@type == "oranges").@quantity = 4;
参阅: Wikipedia (英) / Wikipedia (中)
替代: DOMParser / DOMSerializer