这些天在家研究autojs操作,完全可以用它来模拟手动点击滑动app的各种操作,这个自动化是真的香~
ios端的Jsbox没这么友好,毕竟系统完全不同,也有很多限制。

目前要使用多个账号登录,然后进行点击签到,看广告的需求。

环境:mi8 Android9 AutoJs[4.1.1] 葡萄浏览器com.qwh.grapebrowser

AutoJs在应用市场都被下架了,留个下载的渠道:

https://github.com/SuperMonster002/Hello_Sockpuppet/raw/master/%5Bauto.js%5D%5B4.1.1_alpha2%5D%5Barm-v7%5D(b69a4e23).apk

https://www.hhtjim.com/wp-content/uploads/2020/02/auto.js4_.1.1_alpha2arm-v7b69a4e23.apk_.zip

鼓捣了几天,差不多完工。测试的app是葡萄浏览器com.qwh.grapebrowser,最终效果是运行后自动切换账号来签到。
第一次编写的确是各种懵逼,为啥子不动了,日志在哪里怎么看,每次都手动复制代码到手机好麻烦。。。

开发环境vscode

vscode插件来开发很方便。如果没有开发调试环境,我每次都要微信发送代码的消息,toast,再上app清空粘贴运行,累死。给hyb1996好评,相当不容易。

  1. 运行命令来开启远程环境。

  2. auto.js APP设置里打开,填入电脑端内网ip。当然手机和电脑是要一个内网环境

auto.js自动化处理插件 - 葡萄浏览器多账号签到-LMLPHP

  1. 运行命令就可以在app端运行插件脚本。注意默认模式需要打开在Auso.js界面中启动。

开发

文档:

要操作的控件基本信息都需要用 autojs app的悬浮窗设置里面找到分析

"auto"
console.show();//开启log窗口

//等待打开app
launchApp('葡萄浏览器');
waitForPackage("com.qwh.grapebrowser");

const LOGIN_ACTIVITY = 'com.qwh.grapebrowser.mvp.base.login.LoginActivity';
const MAIN_ACTIVITY = 'com.qwh.grapebrowser.mvp.navigation.NavigationActivity';
const SETTING_ACTIVITY = 'com.qwh.grapebrowser.ui.main.activity.mineview.SystemSettingActivity';
const BASEDIALOG = 'com.qwh.base.BaseDialog';

var  iv_cancel = id("iv_cancel"); //粘贴板搜索窗口的取消按钮
var ad = id('skip_view');//跳过广告按钮
var my = id("ll_mine");//我的按钮
var sign = id("iv_sign");//签到图标
var sign_in = id("iv_sign_in");//签到按钮
var profile_photo = id("iv_pic").className("android.widget.ImageView").clickable(true);//头像
var exit_btn = id('ll_exit');//退出登录的按钮. 不可点击 只能获取坐标来操作
var exit_ac = id('tv_dialog_message_confirm'); //同意执行退出
var login_btn = id('tv_login');//登录按钮

var accounts = {
    "131***1110": "123123"
};

cance_list = [ad , iv_cancel];

//监听弹窗事件(异常界面处理)
threads.start(function(){
    while(true){
        sleep(100);
        for (i in cance_list){
            //toast(cance_list[i]);
            if(cance_list[i].exists()){
                cance_list[i].click();
            }
        }

    };
});

//监听音量下键
threads.start(function(){
  isKeyDown();
})

//id("iv_pic").className("android.widget.ImageView").clickable(true)  .findOne().click();


//根据控件布局点击
function click_btn_func (widget_list,time ){
  if(widget_list instanceof Array){
    for(var i in widget_list){
      var widget = widget_list[i];
      if(widget.exists()){
        if(time){
          while(!widget.findOne(time).click());
        }else{
          while(!widget.findOne().click());
        }

        // if(widget_list[i].clickable()){//可点击判断  测试没有用。
        //   toast('aaaa');
        // }
      }
    }
  }else{
    if(time){
      while(!widget_list.findOne(time).click());
    }else{
      while(!widget_list.findOne().click());
    }
  }
}

