一、介绍:
1.Auto.js是一款安卓应用,针对安卓7.0以上机型,它可以无需root执行脚本。主要是运用系统自带的“无障碍服务”来获取页面的,这是个亮点,但有个缺陷就是每次关闭 Auto.js 这个app后都要重新开启“无障碍服务”,颇为繁琐。
2.Auto.js可以打包成apk直接装到手机
3.Auto.js可以查看页面布局,需要打开悬浮窗权限
二、简单案例:
1.快手刷金币
//判断当前页面是否有指定text if (text("发现").exists() || text("同城").exists()){ log('在设置页面—记录log')//可在手机的log中打印 sleep(500); swipe(500,1800,500,300,200);//上滑屏幕 } else{ toast('不在刷视频页面_刷不到金币'); }
2.华为辅助安装处理
//app.launchApp("设置");//打开应用 auto(); var i=0 if(text("继续安装").exists()){ log('111111111111111') sleep(2000) click(760,1650);//坐标点击 sleep(6000) if (text("去华为应用市场查找").exists()){ sleep(2000) click(530,1567);//坐标点击 sleep(4000) } if(text("安装成功").exists()){ toast('安装成功'); click(788,1730);//坐标点击 } } else{ log('没有应用安装弹框'); }
3.oppo手机安装处理
if(text("继续安装").exists()){ log('111111111111111'); setText("123456"); textContains("确定").find().click(); sleep(5000); if (text("安装").exists()){ sleep(2000) textContains("安装").find().click(); sleep(4000) textContains("完成").find().click(); } } else{ console.error('没有应用安装弹框_安装出错'); }
4.app应用名和包名
// 使用 应用名称,获取应用的包名. var PackageName; //声明变量 PackageName=getPackageName("QQ"); log(PackageName); //使用 包名,获取 应用名称. var AppName; AppName = getAppName("com.tencent.mobileqq"); log(AppName);
5.设备截图
////______________________设备截图_______________________________________________ ////设置无障碍模式 fast为启用缓存 auto(); ////方式一 test_img(); function test_img(){ // 1、开启线程(因为线程是异步的)自动点击 立即开始,并且触发事件(只需要执行一次就可以) threads.start(function () { var beginBtn; if (beginBtn = classNameContains("Button").textContains("立即开始").findOne(2000)) { beginBtn.click(); } }); // 2、请求截图权限(弹框出现,可以省略第一步但需要手动点击“立即开始”) if(!requestScreenCapture()){ toast("请求截图失败"); exit(); } //3、进行截图 sleep(1700);//等待一会保证弹框关闭了 captureScreen("/sdcard/img.png"); } ////方式二 //1.请求截图权限 if(!requestScreenCapture()){ toast("请求截图失败"); exit(); } //2、进行截图 captureScreen("/sdcard/img.png"); ////方式三: requestScreenCapture(false);//请求截图 var im = captureScreen();//截图 var path = "/sdcard/screenshot.png"; //保存图片 im.saveTo(path); toast("保存图片");//tosat提示 //把图片加入相册中 app.sendBroadcast( new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, android.net.Uri.fromFile(new java.io.File(path))) );
//方式一可以全部自动截图,, 方式二需要先记住勾选,如果autojs清除缓存了就需要重新勾选了,,方式三全自动截图切复制到相册中
6.获取设备信息&设备操作
////______________________设备获取&设备操作_______________________________________________ ////设置无障碍模式 fast为启用缓存 auto(); a = device.height; //高度 b = device.width; //宽度 console.log('设备分辨率:'+b+'*'+a); brand = device.brand; //品牌厂商 console.log(brand); model = device.model; // 设备型号 console.log(model); product = device.product; // 手机型号名称 console.log(product); //硬件序列号 serial = device.serial; // c3ba6d87a0d71433 console.log(serial); //安卓系统API版本 sdkint = device.sdkInt; //API版本:25 console.log('API'+sdkint); //系统版本号 release = device.release; //7.1.2 console.log(release); //安卓id getandroidid = device.getAndroidId(); //71433c3ba6d87a0d console.log(getandroidid); //MAC地址 需要联网才能获取 getmacaddress = device.getMacAddress(); //B0:FC:36:12:C9:EF console.log(getmacaddress); //获取媒体音量 getmusicvolume = device.getMusicVolume(); console.log('音量'+getmusicvolume); //音量:大小 //获取电量百分比 getbattery = device.getBattery(); //87 console.log(getbattery); //确认设备是否在充电 ischarging = device.isCharging(); console.log(ischarging); //flase 没有在充电 //获取设备运行内存容量(占用的内存) gettotalmem = device.getTotalMem(); console.log(gettotalmem); //3186032640 单位(字节),可以自己转换 //获取设备当前可用内存 getavailmem = device.getAvailMem(); console.log(getavailmem); //2386280448(字节),可以自己转换 //查看屏幕是否亮着 isscreenon = device.isScreenOn(); console.log(isscreenon); //true //唤醒设备 (如果息屏可以点亮屏幕,亮屏就依然亮屏) device.wakeUp(); //保持点亮屏幕(设置时间) device.keepScreenOn(30000); //不加参数常亮, 手机亮屏时间以device.keepScreenOn为准,之前系统设置的时间作废 //保持屏幕常亮 可调节省电模式 device.keepScreenDim(timeout); //取消设备保持唤醒状态 用来取消屏幕的唤醒状态 device.cancelKeepingAwake(); ////使设备震动一段时间 device.vibrate(300); //单位毫秒 //取消震动 device.cancelVibration();
7.模拟按键
////______________________按键模拟_物理按键的全局函数_______________________________________________ ////设置无障碍模式 fast为启用缓存 auto(); //以上函数都可以放在toast()或log()里, 例如:toast(notifications()); back();//返回,返回是否执行成功 home();//回到桌面,返回是否执行成功 powerDialog();//弹出电源键菜单。返回是否执行成功 notifications();//拉出通知栏。返回是否执行成功 quickSettings()//下拉通知栏到底。返回是否执行成功 recents();//显示最近任务。返回是否执行成功
8.多线程
////__________________________________多线程_____________________________________ //定义子线程 var thread = threads.start(function(){ while(true){ sleep(200); log("子线程"); } }); //这里是主线程 sleep(2000); log('准备停止主线程了') if (20>10){ sleep(1000); //停止线程执行 thread.interrupt(); } ////_________________________子线程主动退出____________________________________________ var thread = threads.start(function(){ var i=0 while(i<10){ sleep(200); log("子线程"); if (i>5){ log("子线程i>5"); threads.shutDownAll() } i=i+1 } }); //这里是主线程 sleep(2000); log('准备停止主线程了') if (20>10){ sleep(1000); log('主线程.....') } log('主线程...end') ////______________________________堵塞主线程、等待子线程完成____________________________________ var sum = 0; //启动子线程计算1加到10000 var thread = threads.start(function(){ log('子线程开始') for(var i = 0; i < 10000; i++){ sum += i; } }); log('主线程开始') //等待子线程完成(堵塞) thread.join(); toast("sum = " + sum);
三、语法案例
1.通过函数模式操作
//____________________________通过函数打开url&搜索&断言__________________________________________ home();//回到桌面 sleep(2000);//等待2秒 auto(); test_url();//函数声明 function test_url(){ var url="https://www.baidu.com/"; app.openUrl(url);//打开网页 sleep(5000); if(text("百度一下").exists()){ log("已在百度首页"); id("su").find();//定位到搜索框 sleep(1000); setText("城南花已开");//输入文字 sleep(1000); desc("百度一下").click(); sleep(4000); //匹配当前页面是否存在“城南花已开 - 百度百科,,可借助auto.js的布局范围分析查看控件” if((className("android.widget.Button").desc("城南花已开 - 百度百科")).exists()){ toastLog('true-已匹配到相关内容') } else{ toastLog('false-未匹配到相关内容') } } } //_____________________通过函数判断是否包含"备忘录"或蓝牙_________________________ main();//声明主函数 function chen_test(){ //判断当前页面是否有备忘录或蓝牙 if (text("备忘录").exists() || text("蓝牙").exists()) { toast("找到相关内容"); //toast提示 log('在auto.js的日志中打印信息')//可在手机的log中打印 sleep(4000);//等待时间 toast('欢迎进入-设置页面');//toast提示 } else { toast("当前没有找到_任何相关内容"); //悬浮框,toast提示 } } //定义主函数main,需要在顶部先声明不然调用不生效 function main(){ chen_test();//调用函数 exit();//退出,可写或不写 }
2.监听toast&包名&网络请求&文件上传
////__________________________监听toast和包名(可监听手机一切toast、通知等信息很强大)___________________________________________
auto(); events.observeToast(); events.onToast(function(toast){ // log(toast.texts) log("Toast内容:" + toast.getText() +'\n'+"包名:" + toast.getPackageName()) }); ////_________________________通过包名、应用名启动应用_____________________________________ ////如果对应的应用不存在,则返回false; 否则返回true var packageName="com.tencent.mobileqq"; var appname="备忘录"; ////通过包名判断 if(app.launch(packageName)){ sleep(2000); log('找到包名:'+packageName); } ////通过应用名判断 else if (app.launchApp(appname)) { sleep(2000); log('找到应用名:'+appname) } else{ log('没有找到应用') } ////_________________________通过应用名获取包名—————————————————————————————————————————— var name_pa = getPackageName("备忘录"); //获取应用对应的包名 log(name_pa) ////__________________________打开一个网址 并判断是否成功__________________________________ home();//回到桌面 sleep(2000);//等待2秒 auto(); test_url();//函数声明 function test_url(){ var url="https://www.baidu.com/"; app.openUrl(url);//打开网页 sleep(3000); if(text("百度一下").exists()){ log("断言成功") } } ////___________________请求GET__________________________________________________________ var url="http://192.168.10.32:8000/subcontract" var res = http.get(url); //判断状态码 if(res.statusCode >= 200 && res.statusCode < 300){ toast("页面获取成功!"); }else if(res.statusCode == 404){ toast("页面没找到哦..."); }else{ toast("错误: " + res.statusCode + " " + res.statusMessage); } log('获取头信息:\n',res.headers); // log('获取响应的内容:\n',res.body.string());//以字符串形式返回响应内容 // log('获取响应的内容:\n',res.body.json());//以json形式返回响应内容 // log('获取响应的内容:\n',res.body.bytes());//以字节数组形式返回响应内容 log('当前请求地址及方式\n',res.request) log('当前请求url\n',res.url) log('当前请求的方法\n',res.method) ////带headers的get请求 var url = "http://192.168.10.32:8000/subcontract"; var res = http.get(url,{ 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' } }); if(res.statusCode >= 200 && res.statusCode < 300){ toast("页面获取成功!"); }else if(res.statusCode == 404){ toast("页面没找到哦..."); }else{ toast("错误: " + res.statusCode + " " + res.statusMessage); } ////获取返回信息 var html = res.body.string(); log(html) ////_____________________请求post________________________________________________________ ////post请求方式一: var url = "http://192.168.10.32:8000/subcontract"; var res = http.post(url,{ "game_id":"200003306", "name":"dalan_test" }); //获取返回信息 var html = res.body.string(); log(html) //通过状态码判断 if(res.statusCode >= 200 && res.statusCode < 300){ toast("页面获取成功!"); }else if(res.statusCode == 404){ toast("页面没找到哦..."); }else{ toast("错误: " + res.statusCode + " " + res.statusMessage); } //通过字符串匹配来判断(&&表示且,||表示或) if(html.match('status') && html.match('POST')){ log('已经包含') } else{ log('没有包含') } ////post请求二: //例如接口响应为:{ code: 200, method: 'POST', msg: '渠道包上传成功!', status: true } let url = "http://192.168.10.32:8000/subcontract"; let res = http.post(url, { "service": "App.Zllgcimei.Imei", "game_id": "200003306" }); let appName;//声明变量 let html = res.body.string(); //取页面html源码 log(html) //JSON.parse() 将数据转换为 JavaScript 对象。 let json = JSON.parse(html); //log(json) if (json.code == "200") { log("符合条件") appName = json.msg } else { log("请求失败!") } log(appName) //postJson方式(相当于post的json请求) let url = "http://192.168.10.32:8000/subcontract"; r = http.postJson(url, { "service": "App.Zllgcimei.Imei", "game_id": "200003306" }); let text=r.body.string();//获取响应 //同时弹起toast和记录日志 toastLog(text); ////____________________文件上传__________________________________________________ var url="http://106.55.29.87:8000/upload" var res = http.postMultipart(url, { file: open("/sdcard/test/chen.jpg") }); let html=res.body.string();//打印原始数据 let json = JSON.parse(html);//将数据转换为 JavaScript 对象。 log(json) if (json.msg == "success") { log('上传文件成功') }
四、常用控件汇总
launchApp('名字'); //通过app名字启动app应用 launch(‘app包名’); //通过包名启动app应用 app.uninstall('包名'); //卸载app sleep(random(1000,5000)); //随机等待1到5秒 swipe(x1,y1,x2,y2,time); //滑动屏幕(time表示滑动的时间) click(x,y); //单点击坐标,, click("加好友"); //点击"加好友"按钮 press(x,y,time); //按住坐标,time表示时间好像是毫秒 home(); //回到桌面 back(); //返回上一步 getpackagename('应用名'); //通过应用名获取app包名 toast("hallo word"); //在手机toast提示 toastLog('hallo word'); //提示信息+log记录 log('hallo word'); //记录log text("属性值").findOne().parent().click(); //parent通过子控件查找父控件,常用于子控件不能点击,而通过子控件查找到父控件完成点击 text("属性值").findOne().childCount(); //获取控件中子控件的数量 text("进入游戏").find().click(); //点击进入游戏(先查找再点击) text("进入游戏").findOne(3000).click(); //点击进入游戏___查询超时就报错,,(text()是完全匹配) textContains("手机").find().click(); //匹配页面包含手机的元素 textStartsWith("手机").find().click(); //匹配以"手机"开头的元素 textEndsWith("手机").find().click(); //匹配以"手机"结尾的元素 text("xxxx").find(); //按控件文本查找,, 也可使用findOne() desc("xxxx").find(); //按描述信息查找 id("xxxx").find(); //按元素id查找元素 className("xxxx").find(); //按元素类型查找 atextMatches("\\d+"); //以正则匹配 setText("城南花已开") ; //在光标处输入数据 alert("标题","内容"); //对话框输出
五、疑问解答
1.在脚本前面加auto();、auto、auto.waitFor()有什么作用?
auto()
函数来确保无障碍服务已经启用。如果运行到某个需要权限的语句无障碍服务并没启动,则会抛出异常并跳转到无障碍服务界面.
相关连接:
https://blog.csdn.net/QiHsMing/article/details/86762007 .........................VS Code运行AutoJS(包含电脑端调试到手机,,页面布局)
https://pro.autojs.org/docs/#/zh-cn/ ..........................................................autojs官方教程
https://gitee.com/jianyue/autojsDemo?skip_mobile=true .........................gitee的autojs案例
https://blog.csdn.net/zy0412326/article/details/117155945 ..................autojs打包成apk