安卓自动化脚本热更新怎么做?不重新打包 APK 也能更新代码

很多人做安卓自动化脚本,都经历过这种场景:脚本部署到几十台手机上,突然发现一个逻辑 bug 或者想加个新功能,只能重新打包 APK、一个个传包、让用户重新安装。一台两台还能忍,几十台上百台就是灾难。

热更新就是解决这个问题的------不重新打包 APK,直接把编译后的代码文件下发到手机。这篇文章把安卓脚本热更新的完整链路讲清楚:怎么配置、服务端怎么写、怎么自动更新、怎么在脚本内手动触发。

一、先搞清楚:热更新热的是什么

很多人第一次接触"热更新"会误以为是要更新 APK,其实不是。热更新的是编译后的 iec 文件,不是打包的脚本 APK。

APK 只是壳,装一次就不用动了。真正的业务逻辑编译成 iec 文件,通过热更新机制下发。这样做的好处非常直接:

  • 免发版:改代码不用重新走打包、签名、分发流程;
  • 秒级下发:用户下次启动脚本,自动拉取最新代码;
  • 故障止损:线上出问题,改一版代码立刻覆盖,不用等用户手动升级。

二、配置文件:update.json 是热更新的入口

在工程目录下找到(或新建)update.json,热更新的所有基础配置都在这里:

json 复制代码
{
  "update_url": "http://baidu.com/update",
  "version": "1.0.0",
  "appendDeviceInfo": true,
  "timeout": 30000
}

各字段含义:

字段 说明
update_url 服务端更新接口地址,需要自己编写服务端接口(或用官方热更新服务)
version 当前脚本的版本号
timeout 请求超时时间,单位毫秒,最低 1000
appendDeviceInfo 是否在请求时附加设备基础信息

appendDeviceInfo 设为 true 后,请求会自动带上设备参数,方便服务端做差异化下发。请求地址会变成类似:

ini 复制代码
http://baidu.com/update?version=1&deviceId=7521e5d9eeec4f58b71dea8b78c414d5&apkVersion=9.22.0&osVersion=12&pkgName=com.gibb.easyclick&model=LNA-AL00&ecVersion=9.22.0&brand=HUAWEI&androidId=82a3b055470ebe1a

参数含义:

参数 说明
version 当前运行的 iec 版本
deviceId EC 生成的设备 ID(可能丢失,不一定能作为设备唯一标识)
apkVersion APK 打包版本
osVersion 系统版本
ecVersion 实际使用的 EC 版本
pkgName 打包的包名
model / brand 机型与品牌
androidId Android ID

三、服务端怎么写:两种返回格式

配置好后,打包运行,客户端会自动用 GET 方式请求 update_url 并带上版本参数,例如 http://baidu.com/update?version=1.0.0。版本比较逻辑在服务端自行处理。

服务端返回分两种情况:

1. 无需更新 ------直接返回空字符串即可,不要返回 JSON

2. 需要更新------返回更新信息 JSON:

json 复制代码
{
  "download_url": "http://baidu.com/aaa.iec",
  "version": "1.1.0",
  "dialog": true,
  "msg": "优化部分问题",
  "force": false
}

字段说明:

字段 说明
download_url 新包的下载地址
version 新包的版本号
dialog 是否用对话框形式展示更新提示(true 弹窗 / false 静默)
msg 对话框中要显示的消息
force 对话框模式下是否强制更新(true 无法取消)

客户端拿到这个 JSON 后,会下载最新的 iec 包并加载使用。

担心下载失败?用严格模式校验 MD5

json 复制代码
{
  "download_url": "http://baidu.com/aaa.iec",
  "version": "1.1.0",
  "dialog": true,
  "msg": "优化部分问题",
  "force": false,
  "md5": "服务器自行校验的iec文件的md5值",
  "download_timeout": 60
}
  • md5:iec 文件的 MD5 值,有该字段会强制校验文件完整性,保证下载的文件一定完整;
  • download_timeout:下载超时时间(秒),不填默认 60 秒。

四、两种更新时机:启动自动更新 + 脚本内手动更新

4.1 UI 启动更新

只要 update.json 配置无误,用户打开脚本界面时会自动请求更新,无需任何额外代码。这是最常用的方式------用户打开脚本,最新代码已经在路上了。

4.2 脚本内热更新