//根据坐标点击控件
function click_coord_func(widget_list){
  if(widget_list instanceof Array){
    for(var i in widget_list){
      let widget = widget_list[i];
      if(widget.exists()){
        widget = widget.findOne();
          //获取其中心位置并点击
        while( !click(widget.bounds().centerX(), widget.bounds().centerY()) );
      }
    }
  }else{
    let widget = widget_list.findOne();
          //获取其中心位置并点击
    while( !click(widget.bounds().centerX(), widget.bounds().centerY()) );
  }
}

// 我的界面中判断是否登录
function is_login_of_my_activity(){
    return !!profile_photo.exists();
}

function logout(){
  console.log('function: logout')

  //已经进入我的界面
    // waitForActivity(MAIN_ACTIVITY);//入口主界面 activity
  if(is_login_of_my_activity()){//如果已登录,则点击退出
    console.log('发现有登录账号')
    //切记等待界面响应
    click_btn_func([profile_photo]);
    waitForActivity(SETTING_ACTIVITY);//等待界面响应
    click_coord_func([exit_btn]);
    waitForActivity(BASEDIALOG);
    console.log('返回到登录界面');
    click_btn_func([exit_ac]);
  }else{//已经是退出了 进入登录界面
    console.log('发现已经退出');
      //我的界面点击登录按钮操作
  // if(id('tv_btn').exists()){
  //   .findOne().click();
  // }
  console.log('查找「登录/注册」按钮 进入登录界面')
  click_btn_func( id('tv_btn'),4000);
  }
}

function login(phone,pwd){
  //已进入登录界面
    waitForActivity(LOGIN_ACTIVITY);
    setText(0,phone);
    setText(1,pwd);
  click_btn_func([login_btn]);
  console.log('登录完成')
}

//检测是否点击了音量下键的方法
function isKeyDown(){
  //按键时不会弹出音量框
  events.setKeyInterceptionEnabled("volume_down",true);
  //监听按键
  events.observeKey();
  events.on("key_down",function(volume_down,event){
      toast("正在关闭此脚本");
      //退出脚本
      sleep(500);
      engines.stopAll();
      //直接返回桌面
      home();
  });
}

//每秒执行检测操作 超时退出
function await_callback(callback,timeout_second){
  let _n = 0;
  while(true){
    if(_n > timeout_second){// 最长等待n秒检测
      console.log('await_callback最长等待超时 break')
      break;
    }
    if(callback()){//执行回调 返回true
      return true;//返回true标记给外部
      // break;
    }
    sleep(1000);//步长 1秒
    _n++;
  }
  return false
}

console.log('查找关闭按钮');
await_callback(function(){
    if(className("android.widget.ImageView").depth(5).bounds(55,130,137,212).exists()){
        className("android.widget.ImageView").findOne().click();
        console.log('完成 关闭广告按钮');
        return true
    }
    return false
},3);

  //确定图片 领取报销额度
  console.log('等待界面 准备领取');
  // waitForActivity('com.qwh.grapebrowser.dialog.s');//等待领取报销额度的页面
  var pull_down = await_callback(function(){
    if(className("android.widget.FrameLayout").exists()){
      console.log('点击确定FrameLayout 领取');
      click_coord_func(className("android.widget.FrameLayout"));
      return true;
        }
        return false;
  },30);

console.log('done');

说明:
上面成品修改下账户密码可以直接运行。
需要注意的是代码中很多时候卡住不动都需要判断控件或者按钮是否存在,否者findOne()会一致做轮询。
用log输出,查看运行状态
有些控件无法触发click()方法,需要查看其clickable属性是否为true,意即为是否可点击
不能正常按照控件布局点击的话只能用坐标进行点击操作

安卓是真的香,以后想拥有一台一加😂

参考:

https://hyb1996.github.io/AutoJs-Docs

https://github.com/SuperMonster003/Auto.js_Projects/tree/Ant_Forest

https://www.jianshu.com/p/d2ad3ce9cf87

https://thbelief.coding.me/2019/04/02/Auto-js-Script%E5%BC%80%E5%8F%91-%E4%BA%8C/

https://www.autojs.org/

https://www.autojs.org/topic/1651/%E5%BD%93%E6%8E%A7%E4%BB%B6-clickable-false-%E6%97%B6-%E6%80%8E%E4%B9%88%E8%BF%9B%E8%A1%8C%E7%82%B9%E5%87%BB%E6%88%96%E8%80%85%E8%A7%A6%E6%91%B8

PEACE~

03-04 15:03