AutoxJS脚本保姆级教程

目录

引言

准备工作

脚本开发

邮件提示(不使用邮件推送的可以跳过这步)

节假日判断(不需要判断节假日的可以跳过)

问题及技巧归总

JS语法错误:软件更新

按钮或组件无法找到

使用定时器等待组件出现

root环境下才能用shell的root模式

主线程堵塞问题

全局日志记录

巧用id或text

Tasker和AutoXjs自启问题

效果展示

写在最后

注意:该脚本请勿用于商用,侵删

相关代码


引言

2021年的时候分享了一个自动化脚本的文章,介绍了使用Tasker+Autojs实现自动化操作。现在公司更换了新的考勤软件,脚本也做了许多期迭代,所以更新了一版脚本分享的文章,并记录一些遇到的问题

准备工作

这篇文章

脚本开发

开发调试的过程可以参照这篇文章

这里直接贴出脚本

javascript 复制代码
/*
 * @Author: Hunter
 * @Date: 2023-07-10 17:46:35
 * @LastEditTime: 2023-07-18 14:56:28
 * @LastEditors: Hunter
 * @Description:
 * @FilePath: \北sen\main.js
 * 可以输入预定的版权声明、个性签名、空行等
 */
var appName = "北森iTalent", //app名
  packageName = getPackageName(appName), //包名
  roundTimer = 60 * 1000, //超时定时器间隔60秒
  randomTimer = parseInt(Math.random() * 5 * 60 * 1000), //随机定时器0-5分钟(精确到毫秒)
  maxRetryCount = 3, //重试打卡次数
  useEmail = true, // 是否发送邮件
  useDate = true, // 是否检查节假日
  cardMenuBtn = () => id("mIVBottomCenter").findOne().bounds(), //打卡界面菜单
  cardViewBtn = () => text("签到").findOne().bounds(), //打卡界面按钮
  positionBtn = () => id("tv_sign_company_status").text("办公地点"), //定位成功按钮
  cardTakeBtn = () => id("rlt_sign_click").findOne(); //打卡按钮
let logs = ``;
// 日志记录
const __log = function () {
  logs += `
  ${new Date()}:${JSON.stringify(arguments)}
  `;
  toast(JSON.stringify(arguments));
  console.trace.apply(null, arguments);
};
const getLog = () => logs;
const mailApi = "https://api.emailjs.com/api/v1.0/email/send", //邮箱请求地址
  mailConfig = {
    user_id: "user_xxxxxxxxxxxxxxxxxxxxxxhj",
    service_id: "sexxxxxxxmk",
    template_id: "templxxxxxxxxxxmn",
    accessToken: "8xxxxxxxxxxxxxxxxxxxxxxxxxxx9",
    template_params: {
      title: "自动打卡通知",
      content: `打卡成功
      日志:${getLog()}
      `,
      email: "xxxxxxxxx@qq.com",// 接收消息的邮箱
    },
  }, //邮箱配置,需要去emailjs官网申请api,每月免费200次
  dateApi = "http://api.tianapi.com/jiejiari/index", //节假日接口
  dateConfig = {
    key: "9dxxxxxxxxxxxxxxxxxx93",
    date: formatDate(new Date()),
  }; //在天行数据申请节假日api(每天免费查询100次):https://www.tianapi.com/
__log("随机延迟时间:", randomTimer);
if (useDate) {
  // 检查是否开启节假日检测
  checkDateIsWork(dateConfig, function (res) {
    if (res.newslist[0].isnotwork) {
      sendEmail(setNewMessage("今天是法定节假日,无需打卡"));
      exitApp(true);
      return;
    }
    exitApp(false);
    setTimeout(init, randomTimer);
  });
} else {
  exitApp(false);
  setTimeout(init, randomTimer);
}

function init() {
  if (!!maxRetryCount) {
    __log("剩余重试次数" + maxRetryCount);
    timeOutMsg();
    maxRetryCount--;
    startProgram();
    return;
  }
  exitApp(true);
}
//开启应用
function startProgram() {
  __log("launchApp:" + appName, launchApp(appName)); //打开app
  waitForPackage(packageName); //等待app打开
  __log("launchAppSuccess", packageName);
  openCardView();
}
//首页--->打卡页
function openCardView() {
  var cardMenuButton = cardMenuBtn();
  __log(
    "打卡界面菜单",
    click(cardMenuButton.centerX(), cardMenuButton.centerY())
  );
  var cardButton = cardViewBtn();
  __log("进入打卡界面", click(cardButton.centerX(), cardButton.centerY() - 10));
  takeCard();
}
//打卡
function takeCard() {
  __log("等待定位");
  positionBtn().waitFor();
  __log("定位成功");
  __log("点击打卡按钮", cardTakeBtn().click());
  sendSuccEmail();
  exitApp(true);
}
// 打卡成功发邮件
function sendSuccEmail() {
  const _mailConfig = mailConfig;
  _mailConfig.template_params.content += getLog();
  __log("发送邮件", sendEmail(_mailConfig));
}
//退出程序
function exitApp(exitJs, fn) {
  shell("am force-stop " + packageName, true);
  fn && fn();
  exitJs && exit();
}

// 程序超时处理
function timeOutMsg() {
  threads.start(function () {
    //在新线程执行的代码
    setTimeout(function () {
      sendEmail(setNewMessage("自动打卡超时,正在重试"));
      exitApp(false, init);
    }, roundTimer);
  });
}
// 发送邮件api
function sendEmail(params) {
  if (useEmail) {
    var res = http.post(mailApi, params || mailConfig, {
      contentType: "application/json",
    });
    return res;
  }
}
// 节假日api请求
function checkDateIsWork(params, fn) {
  var res = http.post(dateApi, params || dateConfig).body.json();

  if (res.code === 200) {
    fn(res);
    return;
  }
  __log(res);
  sendEmail(setNewMessage(res.msg));
}
// 修改默认邮件提示信息
function setNewMessage(msg) {
  var _mailConfig = simpleCloneObj(mailConfig, {
    contentType: "application/json",
  });
  _mailConfig.template_params.content = `${msg + new Date()}
  日志:${getLog()}
  `;
  return _mailConfig;
}

