脚本Api
App内提供接口的介绍和演示,和它们之间的一些区别 部分lua与js代码相同,会直接写在一起
文章不免有疏漏,欢迎在Issues中指出
阅前须知
- 脚本中使用了需要无障碍的函数需要在脚本中声明
require 'accessibility'
[lua|js均] - 可在App高级/脚本测试中使用
更新日志
-
1.3.4
system.simCount
system.contacts
system.saveMarkedContact
system.saveMarkedApp
system.call(phone,simId)
-
1.2.9
- 添加标志
runtime.userInterrupt
- 添加标志
-
1.2.8
system.sendSMS(phone: String, content: String)
system.getLaunchIntent(pkg:String)
system.getPhoneByName(name: String)
runtime.focusView
ViewNode.appendText()
ViewNode.globalClick()
ViewFinder.containsDesc(...)
-
1.1.8
system.screenOn
system.screenOff
system.sendKey
-
1.1.7
- androRuntime(终端/Root命令相关)
- parseDateText (解析日期文本 ;Fx其他页)
-
2018-10-11
- 添加system api
screen2File(): File?
- 添加system api
screenShot(): Bitmap?
- 添加system api
脚本参数
命令参数
播放断桥残雪
——播放@{song}
解析—–> 得到argMap = {song:"断桥残雪"}
脚本中获取命令参数:
- Lua
1
local song = argMap['song']
- Js
1
var song = argMap['song']
全局变量
脚本中可以直接使用的变量
运行时参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 需无障碍权限
print('当前App',runtime.currentApp)
print('当前App包名',runtime.currentApp.packageName)
print('当前Activity',runtime.currentActivity)--也可能是Dialg
print('执行队列数量',runtime.actionCount)
print('当前动作在队列中的索引',runtime.currentActionIndex)
print('是否为全局操作',runtime.isGlobal())
print('命令类型',runtime.commandType) -- 打开 1 关闭 -1 默认0
print('语音命令',runtime.command) -- 命令文本
print('是否为调试模式',runtime.DEBUG)
print('当前获得焦点的ViewNode',runtime.focusView)
print('用户中断标志',runtime.userInterrupted)
执行器函数
大部分函数已设为全局,可直接调用,调用失败可尝试
executor.xxx()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//等待用户说话,并返回识别结果,识别失败返回空
waitForVoiceParam():String?
//语音合成(同步) 参数:待合成text文本 返回是否成功
speakSync(text):Boolean
//语音合成(异步)无返回值
speak(text)
//终止执行
interrupt()
//检查无障碍 返回无障碍是否开启
checkService():Boolean
//显示对话框,返回是否继续
alert(title, message):Boolean
//显示单选对话框,返回选择文本,若取消返回空
singleChoiceDialog(title, items):String?
//等待应用出现
//参数 pkg: 应用包名, activity(可选) Activity名:如'MainActivity',
//millis(可选)等待时长,不指定则无限等待
//返回:等待结果,true等待到,false:超时
waitForApp(pkg[,activity[,millis]]):Boolean//
调用Java类和函数
Java作为”宿主”语言,在Lua和Js中均可以使用开放的Java类和函数
引入类名:
- Lua
1
import 'xxx.xxx.xxx.xx'
- Js
1 2
importClass(Packages.xxx.xxx.xxx.xx) //引入类 importPackage(Packages.xxx.xxx.xxx) //引入包
1 2 3 4 5 6 7
import 'android.content.Intent' -- 已自动引入可不加 import 'android.net.Uri' -- 已自动引入可不加 i = Intent(Intent.ACTION_VIEW) i.setData(Uri.parse('tel:10086')) i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) print(i) app.startActivity(i)
视图节点(ViewNode)
为视图节点,可进行一系列操作:点击,文本框设置文字,滑动
视图节点类:ViewNode
如何获取ViewNode
=> 全局操作 视图节点查找器
提示:类似node.getAbc()
的函数可以直接通过node.abc
调用
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 尝试点击
* 当此节点点击失败,会尝试向上级容器尝试
* @return Boolean 是否成功
*/
fun tryClick(): Boolean
/**
* 使用全局函数click进行点击操作,如点击网页控件
* 需要7.0+
* @return Boolean
*/
fun globalClick(): Boolean
1
2
3
4
5
6
/**
* 点击此Node
* 失败率较高,使用起来不方便
* @return Boolean
*/
fun click(): Boolean
1
2
3
4
5
6
7
8
9
10
/**
* 以此Node中心滑动到dx,dy的地方
* 需要Android 7.0+
* setScreenSize() 对此有效
* @param dx Int x方向 移动距离 ±
* @param dy Int y ±
* @param delay Int 用时
* @return Boolean
*/
fun swipe(dx: Int, dy: Int, delay: Int) :Boolean
1
2
3
4
5
/**
* 尝试长按,机制类似tryClick
* @return Boolean
*/
fun tryLongClick(): Boolean
1
2
3
4
5
/**
* 长按操作
* @return Boolean
*/
fun longClick(): Boolean
1
2
3
4
5
6
/**
* 双击操作
* 默认使用tryClick
* @return Boolean
*/
fun doubleClick(): Boolean
1
2
3
4
5
6
/**
* 设置文本,一般只能用于可编辑控件
* @param text String
* @return Boolean
*/
fun setText(text: String): Boolean
1
2
3
4
5
6
/**
* 尝试设置文本内容,机制同tryClick
* @param text String
* @return Boolean 是否成功
*/
fun trySetText(text: String): Boolean
1
2
3
4
5
6
7
/**
* 追加文本
* 适用于纯文本输入框
* @param s String
* @return Boolean
*/
fun appendText(s: String): Boolean
1
2
3
4
5
6
7
/**
* 获取下级所有Node
* @return Array<ViewNode>
* 示例 : s=ViewFinder()....findFirst()
* s.childs[0] //获取s第一个子Node
*/
fun getChilds(): Array<ViewNode>?
1
2
3
4
5
/**
* 获取父级Node
* @return ViewNode?
*/
fun getParent(): ViewNode?
1
2
3
4
5
/**
* 获取边界范围
* @return Rect
*/
fun getBounds(): Rect?
1
2
3
4
5
6
/**
* 获取中心点坐标(相对于本机屏幕)
* @return Point?
*/
fun getCenterPoint(): Point?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 获取Node包含文本
* @return String?
*/
fun getText(): String?
//选择
fun select(): Boolean
fun trySelect(): Boolean
//获得焦点
fun focus(): Boolean
/***以下不常用,并且失败率高,不建议使用***/
fun scrollUp(): Boolean
fun scrollDown(): Boolean
fun scrollForward(): Boolean
fun scrollBackward(): Boolean
fun scrollLeft(): Boolean
fun scrollRight(): Boolean
视图节点查找器(ViewFinder)
对屏幕内容检索,根据条件找出满足的ViewNode
使用示例:基本结构ViewFinder().[..构造..].[find()|findFirst()|waitFor()...]..操作
1
2
3
4
ViewFinder().id('title').equalsText('文本').findFirst() --立即查找
ViewFinder().id('title').waitFor() --等待返回
ViewFinder().id('title').tryClick() --立即查找并点击
ViewFinder().id('title').waitFor(3000).tryClick() --最多等待3s出现后在点击,未找到则返回false
1
ViewFinder().id('title').equalsText('内容').find() --返回所有满足条件列表
所有规则:
1
2
3
4
5
6
7
8
/**
* 正则匹配文字
* 此处正则 与其他地方相同 均以%匹配任意长度字符串
* @param regs 表达式 %消息%
* @return this
*/
ViewFinder matchesText(String... regs)//可多个参数
ViewFinder matchesText(String reg)//单参数
1
2
3
4
5
6
7
/**
* 包含文本 不区分大小写
* @param texts text
* @return this
*/
ViewFinder containsText(String... texts)//可多个参数
ViewFinder containsText(String text)//单参数
1
2
3
4
5
6
7
/**
* 相同文本 不区分大小写
* @param texts text
* @return this
*/
ViewFinder equalsText(String... texts) //可多个参数
ViewFinder equalsText(String text) //单参数
1
2
3
4
5
6
7
8
9
10
11
/**
* 根据文本相似度 > 0.8 匹配 (转为拼音后的比较)
*
* 例如 搜索QQ联系人时,使用首字母搜索,然后使用此方法模糊查找出现的联系人 参考QQ内指令选择聊天人
*
* @param text 文本内容
*
* @return this
*/
ViewFinder similaryText(String... texts)
ViewFinder similaryText(String text)
1
2
3
4
5
6
ViewFinder id(String id) //设置id
ViewFinder desc(String... descs)//设置多个descs
ViewFinder desc(String desc)//一个desc
ViewFinder containsDesc(String desc)//desc包含
ViewFinder containsDesc(String... descs)//设置多个descs
其他属性:
1
2
3
4
ViewFinder editable() //可编辑
ViewFinder scrollable()//可滚动
ViewFinder type(String... types) //指定多个className 不区分大小写
ViewFinder type(String type) //指定一个className 如 'textview'
搜索函数:
1
2
3
4
5
6
ViewNode findFirst() //立即搜索,直到找到第一个
Array<ViewNode> find() //搜索所有符合条件
ViewNode waitFor() //无限等待,直到搜索到,返回ViewNode
ViewNode waitFor(Long m) //等待毫秒
ViewNode await() //同waitFor()
ViewNode await(long l)//同waitFor(millis)
此外ViewFinder
可以直接调用ViewNode
中的函数,省去了findFirst()
的操作
如:ViewFinder().id('title').tryClick()
,一般情况下切勿使用,因为可能视图未出现,导致执行失败
全局操作
仅视图操作需要无障碍
-
waitForId(id [,millis]) :ViewNode?
等待指定视图
id
的出现,millis
等待时长返回:找到的
ViewNode
, 超时或无障碍未打开返回空 -
waitForDesc(desc[,millis]):ViewNode?
等待等待指定视图
descd
的出现,millis
等待时长返回:找到的
ViewNode
, 超时或无障碍未打开返回空 -
waitForText(text[,millis]):ViewNode?
等待文本
包含
text的节点出现,millis
等待时长 -
waitForText(texts [,millis]):ViewNode?
等待文本为texts其中一个的节点出现,
millis
等待时长require 'accessibility' v = waitForText({'主页','2'},5000) -- 等待5s
-
smartOpen(s):Boolean
s可以为应用包名,应用名,打开标记的记录
-
smartClose(s):Boolean
关闭应用、标记的记录
-
sleep(m)
休眠m毫秒
-
·
toast(msg: String)
弹消息框
-
back(): Boolean
执行返回
-
home(): Boolean
执行返回主页
-
powerDialog(): Boolean
显示电源菜单
-
quickSettings(): Boolean
下拉通知栏显示
quickSettings
-
recents(): Boolean
调出最近应用界面
-
notificationBar(): Boolean
显示通知栏
-
setScreenSize(width: Int, height: Int)
设置屏幕尺寸值,其他使用到屏幕坐标的都基于此尺寸,默认为本机屏幕实际尺寸。
-
swipe(x1: Int, y1: Int, x2: Int, y2: Int, dur: Int): Boolean
滑动手势,从
[x1,y1] => [x2,y2]
dur执行使用时间,毫秒 Android7.0+ -
click(x: Int, y: Int): Boolean
点击坐标[x,y]Android7.0+
-
longClick(x: Int, y: Int): Boolean
长按[x,y]Android7.0+
-
gesture(dur: Long, points: Array<Pair<Int, Int>>): Boolean
根据坐标数组执行手势Android7.0+
-
fun scrollDown(): Boolean
下划手势Android7.0+
-
scrollUp(): Boolean
上划手势 Android7.0+
System类函数
一般都作为了全局函数,可以直接
xxx
调用。还可使用system.xxx
调用。不需要无障碍
1
2
3
4
5
6
/**
* 打开应用详情页
* @param pkg String
* @return Boolean
*/
fun openAppDetail(pkg: String): Boolean
1
2
3
4
5
/**
* 通过包名打开App
*/
fun openAppByPkg(pkg: String, resetTask: Boolean = false): ExResult<String>
1
2
3
4
5
6
7
8
9
//快速搜索
fun quickSearch(s: String?)
/**
* 获得App启动的Intent
* @param pkg String
* @return Intent?
*/
fun getLaunchIntent(pkg: String): Intent?
1
2
3
4
5
6
/**
* 通过通过关键字匹配
* @return pkgName if ok
*/
fun openAppByWord(appWord: String): ExResult<String>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 拨打电话
* 输入 纯数字 | [标记]联系人
* 优先级:标记 -> 通讯录 -> 服务提供
*/
fun call(s: String): ExResult<String>
/**
* 拨打电话
* 输入 纯数字 | [标记]联系人
* 优先级:标记 -> 通讯录 -> 服务提供
* @param s String
* @param simId Int? 卡号 0:卡1 1:卡2
* @return Boolean
*/
fun call(s: String, simId: Int?): Boolean
/**
* 根据指定名查找手机
* 优先级:标记 -> 通讯录 -> 服务提供
* @param name String
* @return String?
*/
fun getPhoneByName(name: String): String?
1
2
3
4
5
6
/**
* 发送短信
* @param phone String
* @param content String
*/
fun sendSMS(phone: String, content: String)
1
2
3
4
5
/**
* 手电
*/
fun openFlashlight(): Boolean
fun closeFlashlight(): Boolean
1
2
3
4
/**
* 获取手机信息
*/
fun getDeviceInfo(): DeviceInfo
1
2
3
4
5
/**
* 获取App信息
* @param s 包名 或 App 名
*/
fun getAppInfo(s: String): AppInfo?
1
2
3
4
5
/**
* 打开链接
*/
fun openUrl(url: String)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Media control
fun mediaPause()
//控制媒体播放
fun mediaStart()
fun mediaResume()
fun mediaStop()
fun mediaNext()
fun mediaPre()
fun volumeMute()
fun volumeUnmute()
fun volumeUp()
fun volumeDown()
fun setMusicVolume(index: Int)
fun setAlarmVolume(index: Int)
fun setNotificationVolume(index: Int)
fun isMediaPlaying(): Boolean
1
2
3
4
//最大音量
var musicMaxVolume: Int
//当前音量
var musicCurrentVolume: Int
1
2
3
4
//震动 millis时长
fun vibrate(millis: Long): Boolean
//震动 指定数组震动
fun vibrate(arr: Array<Long>): Boolean
1
2
3
4
//打开蓝牙
fun openBluetooth(): Boolean
//关闭蓝牙
fun closeBluetooth(): Boolean
1
2
3
4
5
6
7
8
9
//打开wifi
fun openWifi(): Boolean
//关闭wifi
fun closeWifi(): Boolean
//打开热点
fun openWifiAp(): Boolean
//关闭热点
fun closeWifiAp(): Boolean
1
2
3
4
//获取剪切板内容
fun getClipText(): String?
//设置剪切板内容
fun setClipText(text: String?)
1
2
3
4
5
//发送邮件
//to : 收件人邮箱
//subject : 标题
//content : 内容
fun sendEmail(to: String, subject: String? = null, content: String? = null)
1
2
3
4
5
6
/**
* 获取用户地理位置,等待时长5s
* 需授权
* @return String? 获取失败返回空
*/
fun location():Location?
1
2
3
4
5
//截屏,返回[Bitmap]()类
fun screenShot(): Bitmap?
//截屏保存至文件,返回File?
fun screen2File(): File?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 插入的sim卡数量
*/
val simCount:Int
/**
* 获得联系人数组 元素:Pair(contactName,phone)
*/
val contacts: Array<Pair<String, String?>>
/**
* 保存到标记联系人
* @param name String 显示名
* @param regex String? 正则
* @param phone String phone
*/
fun saveMarkedContact(name: String, regex: String, phone: String): Boolean
/**
* 保存到标记应用
* @param name String
* @param regex String?
* @param pkg String
*/
fun saveMarkedApp(name: String, regex: String, pkg: String): Boolean
/**
* 电量值 0-100
*/
val batteryLevel: Int
/**
* 充电状态
*/
fun isCharging(): Boolean
1
2
3
4
5
6
7
//屏幕是否亮起
fun isScreenOn(): Boolean
//亮屏
fun screenOn()
//灭屏 需root权限
fun screenOff()
AndroRuntime
1
2
3
4
/**
* 判断机器Android是否已经root,即是否获取root权限
*/
fun isRoot(): Boolean
1
2
3
4
5
6
/**
* 执行无root命令
* @param cmd String 命令
* @return String 结果
*/
fun exec(cmd: String): String
1
2
3
4
5
/**
* 执行root命令
* @return String 结果
*/
fun execWithSu(cmd: String): String? {
运行时存储
示例 [lua]
1
2
3
4
5
6
7
8
9
10
11
12
13
sp = SpHelper('lua_sample')
sp.set('no', 127)
sp.set('name', 'Lua')
sp.set('b', true)
local data = { 'a', 'b', 'c' } -- js: data=['a', 'b', 'c']
set = SetBuilder().addAll(data).build() -- 集合
sp.set('set', set)
--
print(sp.getInt('no'))
print(sp.getString('name')) -- string 可用json存储复杂对象
print(sp.getBoolean('b'))
print(sp.getStringSet('set'))
指令设置存储
在高级手册2中使用config = registerSettings(..)
得到指令设置对象,此对象的函数如下
resetSettings()
重置此条指令设置getInt(key)
获得key对应整数getString(key)
获得key对应字符串getBoolean(key)
获得key对应布尔值set(key,value)
设置值 value类型,只支持int,string,boolean
执行结果回调
notifyFailed(msg)
失败回调
仅仅是显示失败信息,代码中需自行结束执行
其他
文本操作
toPinyin(text [,onlyFirstLetter])
将text文本转换为中文拼音,onlyFirstLetter是否只需要首字母
- Lua同Js
1 2 3
s = '一二三ab' print(toPinyin(s)) -- 输出yiersanab print(toPinyin(s,true)) -- 输出yesab
arr2String(arr)
将数组转为文本
返回转换结果,若arr空返回空- Lua
1 2 3
arr = {1,2.1,3,'abc'} print(arr[1]) -- 1 print(arr2String(arr)) -- 1, 2.1, 3, abc
- Js:
1 2 3
arr = [1,2.1,3,'abc'] print(arr[0]) // 1 print(arr2String(arr)) // 1, 2.1, 3, abc
matches(text,regexStr)
text: 待匹配字符串 regex:正则式字符串 %为特殊
返回boolean 是否匹配成功- Lua同Js:
1 2
print(matches('123456789','%3%6%9')) -- true print(matches('123456789','%3%9%6')) -- false
matchValues(text,regexStr)
text: 待匹配字符串 regex:正则式字符串 %为特殊
返回匹配到的字符串数组- Lua
1 2 3 4 5
arr = matchValues('123456789','%3%6%9') print(arr2String(arr)) -- 12, 45, 78 arr = matchValues('123456789','%3%6%8') -- 匹配不成功 返回空 print(arr) -- nil 空 print(arr2String(arr)) -- nil 匹配失败
- Js
1 2 3 4 5
arr = matchValues('123456789','%3%6%9') print(arr2String(arr)) // 12, 45, 78 arr = matchValues('123456789','%3%6%8') // 匹配不成功 返回空 print(arr) // null print(arr2String(arr)) // null 匹配失败
文本日期解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 解析中文时间
* 例:
* "十二点", "八点四十五", "八点半", "晚上八点", "中午12点", "下午2点一刻",
* "明天中午", "后天下午3点", "大后天中午", "昨天下午2:21", "前天下午两点半",
* "周一下午", "下周二八点半", "周日晚上八点",
* "二十号晚上七点", "21号", "二十八号", "下个月十八号上午8点二十三", "十二月25号",
* "12月8号上午8点", "周二一点", "这周五八点", "周五晚上7点半",
* "一小时后", "一个半小时后", "半小时后", "两个半小时后", "45分钟后", "三十二分钟后",
* "两个小时后", "两小时后", "二十小时后",
* "八天后"
*
* @param s String
* @return Calendar 返回Calendar对象
*/
fun parseDateText(s: String): Calendar
赶快对它说"打开QQ扫一扫"
(戳我加群)