最近手上的有个autojs项目,客户起初只想要脚本,但是做到大半,又改了主意说要加个本地密码,最后又更改主意说要来个网络验证。

针对网络验证,我仔细思考了一下,某椒云和易某证都经常有朋友推荐,但是经过对成本的核算,我选择投入某椒云的怀抱。按道理来说,官网有接入文档,理论上接入不该有任何难度。

然而,刚刚一接入,就立马出现了一个报错,说ui线程被阻塞。


分析过程

ui为什么会被阻塞呢?我脚本的主要代码都是封装成了函数,用子线程来执行。

按道理来说网络验证接口代码,也是作者封装好了的。

但是事实却就是这样发生了,所以我判断是因为网络验证接口代码导致的。

但是具体是哪个位置呢?

起初我以为是setTimeout()或者setInterval(),然后经过仔细排查,却发现不是。

后来又以为是while循环导致的线程被阻塞,但是经过排查,居然也不是。

为什么都排除了呢?

因为报错代码显示的行里,只有一个sleep。

解决思路

首先,我想着先把接口代码(为自调用函数 返回结果为对象)再封装为一个函数,当脚本主要代码开始运行时才来执行,但是当我这样去解决的时候,我发现,函数外部已经无法访问我想要的值。

接口代码形如:

const cc = (function(){
    function cc(app_key, app_secret){
        http.__okhttp__.setMaxRetries(0);
        http.__okhttp__.setTimeout(10*1000);

        this.event = events.emitter();

        this.debug = true;
        this._lib_version = "v1.07";
        this._protocol = "https";
        this._host = "api.paojiaoyun.com";
        this._device_id = this.getDeviceID();
        this._retry_count = 9;
        
        this._app_key = app_key;
        this._app_secret = app_secret;
        
        this._card = null;
        this._username = null;
        this._password = null;
        this._token = null;
        
        this.is_trial = false;  
        this.login_result = {
            "card_type": "",
            "expires": "",
            "expires_ts": 0,
            "config": "",
        };

        this._auto_aa = true; 
    }
    cc.prototype.SetCard = function(card) {
        this._card = card;
    }
    return cc;
//具体的参数和方法肯定比这个示例代码要多太多太多
})();

let CC = new cc("bnsekoafod", "m3p0lkODSJqqLy"); 
CC.debug = true;
CC.SetCard("mrfzBB");

// 监听心跳失败事件
CC.event.on("heartbeat_failed", function(hret) {
    toast(hret.message);  // 失败提示信息
    exit();  // 退出脚本
})

let login_ret = CC.CardLogin();
if (login_ret.code == 0) {
    // 登录成功,后面写你的业务代码



} else {
    // 登录失败提示
    toast(login_ret.message);
}

// 用户主动退出时记得调用logout
CC.CardLogout();

然后我改变了思路,我试图动手将封装的接口代码直接放到我的脚本的主要运行函数里面去,然而奇怪的,我依旧没有办法在外部访问变量,等改天有时间的时候还得再验证一下这个思路。

经过一番折腾,已经浪费太多时间,我开始相信万能得搜索引擎,但是关于autojs的教程确实比较少,并且ui阻塞的更是难找。

但是,经过一番寻找,也大概有了一个思路,那就是再开一个线程,来执行接口代码。

实践过程一番折腾,才发现理想太丰满,现实太骨感。

子线程执行后,我依旧被变量的作用域所限制了,导致我依旧没法解决我的问题。

痛定思痛,我开始借助群众的力量,找了专门的autojs人员询问,但是也只是说子线程。而找接口的作者,也是子线程。最后是一位热心群众给了我个链接,是别人的博客,写得也挺好的。

遇到ui堵塞怎么办?

解决方案,将sleep重写为一个暂停的function

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

之后你sleep(5000),这类就不会再提示你堵塞了(aj作者提示是)

谁知道,我看完一试,直接死亡。使用之后接口代码就会报错连接服务器失败,因为接口代码里面太多参数和方法我没法一个个去排查这个整出来的新问题,只好放弃。

迷茫的我又思考了一下,最后将封装函数和子线程执行结合起来,同时因为我从外部访问变量让我觉得太难了,那我就不访问了,直接将需要执行的代码和参数直接传入就行了。

解决代码如下:

function lsgo(card){
const cc = (function(){省略})();
let CC = new cc("bnsekoafod", "m3p0lkODSJqqLy"); 
    CC.debug = true;
    CC.SetCard(card);
    
    // 监听心跳失败事件
    CC.event.on("heartbeat_failed", function(hret) {
        toast(hret.message);  // 失败提示信息
        exit();  // 退出脚本
    })
    
    let login_ret = CC.CardLogin();
    if (login_ret.code == 0) {
        toastLog("激活码验证成功");
    name = ui.name.text();
    gonum = Number(ui.gonum.text());
    checknum = ui.checknum.checked;
    if (name.length != 0) {
      if(checknum){
         if(gonum==0){
    return toast("请检查数量是否填写");
     }
     }else{
      gonum=9999;
     }
   log("保存设置");
   SaveAll();
    } else {
    toast("请把备注名补充完整!");
      return;
    }
     console.info(">>>脚本已启动");
     start();

   } else {
        // 登录失败提示
        toast(login_ret.message);
  }
    
    // 用户主动退出时记得调用logout
    CC.CardLogout();
}

本文由 大古 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论