//日期格式转换 YYYY-MM-DD
function formatDate(date) {
  var y = date.getFullYear();
  var m = date.getMonth() + 1;
  m = m < 10 ? "0" + m : m;
  var d = date.getDate();
  d = d < 10 ? "0" + d : d;
  return y + "-" + m + "-" + d;
}

// 简单的深复制
function simpleCloneObj(target) {
  return typeof target === "object" && JSON.parse(JSON.stringify(target));
}

邮件提示(不使用邮件推送的可以跳过这步)

在代码中可以配置邮件通知的选项,或者使用useEmail来控制是否发送邮件,此外还可以参照这篇文章,使用自己的邮件推送服务

这里以emailjs为例,每个月可以调用200次。

首先绑定自己的邮件服务

接着同样参照这篇文章,配置一下邮箱的选项用于邮件推送

然后是邮件模板的配置,代码中的template_params请求参数与模板配置对应

最后是emailjs的一些id

  • service_id

  • template_id

  • user_id和accessToken

将这些配置项放在代码中就可以使用了

节假日判断(不需要判断节假日的可以跳过)

为了计算当前日期是否是节假日,我调用了一个天行的公共api,当然也可以通过将代码中的useDate设置为false关闭该功能

注册并实名后搜索节假日

点击开通,每天免费使用100次

问题及技巧归总

在上一版本脚本迭代中遇到了以下问题以及autoxjs中的一些使用技巧,供参考

JS语法错误:软件更新

旧版本的autojs或AutoXJS可能会提示语法错误,有可能是使用了过于超前的JS语法,建议更新app版本比如字符串模板 ` ${} ` ,const 等

按钮或组件无法找到

按钮无法找到的问题出现在北sen软件中,在*人薪事中可以使用id或者text的方式找到并点击组件,但是升级安卓高版本的系统后,组件的clickable为false,可能会出现找不到组件的问题,那就只能通过例如:text("签到").findOne().bounds() 的方式来获取组件的范围,然后通过类似:click(cardButton.centerX(), cardButton.centerY()) 的方式对屏幕进行动态定位点击事件,具体可以参考上面代码中的openCardView函数的两个点击事件

使用定时器等待组件出现

使用setinterval来轮询查询页面组件的clickable是否为true,由于有时使用官方的waitfor失效,所以想到了这个方式,这种方式虽然可以解决问题,不到万不得已不推荐使用,会导致性能差

root环境下才能用shell的root模式

模拟器中需要开启root,手机也需要root才能使用root模式执行sh

主线程堵塞问题

我在脚本后续迭代中加入了主线程超时处理,超过一分钟我就会重启脚本和软件,具体参考timeOutMsg函数

全局日志记录

好的程序必定离不开日志监控及问题定位排查,在__log函数中我封装了全局的日志处理,每步操作都会记录日志信息

巧用id或text

有许多组件没有id选项,所以就只能使用text或者parent等方式取获取组件

Tasker和AutoXjs自启问题

自启问题比较棘手,我使用tasker每天定时启动autojs防止脚本执行,那么如何保证tasker自启呢?使用autojs实现的,说起来很怪,有时会偶发autojs启动了但是却无法接受tasker发的系统广播,此时重启一下autojs就可以解决,具体脚本如下

javascript 复制代码
// 自启tesker,防止开机被kill
var appName = "Tasker", //app名
  packageName = getPackageName(appName); //包名
startProgram();
//开启应用
function startProgram() {
  toast("launchApp:" + appName);
  console.log("launchApp:" + appName, launchApp(appName)); //打开app
  waitForPackage(packageName); //等待app打开
  console.log("launchAppSuccess", packageName);
  toast("launchAppSuccess", packageName);
  exit();
}

效果展示

讲完了这么多,我们参考这个将脚本放在AutoXJS中演示一下

写在最后

本篇文章对以前的自动化脚本的迭代更新做了个梳理,有许多步骤在之前的文章中有,建议先过一遍,除此之外,文章总结了一些在脚本迭代过程中遇到的问题和解决技巧。其中涉及到的问题包括JS语法错误、按钮或组件无法找到、使用定时器等待组件出现、root环境下才能用shell的root模式以及主线程堵塞问题等。同时,文章提供了一些技巧,如巧用id或text获取组件、全局日志记录和Tasker与AutoX.js自启问题的解决方案。

注意:该脚本请勿用于商用,侵删

以上就是文章全部内容了,如果觉得文章不错的话,还请三连支持一下,谢谢!

相关代码

myCode: 基于js的一些小案例或者项目 - Gitee.com

邮件推送服务: 基于 TS+Node+nodemailer 实现一个开箱即用的 Node 邮件推送服务,需要获取邮箱的授权码

相关推荐
xjt_09012 分钟前
浅析Web存储系统
前端
foxhuli22940 分钟前
禁止ifrmare标签上的文件,实现自动下载功能,并且隐藏工具栏
前端
青皮桔1 小时前
CSS实现百分比水柱图
前端·css
失落的多巴胺1 小时前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear1 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息1 小时前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月1 小时前
1.vue权衡的艺术
前端·vue.js·开源
样子20181 小时前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿1 小时前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
翻滚吧键盘1 小时前
vue文本插值
javascript·vue.js·ecmascript