Auto.js (支付寶篇):螞蟻森林自動收取能量和偷取能量
說在前面
對於螞蟻森林,我有一段時間沒有玩,後來被人超了。然後,我又開始偷取,每天定鬧鐘,每天走步數。相信不是土豪,還想成為排行榜的第一。肯定也像我一樣(幼稚),O(∩_∩)O哈哈~
當然,作為一名還沒入門的程式猿,“懶”便讓我想起了如何“偷懶”。
首先宣告,程式碼部分不是本人所寫,通過大量搜尋,只是做了部分改動,增加自己的想法,以及從0入門的更易理解。本文的目的一是分享給大家,二算是記個筆記方便以後看。
前幾天在CSDN看到一篇用android逆向編譯的,完全看不懂。後來想起了 WorkFlow,但是感覺也很無聊。於是想起了用js試一試。
開發環境
手機支援
小米 5S(無需ROOT,但是需要開啟無障礙模式)
Auto.js APP
百度手機助手: http://shouji.baidu.com/software/23334313.html
酷安:https://www.coolapk.com/apk/129872
MIUI 版本
MIUI 9.2 | 穩定版
Android 版本
7.0
解析度
1920 x 1080 畫素
電腦支援
一臺Windows
安裝Auto.js
桌面編輯器Visual Studio Code的外掛。可以讓Visual Studio Code支援Auto.js開發。
在VS Code中選單“檢視” - >“擴充套件” - >輸入“Auto.js”或“hyb1996”搜尋,即可看到“Auto.js-VSCodeExt”外掛,安裝即可。外掛的更新也可以在這裡更新。
如何使用
第1步
按Ctrl+Shift+P
或點選“檢視” - > “命令面板”可調出命令面板,輸入側Auto.js
可以看到幾個命令,移動游標到命令Auto.js: Start Server
,按回車鍵執行該命令。
此時VS Code會在右上角顯示“Auto.js server running”,即開啟服務成功。
第2步
將手機連線到電腦啟用的無線上網或者同一區域網中。通過命令列IPCONFIG(或者其他作業系統的相同功能命令)檢視電腦的IP地址。在Auto.js的側拉選單中啟用除錯服務,並輸入IP地址,等待連線成功。
(md,這個地方的Auto.js是手機上的。找了大半天沒找到ip。官方下載地址:
第3步
之後就可以在電腦上編輯的JavaScript並檔案通過命令Run
或者按鍵F5
在手機上運行了。
命令
按Ctrl+Shift+P
或點選“檢視” - > “命令面板”可調出命令面板,輸入側Auto.js
可以看到幾個命令:
- Start Server:啟動外掛服務。之後在確保手機和電腦在同一區域網的情況下,在Auto.js的側拉選單中使用連線電腦功能連線。
- 停止伺服器:停止外掛服務。
- 執行運行當前編輯器的指令碼。如果有多個裝置連線,則在所有裝置執行。
- Rerun停止當前檔案對應的指令碼並重新執行。如果有多個裝置連線,則在所有裝置重新執行。
- 停止當前檔案對應的指令碼。如果有多個裝置連線,則在所有裝置停止。
- StopAll停止所有正在執行的指令碼。如果有多個裝置連線,則在所有裝置執行所有指令碼。
- 儲存當前檔案到手機的指令碼預設目錄(檔名會加上字首remote)。如果有多個裝置連線,則在所有裝置儲存。
- RunOnDevice:彈出裝置選單並在指定裝置執行指令碼。
- SaveToDevice:彈出裝置選單並在指定裝置儲存指令碼。
以上命令一些有對應的快捷鍵,參照命令後面的說明即可。
日誌
要顯示來自Auto.js的日誌,開啟VS Code上面選單的“幫助” - >“切換開發人員工具” - >“控制檯”即可。
官方文件來源:https://github.com/hyb1996/Auto.js-VSCode-Extension
實現步驟
其實說白了,就是類似於巨集記錄,類似按鍵精靈,其實就是模擬你的操作,讓你放手做其他的事情。
本身外掛也好,輔助也罷,道理都差不多,好了不廢話了,不住簡單如下幾步:
- 解鎖(點亮螢幕,切換到輸入密碼介面,輸入密碼)
- 開啟支付寶
- 從主頁進入螞蟻森林主頁
- 收集自己的能量
- 進入排行榜
- 在排行榜檢測是否有好有的能量可以收集
- 結束後返回主頁面
程式碼
當然,如果不想使用電腦,可以直接在手機端 下載 Auto.js,直接把程式碼複製 執行即可。
/**
* author lvyimeng
* @version V1.0
* @Title: 螞蟻森林
* @Description:螞蟻森林自動收取能量和偷取能量
* @date: 2018-9-14 12:33:56
*/
var myEnergeType=["線下支付","行走","共享單車","地鐵購票","網路購票","網購火車票","生活繳費","ETC繳費","電子發票","綠色辦公","鹹魚交易","預約掛號"];
var morningTime="07:03";//自己運動能量生成時間
unlock();
sleep(1000);
mainEntrence();
//解鎖
function unlock(){
if(!device.isScreenOn()){
//點亮螢幕
device.wakeUp();
sleep(1000);
//滑動螢幕到輸入密碼介面
swipe(500, 1900, 500, 1000, 1000);
sleep(1000);
//輸入四次 1 (密碼為1111)其他密碼請自行修改 數字鍵1的畫素座標為(200,1000)
click(200,1000);
sleep(500);
click(200,1000);
sleep(500);
click(200,1000);
sleep(500);
click(200,1000);
sleep(500);
}
}
/**
* 日誌輸出
*/
function tLog(msg) {
toast(msg);
console.log(msg)
}
/**
* 獲取許可權和設定引數
*/
function prepareThings(){
setScreenMetrics(1080, 1920);
//請求截圖
if(!requestScreenCapture()){
tLog("請求截圖失敗");
exit();
}
}
/**
* 設定按鍵監聽 當指令碼執行時候按音量減 退出指令碼
*/
function registEvent() {
//啟用按鍵監聽
events.observeKey();
//監聽音量上鍵按下
events.onKeyDown("volume_down", function(event){
tLog("指令碼手動退出");
exit();
});
}
/**
* 獲取截圖
*/
function getCaptureImg(){
var img0 = captureScreen();
if(img0==null || typeof(img0)=="undifined"){
tLog("截圖失敗,退出指令碼");
exit();
}else{
return img0;
}
}
/**
* 預設程式出錯提示操作
*/
function defaultException() {
tLog("程式當前所處狀態不合預期,指令碼退出");
exit();
}
/**
* 等待載入收集能量頁面,採用未找到指定元件阻塞的方式,等待頁面載入完成
*/
function waitPage(type){
// 等待進入自己的能量主頁
if(type==0){
desc("訊息").findOne();
}
// 等待進入他人的能量主頁
else if(type==1){
desc("澆水").findOne();
}
//再次容錯處理
sleep(3000);
}
/**
* 從支付寶主頁進入螞蟻森林我的主頁
*/
function enterMyMainPage(){
launchApp("支付寶");
tLog("等待支付寶啟動");
var i=0;
sleep(1000);
//五次嘗試螞蟻森林入口
while (!textEndsWith("螞蟻森林").exists() && i<=5){
sleep(2000);
i++;
}
clickByText("螞蟻森林",true,"請把螞蟻森林入口新增到主頁我的應用");
//等待進入自己的主頁
waitPage(0);
}
/**
* 進入排行榜
*/
function enterRank(){
tLog("進入排行榜");
Swipe(520,1860,520,100);
sleep(2500);
clickByDesc("檢視更多好友",0,true,"程式未找到排行榜入口,指令碼退出");
var i=0;
//等待排行榜主頁出現
sleep(2000);
while (!textEndsWith("好友排行榜").exists() && i<=5){
sleep(2000);
i++;
}
if(i>=5){
defaultException();
}
}
/**
* 從排行榜獲取可收集好友的點選位置
* @returns {*}
*/
function getHasEnergyfriend(type) {
var img = getCaptureImg();
var p=null;
if(type==1){
//img 是圖片
//"#30bf6c" 第一個顏色
//[0, 33, "#30bf6c"] 第二顏色和它的相對座標
//[34,45, "#ffffff"] 第三個顏色和他的相對座標
//region: [1030, 100, 1, 1700] 第一個顏色的檢測區域1030,100為起始座標,1,1700為區域寬度!!!
p = images.findMultiColors(img, "#30bf6c",[[60, 0, "#30bf6c"], [46,45, "#ffffff"]], {
region: [1018, 100, 1, 1700]
});
}
if(p!=null){
return p;
}else {
return null;
}
}
/**
* 判斷是否好有排行榜已經結束
* @returns {boolean}
*/
function isRankEnd() {
if(descEndsWith("沒有更多了").exists()){
var b=descEndsWith("沒有更多了").findOne();
var bs=b.bounds();
if(bs.centerY()<1920){
return true;
}
}
return false;
}
/**
* 在排行榜頁面,迴圈查詢可收集好友
* @returns {boolean}
*/
function enterOthers(){
tLog("開始檢查排行榜");
var i=1;
var ePoint=getHasEnergyfriend(1);
//確保當前操作是在排行榜介面
while(ePoint==null && textEndsWith("好友排行榜").exists()){
//滑動排行榜 root方式的的點選呼叫.如無root許可權,7.0及其以上可採用無障礙模式的相關函式
swipe(520,1800,520,300,1000);
sleep(3000);
ePoint=getHasEnergyfriend(1);
i++;
//檢測是否排行榜結束了
if(isRankEnd()){
return false;
}
//如果連續32次都未檢測到可收集好友,無論如何停止查詢(由於程式控制了在排行榜介面,且判斷了結束標記,基本已經不存在這種情況了)
else if(i>32){
tLog("程式可能出錯,連續"+i+"次未檢測到可收集好友");
exit();
}
}
if(ePoint!=null){
//點選位置相對找圖後的修正
tLog(ePoint.x,ePoint.y);
click(ePoint.x,ePoint.y+20);
waitPage(1);
clickByDesc("可收取",80);
//進去收集完後,遞迴呼叫enterOthers
back();
sleep(2000);
var j=0;
//等待返回好有排行榜
if(!textEndsWith("好友排行榜").exists() && j<=5){
sleep(2000);
j++;
}
if(j>=5){
defaultException();
}
enterOthers();
}else{
defaultException();
}
}
/**
* 根據描述值 點選
* @param energyType
* @param noFindExit
*/
function clickByDesc(energyType,paddingY,noFindExit,exceptionMsg){
if(descEndsWith(energyType).exists()){
descEndsWith(energyType).find().forEach(function(pos){
var posb=pos.bounds();
click(posb.centerX(),posb.centerY()-paddingY);
sleep(2000);
});
}else{
if(noFindExit!=null && noFindExit){
if(exceptionMsg !=null){
tLog(exceptionMsg);
exit();
}else{
defaultException();
}
}
}
}
/**
* 根據text值 點選 * @param energyType * @param noFindExit
*/
function clickByText(energyType,noFindExit,exceptionMsg){
if(textEndsWith(energyType).exists()){
textEndsWith(energyType).find().forEach(function(pos){
var posb=pos.bounds();
click(posb.centerX(),posb.centerY()-60);
});
}else{
if(noFindExit!=null && noFindExit){
if(exceptionMsg !=null){
tLog(exceptionMsg);
exit();
}else{
defaultException();
}
}
}
}
/**
* 遍歷能量型別,收集自己的能量
*/
function collectionMyEnergy(){
var energyRegex=generateCollectionType();
var checkInMorning=false;
//如果是早上7點03分左右的話.等待主頁能量出現 每隔一秒檢測一次
while(isMorningTime() && descEndsWith("行走").exists()){
if (!checkInMorning){
tLog("等待運動能量生成中...");
checkInMorning=true;
}
descEndsWith("行走").find().forEach(function(pos){
var posb=pos.bounds();
click(posb.centerX(),posb.centerY()-80);
sleep(1500);
});
}
if(checkInMorning){
tLog("運動能量收集完成");
}
if(descMatches(energyRegex).exists()){
if(!checkInMorning){
tLog("防止小樹的提示遮擋,等待中");
sleep(3000);
}
//這裡存在一定的問題:如果sleep時間短的話,就會出現迴圈程式碼在執行,迴圈之後的程式碼也在執行,感覺出現了非同步,具體原因不明
descMatches(energyRegex).find().forEach(function(pos){
var posb=pos.bounds();
//tLog( posb.centerX());
click(posb.centerX(),posb.centerY()-100);
sleep(3000);
});
}
tLog("自己能量收集完成");
sleep(1000);
}
/**
* 結束後返回主頁面
*/
function whenComplete() {
tLog("結束");
back();
sleep(1500);
back();
exit();
}
/**
* 根據能量型別陣列生成我的能量型別正則查詢字串
* @returns {string}
*/
function generateCollectionType() {
var regex="/";
myEnergeType.forEach(function (t,num) {
if(num==0){
regex+="(\\s*"+t+"$)";
}else{
regex+="|(\\s*"+t+"$)";
}
});
regex+="/";
return regex;
}
function isMorningTime() {
var now =new Date();
var hour=now.getHours();
var minu=now.getMinutes();
var targetTime=morningTime.split(":");
if(Number(targetTime[0])==hour && Math.abs(Number(targetTime[1])-minu)<=2){
return true;
}else{
return false;
}
}
//程式主入口
function mainEntrence(){
//前置操作
prepareThings();
//註冊音量下按下退出指令碼監聽
registEvent();
//從主頁進入螞蟻森林主頁
enterMyMainPage();
//收集自己的能量
collectionMyEnergy();
//進入排行榜
enterRank();
//在排行榜檢測是否有好有的能量可以收集
enterOthers();
//結束後返回主頁面
whenComplete();
}
其實理論很簡單,無非就是截圖,獲取截圖尺寸,按著座標去觸發點選,比如:
這個函式的註釋在程式碼裡有就不多說了。主要是區別手型,倒計時數字,和邀請按鈕。
它們的共同點是都有綠色的背景,區別是手型的白色區域比數字的高,而邀請按鈕的右邊綠色背景沒有到手機的邊緣,利用這個差別,我們就可以分辨出來。我的做法是用了三個點(如下圖,紅色的三個點),第一個為綠色,第二個在第一個的右邊並且顏色相同,第三個在第一個右下方為白色。第一個點的橫座標為1018,第二個點在第一個點的[60,0]方向,第三個在第一個的[46,45]位置,這就是為什麼第一點的取點區域為[1018, 100, 1, 1700],這樣就可以保證取到的第一個點一定是左上角的綠點。
此方法,僅適用於 安卓,IOS版 我將採用workflow 規則形式來完成,敬請記得~~~
總結
程式碼並不難,思路也很簡單,無非就是 按鍵精靈 指令碼檔案。希望能在看懂程式碼之後再進行實際操作。