更新记录
1.1.5(2026-05-08)
优化了
1.1.4(2026-05-08)
- 重构
readme.md使用说明:拍平第 5 步嵌套结构,改为「方案 B(推荐) / 方案 A」并列,各含启动页 + 首页完整可粘贴示例 - 新增「两种 WGT 集成方案决策表」,在进入第 5 步前明确取舍(生效时机、启动耗时、必填 Props 差异)
- 新增「常见问题」小节,覆盖首页没弹窗、方案 A 需两次启动、iOS 支持度、后台版本号怎么填、
manualCheck()用法、升级覆盖config.js等 6 个高频问题 config.js的APP_UPDATE_SERVER_URL还原为占位符https://api.example.com,避免示例值泄露package.json:补全dcloudext.contact.qq;价格定为 普通授权 ¥1.00 / 源码授权 ¥5.00
1.1.3(2026-03-25)
- 提供插件内
config.js,集中配置应用 ID 与更新服务地址 - 文档补充页面集成步骤与启动页两种 WGT 方案说明
平台兼容性
uni-app(4.0)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.0)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| × | × | √ |
isir-version-update
App 热更新组件,支持 APK 全包更新(弹窗提示 + 下载安装)和 WGT 热更新(后台静默下载下次安装,或在启动页内检查→下载→安装→重启),含 ThinkPHP8 完整后端 + 企业级管理后台。
功能特性
- APK 全包更新:弹窗提示用户,显示更新日志、下载进度、自动安装
- WGT 热更新:① 后台静默下载,下次启动安装(
wgt-installermixin);② 启动页一条龙检查/下载/安装(launch-wgt-flow.js) - 强制更新模式:隐藏关闭按钮,用户必须更新
- 下载失败自动重试(最多 3 次)
- WGT 版本码本地管理,无需依赖
appWgtVersion - 含 ThinkPHP8 后端(API + 管理后台 + 建表 SQL)
- 零第三方依赖,不依赖 uview-plus 等 UI 库
快速开始(共 5 步)
第 1 ~ 4 步是通用准备;第 5 步需要在方案 A / 方案 B 之间二选一(见下方决策表)。
第 1 步:导入插件
在 HBuilderX 插件市场导入,或手动将 uni_modules/isir-version-update 目录复制到你的项目 src/uni_modules/ 下。
第 2 步:部署后端
- 将
server/database_init.sql导入你的 MySQL 数据库 - 将
server/thinkphp8/AppUpdate.php复制到 ThinkPHP8 项目的app/controller/目录 - 将
server/thinkphp8/CrossDomain.php复制到app/middleware/目录 - 将
server/thinkphp8/route.php中的路由配置合并到你的route/app.php - 在
config/middleware.php中注册跨域中间件:
return [
'alias' => [
'cross' => \app\middleware\CrossDomain::class,
],
];
- 将
server/admin/appUpdate.html复制到public/admin/目录,访问http://你的域名/admin/appUpdate.html即可打开管理后台
第 3 步:修改插件内 config.js(必做,不改不可用)
打开 uni_modules/isir-version-update/config.js,只需改前两个常量:
// 1) 改成你后台「应用管理」中的 app_id(建议用包名格式,如 com.yourcompany.app)
export const APP_UPDATE_APP_ID = "com.xxxx.app";
// 2) 改成你的后端站点根地址(结尾不带 /,也不要带 /appUpdate/check 这种子路径)
export const APP_UPDATE_SERVER_URL = "https://api.example.com";
// 3) 一般保持默认;首次安装时写入本地作为 WGT 基线版本码
export const APP_UPDATE_WGT_INIT_CODE = 10001;
业务页面统一这样引用:
import {
APP_UPDATE_APP_ID,
APP_UPDATE_SERVER_URL,
APP_UPDATE_WGT_INIT_CODE,
} from "@/uni_modules/isir-version-update/config.js";
升级插件风险:HBuilderX 升级时可能覆盖
uni_modules内文件,升级前请备份config.js,或把这两个常量挪到业务侧管理。
第 4 步:pages.json 配置
两条关键要求:
- 启动页放
pages数组第一项(冷启动先进入启动页,便于执行 WGT 流程) - 主界面需能常驻或尽早挂载
<isir-version-update />(APK 全包更新检查时机依赖此组件)
最小示例:
{
"pages": [
{
"path": "pages/Launchpage/index",
"style": { "navigationStyle": "custom" }
},
{
"path": "pages/home/index",
"style": { "navigationBarTitleText": "首页" }
}
]
}
本插件符合 easycom 规范,不需要手动
import,也不需要在pages.json的 easycom 里额外配置,页面模板里直接写<isir-version-update ... />即可使用。
第 5 步:选择 WGT 集成方案(二选一)
在真机 APP 上才会生效(H5 / 小程序会自动跳过更新检查)。本插件的 APK 全包更新 总是由首页组件 <isir-version-update /> 负责,你只需决定 WGT 热更新走哪种:
| 维度 | 方案 B:runLaunchWgtFlow(推荐) |
方案 A:wgt-installer mixin |
|---|---|---|
| 启动页职责 | 当次启动:检查 → 下载 → 安装 → 重启 | 仅安装上次已下载好的 WGT |
| WGT 下载时机 | 当次启动,启动页同步下载 | 上次运行中,由首页组件静默后台下载 |
| WGT 生效时机 | 当次启动(立即生效) | 下次启动(用户需开两次 App) |
| 启动耗时 | 每次启动多一次 wgt 检查请求 | 几乎无感(无额外网络请求) |
| 首页组件必填属性 | :skip-silent-wgt-check="true" |
不要设 skipSilentWgtCheck |
| 适合场景 | 紧急修复、要求立即生效 | 体验优先,版本变化不紧急 |
拿不准就选方案 B:每次启动都能拿到最新 WGT,用户侧最一致。
方案 B:runLaunchWgtFlow(推荐)
需要改 2 个页面:启动页 + 首页。
B1. 启动页(完整示例)
<template>
<view class="splash">
<text class="status">{{ wgtStatusText }}</text>
<view class="progress-bar">
<view class="progress-fill" :style="{ width: wgtProgress + '%' }" />
</view>
</view>
</template>
<script>
import { runLaunchWgtFlow } from "@/uni_modules/isir-version-update/js_sdk/launch-wgt-flow.js";
import {
APP_UPDATE_APP_ID,
APP_UPDATE_SERVER_URL,
APP_UPDATE_WGT_INIT_CODE,
} from "@/uni_modules/isir-version-update/config.js";
export default {
data() {
return { wgtStatusText: "正在检查更新...", wgtProgress: 0 };
},
async mounted() {
const result = await runLaunchWgtFlow({
appId: APP_UPDATE_APP_ID,
serverUrl: APP_UPDATE_SERVER_URL,
wgtInitCode: APP_UPDATE_WGT_INIT_CODE,
onStatus: (t) => {
this.wgtStatusText = t;
},
: (n) => {
this.wgtProgress = n;
},
});
// 即将重启:禁止再跳转,交给 plus.runtime.restart()
if (result.waitingRestart) return;
// 无更新 / 下载失败 / 非 APP:进入首页
uni.reLaunch({ url: "/pages/home/index" });
},
};
</script>
B2. 首页(完整示例,必须带 skipSilentWgtCheck)
<template>
<view>
<isir-version-update
:app-id="appId"
:server-url="serverUrl"
:wgt-init-code="wgtInitCode"
:skip-silent-wgt-check="true"
/>
<!-- 你的首页内容 -->
</view>
</template>
<script>
import {
APP_UPDATE_APP_ID,
APP_UPDATE_SERVER_URL,
APP_UPDATE_WGT_INIT_CODE,
} from "@/uni_modules/isir-version-update/config.js";
export default {
data() {
return {
appId: APP_UPDATE_APP_ID,
serverUrl: APP_UPDATE_SERVER_URL,
wgtInitCode: APP_UPDATE_WGT_INIT_CODE,
};
},
};
</script>
为什么首页还要挂组件:启动页的
runLaunchWgtFlow只管 WGT;APK 全包更新弹窗 + 下载安装由<isir-version-update />负责,所以首页必须挂。:skip-silent-wgt-check="true"让组件不再重复请求 WGT 检查,只处理 APK。
方案 A:wgt-installer mixin
同样需要改 2 个页面:启动页 + 首页。
A1. 启动页(完整示例)
<template>
<view class="splash" v-if="wgtInstalling">
<text>{{ wgtStatusText }}</text>
<view class="progress-bar">
<view class="progress-fill" :style="{ width: wgtProgress + '%' }" />
</view>
</view>
</template>
<script>
import wgtInstaller from "@/uni_modules/isir-version-update/js_sdk/wgt-installer.js";
export default {
mixins: [wgtInstaller],
methods: {
// 必填:无待安装 WGT 或安装失败兜底时,跳去首页
onWgtSkip() {
uni.reLaunch({ url: "/pages/home/index" });
},
// 可选:安装失败回调,之后仍会走 onWgtSkip
onWgtFail(err) {
console.error("[isir] WGT 安装失败", err);
},
},
};
</script>
mixin 已经在 mounted 内部执行检测,你不需要自己调用任何方法。
A2. 首页(完整示例,不要加 skipSilentWgtCheck)
<template>
<view>
<isir-version-update
:app-id="appId"
:server-url="serverUrl"
:wgt-init-code="wgtInitCode"
/>
<!-- 你的首页内容 -->
</view>
</template>
<script>
import {
APP_UPDATE_APP_ID,
APP_UPDATE_SERVER_URL,
APP_UPDATE_WGT_INIT_CODE,
} from "@/uni_modules/isir-version-update/config.js";
export default {
data() {
return {
appId: APP_UPDATE_APP_ID,
serverUrl: APP_UPDATE_SERVER_URL,
wgtInitCode: APP_UPDATE_WGT_INIT_CODE,
};
},
};
</script>
关键点:方案 A 的 WGT 由首页组件静默下载到本地(落在
pending_wgt_*),下次冷启动才被启动页 mixin 安装。所以用户至少需要打开两次 App 才能用上新 WGT,这是方案 A 的固有特性。
进阶参考
runLaunchWgtFlow(options) 返回值
Promise<{ waitingRestart?: boolean; skipped?: boolean }>;
| 字段 | 何时出现 | 你应做的 |
|---|---|---|
waitingRestart |
已安装 WGT 并即将 plus.runtime.restart() |
禁止再 uni.reLaunch,直接 return |
skipped |
非 APP / 无更新 / 下载失败 / 安装失败 | 继续你的正常路由(如 uni.reLaunch 首页) |
执行顺序(仅 APP-PLUS):
- 若本地有
pending_wgt_*(来自上一次首页组件的静默下载):先安装它 → 重启 - 否则请求
/appUpdate/check?type=wgt→ 有更新则下载 → 安装 → 重启 - 任一步失败或无更新:返回
{ skipped: true }
onStatus(text) / onProgress(num) 仅用于驱动启动页 UI;onProgress 范围 0–100,下载阶段 10–90,安装阶段 95,完成 100。
wgt-installer mixin 注入的数据与钩子
mixin 会在你的启动页 data 中注入:
| 字段 | 类型 | 说明 |
|---|---|---|
wgtInstalling |
Boolean | 是否正在安装 WGT(用来切换启动页 UI) |
wgtProgress |
Number | 安装进度 0–100 |
wgtStatusText |
String | 状态文字(如 正在安装更新...) |
你需要实现的方法:
| 方法 | 是否必填 | 何时调用 |
|---|---|---|
onWgtSkip() |
必填 | 无待安装包、或安装失败兜底 |
onWgtFail(err) |
可选 | 安装失败(之后仍会调 onWgtSkip) |
Props 属性
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| appId | String | 是 | - | 应用唯一标识,区分不同 APP 项目 |
| serverUrl | String | 是 | - | 后端服务器地址,如 https://update.example.com |
| autoCheck | Boolean | 否 | true | 组件挂载后是否自动检查更新 |
| skipSilentWgtCheck | Boolean | 否 | false | 为 true 时不在组件内请求 WGT 检查/静默下载,仍会检查 APK;与启动页 launch-wgt-flow 联用时可避免重复 |
| wgtInitCode | Number | 否 | 10001 | WGT 初始版本码,第一次安装 APP 时的默认值 |
Events 事件
type / updateType 取值均为 'apk' 或 'wgt',用于区分事件来源。
| 事件名 | 参数 | 说明 |
|---|---|---|
| has-update | { version, updateInfo, updateType } | 有更新可用;updateType = 'apk' | 'wgt' |
| no-update | { currentVersion } | APK / WGT 均无更新 |
| check-error | { error } | 检查更新请求失败 |
| download-progress | { type, progress, totalBytesWritten, totalBytesExpectedToWrite } | 下载进度;type 区分 APK 或 WGT |
| download-error | { error, retryCount } | 下载失败(APK 会自动重试,最多 3 次) |
| install-success | { type } | 安装成功 |
| install-error | { error, type } | 安装失败 |
| wgt-ready | { version, filePath } | WGT 静默下载完成,已写入 pending_wgt_*,下次启动生效 |
插件内文件一览
| 路径 | 说明 |
|---|---|
config.js |
全局配置(APP_UPDATE_*),导入插件后修改 |
js_sdk/wgt-installer.js |
启动页 mixin:仅安装待安装 WGT |
js_sdk/launch-wgt-flow.js |
runLaunchWgtFlow:启动页 WGT 检查、下载、安装、重启 |
components/isir-version-update/isir-version-update.vue |
页面组件(APK 弹窗 + WGT 静默逻辑) |
Methods 方法
| 方法名 | 说明 |
|---|---|
| manualCheck() | 手动触发检查更新(通过 ref 调用) |
<isir-version-update
ref="updater"
appId="xxx"
serverUrl="xxx"
:autoCheck="false"
/>
<button @click="$refs.updater.manualCheck()">检查更新</button>
WGT 版本码机制
由于 uni-app 没有原生的 WGT 版本号 API,本插件采用本地存储数字版本码的方案:
- APP 首次安装时,本地存储默认版本码(默认
10001,可通过wgtInitCode自定义) - 后台发布 WGT 时,填写比当前版本码更大的数字(如
10002) - 组件检查更新时,将本地版本码发送给后端比较
- WGT 安装成功后,自动更新本地版本码
后端 API 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /appUpdate/check | 检查更新(前端组件调用) |
| POST | /appUpdate/upload | 上传安装包(管理后台调用) |
| GET | /appUpdate/list | 版本列表 |
| POST | /appUpdate/del | 删除版本 |
| POST | /appUpdate/edit | 编辑版本信息 |
| GET | /appUpdate/detail | 版本详情 |
| POST | /appUpdate/toggleStatus | 切换启用/禁用 |
| GET | /appUpdate/appList | 应用列表 |
| GET | /appUpdate/clientReport | 客户端上报版本 |
管理后台
将 server/admin/appUpdate.html 部署到后端 public/admin/ 目录,访问即可使用企业级管理界面:
- 数据统计卡片(应用数、版本数、APK/WGT 数量)
- 客户端上报版本查看(便于确定下次发版填多大的版本号)
- 版本发布(上传 APK/WGT + 填写版本号和更新日志)
- 版本编辑(修改强制更新、更新日志等)
- 版本启用/禁用/删除
静态资源
组件使用了一张弹窗背景图 static/versionUpdate.png,请将你的更新弹窗背景图放入插件的 static/ 目录中。
如果没有自定义背景图,可以在网上搜索 "app更新弹窗背景" 找一张合适的。建议尺寸:宽 600rpx,高 700rpx 左右。
常见问题
Q1. 首页没弹出更新提示?
按此顺序排查:
- 是否在 真机 APP 运行(H5 / 小程序会直接跳过)
config.js里的APP_UPDATE_APP_ID和APP_UPDATE_SERVER_URL是否已改为你自己的值- 后台对应
app_id下是否有已启用的 APK 版本,且版本号大于当前 App - 首页是否真的挂载了
<isir-version-update />(组件卸载的页面不会检查) - 浏览器 DevTools / HBuilderX 控制台是否有
[iSir-update]打印或网络错误
Q2. 方案 A 装完 WGT 没生效?
方案 A 的 WGT 下次启动才生效。首次发版时用户没有 pending_wgt_*,需要:
- 打开 App(首页组件静默下载 WGT,落到本地)
- 完全杀掉 App,再次冷启动(启动页 mixin 安装 WGT 并重启)
如果要当次立即生效,请改用方案 B。
Q3. iOS 能用吗?
- APK 全包更新:仅 Android,iOS 必须走 App Store
- WGT 热更新:iOS 可用,但只能更新前端资源(HTML/JS/CSS/图片),不能引入新的原生能力;请遵守 App Store 审核政策
Q4. 发布新版本时,后台那个「版本号」应该填多少?
- APK:填语义化版本号(如
1.0.1),比当前大即可 - WGT:填纯数字(如
10002),必须大于客户端当前的本地版本码;当前值可在管理后台的「客户端上报版本」里看
Q5. manualCheck() 怎么用?
一般用于「设置 → 检查更新」按钮,此时应关闭自动检查:
<isir-version-update
ref="updater"
:app-id="appId"
:server-url="serverUrl"
:auto-check="false"
/>
<button @click="$refs.updater.manualCheck()">检查更新</button>
Q6. 升级插件后我改过的 appId / serverUrl 丢了?
HBuilderX 升级插件时可能覆盖 uni_modules 下的文件。两种做法:
- 升级前手动备份
config.js,升级后恢复;或 - 彻底不用
config.js,把常量写在你自己的业务代码里(Props 直接传字面量)
注意事项
- 本插件仅支持 APP 端(Android/iOS),H5 和小程序环境会自动跳过更新检查
- APK 版本号使用语义化格式(如
1.0.0),WGT 版本码使用纯数字递增(如10001) - 上传的安装包文件存储在后端
public/uploads/app_update/{app_id}/目录下 - 后端需要 PHP 8.0+ 和 ThinkPHP 8.x
发布到 DCloud 插件市场(避免常见报错)
重要: 插件 package.json 的 id、磁盘目录名、components 下子目录名、主 vue 文件名须 完全一致(建议 全小写 + 连字符,如本插件为 isir-version-update),以便通过 easycom 校验并支持普通授权定价。在插件市场创建插件时,插件 ID 请填 isir-version-update(或 你的作者id-version-update,但与包内 id、解压目录名须一致)。
1. components/isir-version-update 不存在 / 插件包格式不正确
多为 zip 根目录多包了一层。正确做法是:解压后 第一层 就应能看到本插件的 package.json 和 components/ 目录(即与 uni_modules 插件目录结构 一致)。
- 错误:zip 里是
uni_modules/isir-version-update/...或src/uni_modules/...,或再多一层空文件夹 - 正确:在资源管理器中进入
uni_modules/isir-version-update,选中该文件夹内全部内容(或选中该文件夹本身用「压缩到 xxx.zip」,保证解压第一层即package.json+components),压缩为 标准 zip,文件名建议英文(如isir-version-update.zip)
更稳妥:在 HBuilderX 中对本插件目录下的 package.json 右键 → 发布到插件市场,由工具打包,避免手工 zip 结构错误。
2. 「仅 easycom 规范的前端组件插件可设置价格」
插件市场当前对 付费 + 自动加密 的前端组件,优先支持符合 easycom 的 uni_modules 组件;传统 uni-app(Vue2)+ 付费加密 可能与 uni-app x + 云端编译加密 规则不完全一致。若持续无法设价:
- 可先 免费发布 验证 zip 与文档;或
- 向 DCloud 插件市场工单 / 官方文档确认 「component-vue + uni-app Vue2」 是否允许与普通授权同价上架;或
- 长期方案:将主组件按官方要求迁移至 uni-app x + easycom(见 付费前端插件说明)
本插件已采用 components/isir-version-update/isir-version-update.vue,安装后可直接 不写 import、在页面使用 <isir-version-update />(与 easycom 一致);示例工程里若仍 import 组件,仅为便于说明,不影响 easycom 能力。
3. 付费插件与 uni_modules.encrypt
package.json 内已配置 uni_modules.encrypt,列出可参与加密的 JS 文件路径(相对于插件根目录)。config.js 未列入加密,便于购买「普通授权」的用户修改自己的 appId / serverUrl;若市场审核要求调整列表,以审核意见为准。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 16
赞赏 0
下载 11847763
赞赏 1911
赞赏
京公网安备:11010802035340号