钉钉打卡脚本(基于auto.js)开发总结:TaoToken 统一 Key 接入与配置骨架

发布时间:2026/9/26 10:29:03
钉钉打卡脚本(基于auto.js)开发总结:TaoToken 统一 Key 接入与配置骨架 1. 从一次打卡脚本翻车说起钉钉打卡脚本基于 auto.js这件事我一开始想得很简单Android 上跑个 JavaScript点亮屏幕、打开钉钉、找到「工作」按钮点进去、再点打卡收工。真写起来才发现坑不在业务逻辑而在工程化落地——控件找不到、页面动态加载、时间段判断写死、脚本跑一半被系统杀掉。更麻烦的是脚本里如果要接大模型做语义判断比如识别「今日是否已打卡」的文案Key 散落在各个脚本里改一次要翻好几个文件。这篇就把我这段时间折腾钉钉打卡脚本基于 auto.js的经验整理成一份可复现的骨架脚本结构怎么分层、权限怎么配、稳定性怎么保以及怎么用 TaoToken 的统一 Key/API 通道把模型调用收敛到一处配置。适合已经在写 auto.js、想把脚本从「能跑」推到「稳定跑」的人也适合刚接触 Android 自动化、想找个完整例子跟做的同学。auto.js 本身是一个支持无障碍服务的 Android 平台 JavaScript IDE操作的基本单位是控件而不是坐标这点和按键精灵那种基于坐标的方案差别很大。基于控件的好处是换分辨率、换手机不容易崩坏处是遇到动态加载的页面控件树还没渲染出来就去 findOnce直接返回 null。理解这一点后面所有稳定性优化都是围绕它展开的。2. TaoToken 统一 Key 接入为什么脚本侧也需要先说清楚 TaoToken 在这里扮演什么角色。官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 这个不加 UTM。它提供的是统一的模型调用通道你拿一个 Key就能在脚本里发起对话/补全请求不用为每个模型单独维护一套鉴权和地址。对打卡脚本来说模型调用不是必须的但一旦你想加这些能力它就有用了判断钉钉页面上那句「今日已打卡」到底是成功还是失败提示把打卡结果整理成一句自然语言写进日志或者根据当前时间节假日文案决定要不要跳过。这些逻辑用纯字符串匹配也能做但页面文案一改就废用模型做语义判断更抗造。关键是把 Key 收敛。我试过的最笨做法是每个 .js 文件顶部写一个 const KEY ...结果三个脚本三个 Key轮换的时候漏改一个脚本静默失败。正确做法是抽一个配置文件脚本启动时读进来。TaoToken 的 Key 在控制台创建地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建完在 API Keys 页面能看到页面是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到请求格式问题先翻它。注意Key 属于敏感信息别硬编码进要分享的脚本里也别提交到公开仓库。用配置文件 本地读取分享时把配置模板给出去就行。3. 可复制配置settings.json 与 config.toml 骨架auto.js 读本地文件用 files 模块路径一般放在 /sdcard/ 下。我习惯把配置放 /sdcard/autojs-dingtalk/config/ 目录脚本启动时读。下面给两份等价配置你按习惯选一份。先看 settings.json适合直接 JSON.parse{ taotoken: { base_url: https://taotoken.net/api, api_key: sk-替换成你自己的Key, model: gpt-4o-mini, timeout_ms: 15000 }, dingtalk: { package: com.alibaba.android.rimet, work_tab_desc: 工作, checkin_button_text: 打卡, max_retry: 3, retry_interval_ms: 1500 }, schedule: { work_days: [1, 2, 3, 4, 5], morning_after_hour: 8, morning_after_minute: 38, evening_after_hour: 18, evening_after_minute: 0 } }再看 config.toml可读性更好但 auto.js 没有内置 TOML 解析需要你自己写个简易解析或用现成库。如果你不想引依赖直接用上面的 JSON 更省事[taotoken] base_url https://taotoken.net/api api_key sk-替换成你自己的Key model gpt-4o-mini timeout_ms 15000 [dingtalk] package com.alibaba.android.rimet work_tab_desc 工作 checkin_button_text 打卡 max_retry 3 retry_interval_ms 1500 [schedule] work_days [1, 2, 3, 4, 5] morning_after_hour 8 morning_after_minute 38 evening_after_hour 18 evening_after_minute 0读取配置的脚本片段放在主入口最前面// config.js —— 统一读取配置其他脚本 require 它 var CONFIG_PATH /sdcard/autojs-dingtalk/config/settings.json; function loadConfig() { if (!files.exists(CONFIG_PATH)) { toast(配置文件不存在: CONFIG_PATH); exit(); } var raw files.read(CONFIG_PATH); try { return JSON.parse(raw); } catch (e) { toast(配置解析失败: e.message); exit(); } } module.exports loadConfig();主脚本里这样用var cfg require(./config.js); log(模型: cfg.taotoken.model); log(打卡包名: cfg.dingtalk.package);这样 Key 和业务参数都在一个文件里轮换 Key 只改一处。模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 想先在网页上验证 Key 能不能用、模型返回格式对不对去那里试最快。4. 脚本结构与稳定性要点把脚本拆成四层比一个文件从头写到尾好维护得多。第一层是入口层负责点亮屏幕、判断时间段、决定要不要执行。点亮屏幕这段if (!device.isScreenOn()) { log(屏幕未唤醒尝试点亮); device.wakeUpIfNeeded(); sleep(800); }第二层是应用层负责启动钉钉并等待界面就绪。launchApp 之后不要立刻找控件给页面一点渲染时间launchApp(cfg.dingtalk.package); sleep(2500);第三层是控件层负责找控件、点击、重试。这是最容易出问题的地方核心思路是「找不到就等等不到就重试重试超限就报错退出」而不是 findOnce 返回 null 就继续往下跑function findWithRetry(selectorFn, maxRetry, interval) { for (var i 0; i maxRetry; i) { var node selectorFn(); if (node ! null) { return node; } log(第 (i 1) 次未找到控件等待重试); sleep(interval); } return null; } var workBtn findWithRetry(function () { return desc(cfg.dingtalk.work_tab_desc).findOnce(); }, cfg.dingtalk.max_retry, cfg.dingtalk.retry_interval_ms); if (workBtn null) { log(工作页签始终未出现退出); exit(); } workBtn.click(); sleep(1200);第四层是模型层负责在需要语义判断时调 TaoToken。用 auto.js 的 http.post 发请求注意把 Key 放在 Authorization 头里function askModel(prompt) { var url cfg.taotoken.base_url /v1/chat/completions; var headers { Content-Type: application/json, Authorization: Bearer cfg.taotoken.api_key }; var body { model: cfg.taotoken.model, messages: [ { role: system, content: 你是打卡结果判断助手只回答 success 或 fail。 }, { role: user, content: prompt } ] }; var res http.postJson(url, body, { headers: headers, timeout: cfg.taotoken.timeout_ms }); if (res.statusCode ! 200) { log(模型请求失败: res.statusCode res.body.string()); return null; } var data res.body.json(); return data.choices[0].message.content.trim(); }稳定性上还有几个点值得单独说。时间段判断别写死now_Hours 8用更稳否则 8 点 39 分启动脚本就永远进不去分支。工作日判断用配置里的 work_days 数组别硬编码now_day 6调休场景会翻车。脚本跑长任务时Android 可能因为省电策略杀进程建议在 auto.js 里开启前台服务或保持唤醒锁具体在应用设置里勾选。5. 验证请求与成功结果配置写完先别急着跑完整打卡流程分两步验证。第一步验证模型通道。单独写个 test-model.jsvar cfg require(./config.js); var result askModel(测试连通性回复 ok); log(模型返回: result);跑起来如果日志里出现模型返回: ok说明 Key、地址、模型名都对。如果返回 401检查 Key 是不是复制时带了空格返回 404检查 base_url 是不是漏了 /v1 或者多写了斜杠超时就把 timeout_ms 调大。第二步验证控件链路。把打卡动作先注释掉只跑到「找到工作页签并点击」为止看日志屏幕未唤醒尝试点亮 第 1 次未找到控件等待重试 找到工作页签如果一直卡在「未找到控件」多半是钉钉版本不同导致 desc 文案变了用 auto.js 的布局分析工具悬浮窗里的放大镜抓一下实际控件的 desc 或 text改配置里的 work_tab_desc 即可。完整跑通后日志大概长这样当前系统时间: 8:40 工作日进入打卡流程 启动钉钉 找到工作页签 找到打卡按钮 打卡动作已触发 模型判断结果: success看到最后一行 success说明从配置读取、控件查找、到模型语义判断整条链路都通了。6. 本篇常见错排查控件 findOnce 返回 null最常见。原因有三——页面没渲染完加 sleep 或重试、desc/text 文案和实际不符用布局分析工具核对、控件在 WebView 里auto.js 对 WebView 内控件支持有限这种情况得退回坐标点击辅助。脚本在 Android 7.0 以下报错auto.js 的部分 API 依赖较新的系统能力低版本系统上无障碍服务行为不一致。建议在 7.0 以上系统跑这是社区里反复验证过的经验。模型请求返回 401/403Key 无效或没带对。确认 Authorization 头是Bearer sk-xxx格式中间一个空格。Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 重新生成一个再试。请求超时网络抖动或模型响应慢。把 timeout_ms 调到 20000并在脚本里对模型调用做 try/catch失败时降级为字符串匹配不要让整个打卡流程因为模型超时而中断。脚本跑一半被杀Android 省电策略。在系统设置里给 auto.js 加白名单关闭电池优化auto.js 内部开启前台服务。时间段判断永远不触发检查是不是用了而不是以及 now_day 的取值周日是 0周一是 1和配置里的 work_days 对齐。如果你在接入过程中遇到请求格式、鉴权头、模型名这类问题优先翻接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 大部分报错那里都有对应说明。想把模型调用嵌进更长的编码或 Agent 流程可以看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合长期跑的自动化任务。ClaudeCodeAnthropic 相关入口在 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 需要的话可以对照配置。最后留一个我踩过的坑配置文件里的 api_key 千万别用中文引号JSON.parse 会直接抛异常而 auto.js 的报错信息不一定明显容易误判成 Key 失效。改配置后先跑 test-model.js比直接跑主流程省时间。