脚本执行期间也可以做热更新,配合代码触发。核心流程是:请求更新 → 下载新包 → 重启脚本

javascript 复制代码
function main() {
    // 从项目文件的 update.json 中获取版本号
    let version = JSON.parse(readIECFileAsString("update.json")).version
    toast("Hello World - " + version);

    // 请求服务器是否有新版本(使用自定义 url 模式)
    let updateResult = hotupdater.updateReq("http://baidu.com", version, true, 9000);
    logd("请求更新是否有: " + updateResult);
    if (!updateResult) {
        logw("请求失败错误信息: " + hotupdater.getErrorMsg());
    } else {
        // 有更新,下载新的版本
        let path = hotupdater.updateDownload();
        logd("下载路径为: " + path);
        if (!path) {
            logw("下载IEC文件错误信息: " + hotupdater.getErrorMsg());
        } else {
            // 重启脚本,加载新版本
            restartScript(path, true, 3)
            return;
        }
    }
}

main();

脚本内热更新用到的方法:

方法 作用
hotupdater.updateReq(updateUrl, version, appendDeviceInfo, timeout) 请求更新接口,返回 true 表示需要更新,false 可能是无需更新或请求失败(用 getErrorMsg 查看具体信息)
hotupdater.updateDownload() 下载热更新返回的 iec 文件,返回下载后文件路径
hotupdater.getUpdateResp() 获取热更新的请求结果
hotupdater.getErrorMsg() 获取请求或下载的错误信息

updateReq 的第一个参数不传时,会使用 update.json 里配置的数据;version 建议使用整型数字。下载完成后调用 restartScript(path, true, 3) 重启脚本,新代码立即生效。

五、几个容易踩的坑

  1. 版本号要一致update.json 里的版本号必须和服务端接口返回的版本号逻辑保持一致,否则可能更新异常;
  2. 无需更新别返回 JSON:服务端判断无更新时直接返回空字符串,返回 JSON 会被当成更新数据处理;
  3. 设备指纹别当唯一标识deviceId 是 EC 生成的,可能丢失,做设备绑定类逻辑不要只依赖它;
  4. 生产环境注意时效 :建议把 appendDeviceInfo 打开,按设备维度控制灰度发布,避免一次全量下发出问题。

六、总结

热更新是安卓脚本从"个人玩具"走向"商业产品"的关键能力:

  • 配置一次,长期受益:update.json 配好后,后续每次迭代都走热更新,告别打包传包;
  • 两种更新方式:UI 启动自动更新适合绝大多数场景,脚本内手动更新适合对时机有要求的业务;
  • 严格模式更稳:生产环境建议带上 md5 校验,防止下载不完整导致脚本异常;
  • 不想写服务端? 直接用官方热更新服务(对接阿里云 OSS),上传 iec 文件即可,自动生成下载地址和 md5。

对于把脚本卖出去、部署到几十上百台设备的团队,热更新不是"锦上添花",而是运维效率的刚需。改一行代码要重装一次 APK 的时代,该翻篇了。

文章来源 blog.ieasyclick.com/blog/androi...

相关推荐
猫七先生1 小时前
在 React 里用 PMTiles 自托管底图
前端
tanghonghanhaoli1 小时前
【图书翻译】有意义的游戏设计:桌面游戏的方法论与心理学(第1、2章)
前端·游戏·ui
光影少年1 小时前
react native打包优化、包体积瘦身、离线包/热更新方案
前端·react native·react.js
Cache技术分享1 小时前
504. Java 反射 - 创建一个简单的依赖注入框架
前端·后端
_codeOH1 小时前
# 手把手复刻 DeepSeek 官网效果:玻璃拟态 + WebGL 流体 + Spring 动画,一篇讲透
前端
名字还没想好☜1 小时前
Next.js 用 cookies()/headers() 读请求信息:动态渲染触发、缓存失效与在 Server Action 里读写 cookie
前端·javascript·缓存·react·next.js·app router
今日无bug2 小时前
从「拿来主义」到「亲手造轮子」:2 种 MCP 文件服务器写法对比
前端·node.js·mcp
xcyxiner2 小时前
flutter 运行到模拟器上
android·前端·flutter
用户921080262862 小时前
从 COT 到 ThoughtChain:AI 应用为什么需要展示“思考过程”
前端