脚本Api

Posted by Vove on September 25, 2018

脚本Api

App内提供接口的介绍和演示,和它们之间的一些区别 部分lua与js代码相同,会直接写在一起

文章不免有疏漏,欢迎在Issues中指出

阅前须知

  1. 脚本中使用了需要无障碍的函数需要在脚本中声明require 'accessibility' [lua|js均]
  2. 可在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?

脚本参数

命令参数

播放断桥残雪 ——播放@{song}解析—–> 得到argMap = {song:"断桥残雪"}

graph LR A[播放断桥残雪] --> |'播放'解析| B[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扫一扫"(戳我加群)