Auto.js (支付宝篇):蚂蚁森林自动收取能量和偷取能量

版权声明:本博客所有内容采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可 https://blog.csdn.net/Soinice/article/details/82698875

说在前面

对于蚂蚁森林,我有一段时间没有玩,后来被人超了。然后,我又开始偷取,每天定闹钟,每天走步数。相信不是土豪,还想成为排行榜的第一。肯定也像我一样(幼稚),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。官方下载地址:https://www.coolapk.com/apk/org.autojs.autojs

第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

实现步骤

其实说白了,就是类似于宏记录,类似按键精灵,其实就是模拟你的操作,让你放手做其他的事情。

本身插件也好,辅助也罢,道理都差不多,好了不废话了,不住简单如下几步:

  1. 解锁(点亮屏幕,切换到输入密码界面,输入密码)
  2. 打开支付宝
  3. 从主页进入蚂蚁森林主页
  4. 收集自己的能量
  5. 进入排行榜
  6. 在排行榜检测是否有好有的能量可以收集
  7. 结束后返回主页面

代码

当然,如果不想使用电脑,可以直接在手机端 下载 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 规则形式来完成,敬请记得~~~

总结

代码并不难,思路也很简单,无非就是 按键精灵 脚本文件。希望能在看懂代码之后再进行实际操作。

源码下载

[相关示例完整代码]

猜你喜欢

转载自blog.csdn.net/Soinice/article/details/82698875
今日推荐