Auto.js is a UiAutomator on android, does not need root access(安卓平台上的JavaScript自动化工具)
写游戏脚本,不像一般的APP可以直接操作控件,而只能通过基于坐标的操作完成。所以Autojs里关于控件的部分可以略过不看(除了多账号登录时的登录界面可能会用到一点控件操作,其他基本用不到),大致的学习流程:
-
软件安装及环境搭建(版本选择、运行测试)
-
JavaScript
基础语法学习(变量类型、流程操作…) -
Auto.js
分模块学习,如系统交互(文件读写、设备信息、打开应用…)、找图找色(游戏脚本的核心)、UI界面、多线程…
toast() //输出到手机屏幕
log() //输出到日志
toastLog() //前两者之和
console.log() //输出到控制台,console模块的一个成员函数,可以通过console.show()在手机上显示
或者过一遍,这里只列举一些我觉得要注意的地方。
-
直观感受,很多语法和C\C++一模一样(除了声明变量要用
var
、函数要加function
…)。 -
undefined
:只声明过但未赋值的变量。 -
==
与===
: 前者是equality
、后者为identity
,即后者不会进行类型转换,类型不同的结果一定不等。 -
JS的数据类型:
var length = 7; // 数字 var lastName = "Gates"; // 字符串 var cars = ["Porsche", "Volvo", "BMW"]; // 数组 var x = {firstName:"Bill", lastName:"Gates"}; // 对象
null
null === undefined // false null == undefined // true
- 对象: 通过关键词 “new” 来声明 JavaScript 变量,则该变量会被创建为对象。
//也可以通过person.firstName="..."的方式初始化 var person = { firstName: "Bill", lastName : "Gates", id : 678, fullName : function() { //成员函数 return this.firstName + " " + this.lastName; } };
- 在字符串中换行,需要加一个反斜杠(非ECMAScript标准):
document.getElementById("demo").innerHTML = "Hello \ Kitty!";
-
和
Number
相加时,会将数字转为字符串;String
和Number
相减时,会将字符串转为数字; -
数组添加元素:
array.push("value")
-
常用对象: Date() (获取时间)、 Math() (常用数学工具)
-
use strict;
: 定义 JavaScript 代码应该以“严格模式”执行。 -
JavaScript的对象通过
引用
//person是个对象 var x = person; // 这不会创建 person 的副本,x相当于person的别名,即引用
官方文档地址:https://hyb1996.github.io/AutoJs-Docs/#/
官方文档已失效,本站已完美修复AutojsPro文档:
- 启动应用,有两种方式:
-
app.launchApp(appName)
,通过应用名称启动,即图标下显示的名称; -
app.launch(packageName)
,通过包名启动,关于如何获取应用的包名后面会讲到,举个栗子:app.launch("com.bilibili.priconne")
;
-
- 获取包名: ,与此相对的还有根据包名获取应用名,举个栗子:
appName = app.getPackageName("微信") toastLog(appName) //输出:com.tencent.mm
- 读写系统剪切板
setClip("将剪切板设置为这段话") //getClip()返回剪切板内容 toastLog("当前剪切板:"+getClip())
- 停止脚本:
exit()
- 设置脚本需要的安卓版本号
requiresApi(24)// 需要至少Android 7.0 requiresAutojsVersion("3.0.0")//指定Autojs最低版本号 //会自动检测当前版本号,若过低会报错
- 获取屏幕分辨率
var Width=device.width; var Height=device.height; toastLog(Width+"x"+Height);
- 获取设备识别码。Autojs里常用的设备标识是
IMEI
和ANDROID_ID
。IMEI
(International Mobile Equipment Identity)是15位数字组成的国际移动设备身份码,写在主板上和硬件绑定,就算刷机也没法改变。AndroidId
当脚本要商业化的时候,可以通过设备码区分不同用户;如果脚本写出来只是一个人用,获取设备码应该也没啥用。var deviceId=device.getIMEI(); // 注意在Android10及后续版本失效 var androidId=device.getAndroidId(); toastLog(deviceId+"\n"+ androidId);
- Device模块有很多功能,比如调整音量、屏幕亮度、获取内存和电量…但感觉写游戏脚本都用不到所以直接跳过吧。
var path1=files.cwd(); //当前工作文件夹绝对路径 var path2=files.path("."); //相对路径转绝对路径 //还有一些不太常用的如files.getSdcardPath()、files.listDir(path[, filter])
var path="/sdcard/newFolder/" if(!files.create(path)){} //创建文件或文件夹,若已存在则返回false,(需要上一级文件夹已存在) files.createWithDirs("/sdcard/newFolder1/newFolder2"); //若不存在会创建一系列文件夹,比上一个命令更强大 //还有些如删除文件、判断空文件夹等功能、略过。
var path = "/sdcard/1.txt"; var text = "Hello, AutoJs"; //以写入模式打开文件 var file = open(path, "w"); //open函数还可以指定文件编码 // "r":读, "w":写 , "a":从文件末尾附加 file.write(text); //还可以:file.writeline()、file.writelines() // var text=file.read() ,或者file.readlines() file.close();
//shell函数,返回result对象;result.code返回码,成功为0;result.result,运行结果(字符串);result.error,无错误时为空,若未获取到root权限可能返回"Permission denied"。
var result=shell("ls",true);
if(result.code==0){toast("执行成功");}
//shell对象
var sh=new Shell(true); //构造函数
sh.exec("ls"); //执行命令,注意该函数没有返回值!! 并且命令执行是"异步"的,不会等待上一步执行完成。
sh.exit(); //强制退出
sh.exitAndWaitFor(); //等待执行完成并退出
# 感觉对写脚本没太大帮助... am start ... am kill ... am force-stop ... am restart ...
pm list packages #列出所有APP包,这个命令感觉有点用 pm install ... pm uninstall ...
wm size #查看屏幕尺寸 wm size 720x1280 # 修改尺寸 wm size reset #还原
-
sleep(n)
-
随机数:
random(min,max)
指定区间、random()
范围是[0,1);点击坐标时常设置一个随机偏移,防止被检测到(每次都点同一个点还是太明显了) -
分辨率适配问题,
setScreenMetrics(1080, 1920);
、表示脚本适合的屏幕宽高为1080×1920(编脚本时基于的设备),如果在别的分辨率手机上运行则会自动放缩光标。听上去很好的一个功能,一般游戏脚本必加这一行,但具体效果如何我没有测试过。 -
click(x,y)
:点击坐标(无需root权限),返回是否成功,点击过程大约150ms,可能被其他事件中断。更长时间的点击如longClick(x,y)
、持续600ms。 -
press(x,y,duartion)
:按住坐标,一般超过500ms才被系统认为是长按。 -
swipe(x1,y1,x2,y2,duration)
: 从(x1,y1)滑动到(x2,y2),持续duration。 -
RootAutomator
上面的几个触摸操作都是免root的,而基于RootAutomator对象的触摸需要root权限,优点是执行没有延迟,明显比click要快。var ra=new RootAutomator(); //初始化一个对象 ra.tap(x,y,id); //id代表不同“手指”,用于多点触摸,不需要时可省略该参数 ra.swipe(x1,y1,x2,y2,duration,id) ra.press(x,y,duration,id) // 这些命令组合在一起就能完成复杂的操作了~ ra.touchDown(x,y,id) ra.touchMove(x,y,id) ra.touchUp(id)
- 模拟按键;(返回bool值)
if(back()){}; //按下返回键 home() //返回桌面 还有一些需要root权限的,开头字母大写: //Home()、Back()、Power()、Menu()、OK()、KeyCode()...
4.2.2 colors、images
颜色常用十六进制值或RGB值来表示,如蓝色可表示为#0000FF
或(0,0,255)
,一般都是#
后面带6位十六进制数,分别表示R、G、B,但Autojs是8位,前面多了一个A(Alpha)
- Autojs通过一个16进制整数或一个字符串表示一个颜色,两者可以互相转换
var myBlue=colors.toString(color.BLUE); //返回#ff0000ff,colors.BLUE代表蓝色,后面必须大写。 var numBlue=colors.parseColor("#ff0000ff"); //返回-16776961,至于为什么是这个数我也不清楚,平时还是用字符串表示比较好。
-
colors对象里还有一些判断两个颜色的相似度、返回A、R、G、B通道值的函数,平时也基本上用不上;颜色的用途主要体现在后面的多点找色上。
var img=images.read("./name.png"); //读取图片,错误时返回null //var img=images.load(url); //从网址获取图片 //...图片操作后回收 img.recycle(); // 例外:captureScreen()返回的图片无需回收
if(!requestScreenCapture()){ //可指定参数true(横屏截图) 或者 false(竖屏截图) toast("请求截图失败"); exit(); }
//在此之前记住要请求一次截图权限 var img=captureScreen(); //可以指定保存路径path
//获取某点的ARGB颜色值 var color=images.pixel(img,100,200); //img是之前创建的images对象
//首先说下region和threshold这两个参数,后面的找色函数options里都要用到: //region、找色区域,默认全图、指定[x,y]代表左上角点,从(x,y)到右下角;指定[x,y,width,height]则代表从(x,y)到(x+width,y+height)。 //threshold、相似度临界值,0~255,默认为4;similarity=1-threshold/255,可以算出默认相似度达到了0.98,觉得太严了可以适当增大threshold var point = images.findColor(img, "#ff0000", { region: [100, 200], threshold: 10 }); //如果找到则返回一个点,如:{463.0, 1242.0};找不到返回null。 //这里颜色值是6位,8位也行不过会忽略A通道(透明度)。 // findColorInRegion,功能和findColor一样,只是优化了下参数表示。 var point=images.findColorInRegion(img,"#ff0000",100,200,1080,1920,10); // findColorEquals,要求颜色完全相等,相当于findColor的threshold参数设为0 var point=images.findColorEquals(img,"#ff0000",100,200,1080,1920);
var point = images.findMultiColors(img, "#ff949fc7", //第一个点 [[60, 60, "#ffe6efe6"], //颜色Array, [60, -60, "#ffeef3e6"], [-60, 60, "#ffe6efe6"], [-60, -60, "#ffeef3e6"]], { region: [1548, 803, 140, 140] }) //指定区域
if(images.detectsColor(img,"#fed9a8",100,200,16,"diff")){} //最后两个参数可省略,代表threshold和匹配算法;x=100,y=200
var temp1=images.read(pathToImage); var point=images.findImage(img,temp1,{ region: [100, 200], threshold: 10 }); //同样findImageInRegion只是优化了下参数排列 //matchTemplate可以同时返回找到的多个位置,通过max控制最大的结果数量 var result=images.matchTemplate(img,temp1,{ region: [100, 200], threshold: 10 ,max:5}); //返回类型是一个MatchingResult对象,有point和similarity这两个数据成员。
//启动一个无限循环的线程 var thread = threads.start(function(){ //用thread对象可以控制线程运行状态,如果不需要操作可以改为: //threads.start(function(){ while(true){ log("子线程运行中..."); sleep(1000); } }); sleep(5000); thread.interrupt();
-
threads.shutDownAll()
: 停止所有通过threads.start()
启动的子线程 -
等待线程开始执行(一般start后需要一段时间):
thread.waitFor();
- 等待线程执行完成:
thread.join();
,参数可以指定一个等待时间 - 中断线程运行:
thread.interrupt();
注意多线程中的变量问题,涉及到线程安全,文档里说的很详细
- 线程间的通信与传递变量,通过
var connect = threads.disposable();
实现;发送结果:connect.setAndNotify(s);
,接收结果:connect.blockedGet(s);
Events模块主要用来监听按键、触摸、通知等,但放在单线程里可能会因为程序其他部分而无法及时执行,造成非预期的结果,常常和多线程`Threads`模块一起使用,如音量键关闭脚本的例子:
auto();
threads.start(function(){ //在子线程中调用observeKey()从而使按键事件处理在子线程执行
events.observeKey(); //启用按键监听
events.on("key_down", function(keyCode, events){
//常用事件有key、key_down、key_up、exit、toast、notification、touch(触摸某点)
if(keyCode == keys.volume_up){ //音量上键关闭脚本
exit();
}
});
});
events.on("exit", function(){ //脚本停止运行时会触发exit事件
toast("脚本已结束");
});
while(true){
log("脚本运行中...");
sleep(2000);
}
Dialogs 这部分提供对话框支持,但由于是弹出一个全屏的消息提示框,实际体验是并不太能用上;如果脚本和用户的交互性比较强的话可以考虑一下。
Console console
的UI是固定的,也可以悬浮、最小化;有时不想设计UI的时候可以偷懒直接拿console
过来凑合用用。
sleep(time)
如何决定,这个要不断地尝试改良,没别的;二是图片识别,有时候换个电脑换个模拟器脚本就没法识图了,这时往往要考虑:
-
是不是图片选取不恰当,太小或者太大或者特征不明显
-
识图函数准确度参数是不是设置的太高或太低了
-
- 最新
- 最热
只看作者