uni-app App更新升级前端实现
1. 概述
因为uni-app提供的 uni-upgrade-center 需要配合uniCloud使用,所以,需要寻找在不使用 uniCloud 的情况下实现 App 的版本检查和自动更新功能方法。在 uni-app 中实现 App 更新功能,主要依赖于 HTML5+ 规范提供的运行时 API 和 uni-app 的跨平台能力。
2. 核心 API 详解
2.1 plus.runtime.getProperty()
功能:获取应用的属性信息
语法:
plus.runtime.getProperty(appid, getPropertyCB);
参数说明:
- appid{String}:应用的标识,通常使用- plus.runtime.appid获取当前应用 ID
- getPropertyCB{Function}:获取属性信息成功回调函数
回调函数参数:
function getPropertyCB(inf) {// inf 包含以下属性:// inf.version - 应用版本号// inf.name - 应用名称// inf.description - 应用描述信息// inf.author - 应用作者// inf.features - 应用许可特性列表
}
使用示例:
plus.runtime.getProperty(plus.runtime.appid, (inf) => {console.log('应用版本:', inf.version);console.log('应用名称:', inf.name);
});
注意:开发环境下可能获取不到真实的版本信息
2.2 uni.downloadFile()
功能:下载文件资源到本地
语法:
uni.downloadFile({url: '',header: {},success: function (res) { },fail: function (err) { },complete: function () { }
});
参数说明:
- [url](file://e:\Test\cyb\cyb\unpackage\cache\apk\apkurl) {String}:下载资源的 URL(必需)
- header{Object}:HTTP 请求 Header
- success{Function}:下载成功的回调函数
- fail{Function}:下载失败的回调函数
- complete{Function}:接口调用结束的回调函数
success 回调参数:
{tempFilePath: '',  // 临时文件路径statusCode: 200,   // HTTP 状态码errMsg: 'downloadFile:ok'
}
使用示例:
const downloadTask = uni.downloadFile({url: 'https://example.com/app-release.apk',success: (res) => {if (res.statusCode === 200) {console.log('下载成功,临时文件路径:', res.tempFilePath);}}
});
注意事项:
- 下载的文件是临时文件,重启应用后会被清理
- 大文件下载可能耗时较长,需要给用户进度反馈
- 需要网络权限
2.3 downloadTask.onProgressUpdate()
功能:监听下载进度变化
语法:
downloadTask.onProgressUpdate((res) => {// 处理进度更新
});
回调参数 res:
{progress: 50,           // 下载进度百分比totalBytesWritten: 500, // 已经下载的数据长度,单位 BytestotalBytesExpectedToWrite: 1000 // 预期需要下载的数据总长度,单位 Bytes
}
使用示例:
const downloadTask = uni.downloadFile({url: 'https://example.com/large-file.apk'
});downloadTask.onProgressUpdate((res) => {console.log('下载进度:', res.progress + '%');console.log('已下载:', res.totalBytesWritten + ' bytes');console.log('总大小:', res.totalBytesExpectedToWrite + ' bytes');
});
注意事项:
- 必须在 uni.downloadFile返回 downloadTask 后调用
- 进度更新频率较高,避免在回调中执行复杂操作
- 某些平台可能不支持精确的进度监控
2.4 plus.runtime.install()
功能:安装下载的文件
语法:
plus.runtime.install(filePath, options, successCB, errorCB);
参数说明:
- filePath{String}:安装文件路径(必需)
- options{Object}:安装选项- force{Boolean}:是否强制安装(默认 false)
 
- successCB{Function}:安装成功回调函数
- errorCB{Function}:安装失败回调函数
使用示例:
plus.runtime.install(res.tempFilePath, {force: false
}, (installRes) => {console.log('安装成功');// 通常在此处重启应用plus.runtime.restart();
}, (error) => {console.error('安装失败:', error.message);
});
注意事项:
- 仅在 App 环境下可用
- 需要文件读写权限
- 安装过程不可中断
- Android 需要特殊权限才能安装 APK
- iOS 由于系统限制无法直接安装,通常跳转到 App Store
2.5 plus.runtime.restart()
功能:重启当前应用
语法:
plus.runtime.restart();
使用示例:
// 安装成功后重启应用
plus.runtime.install(filePath, {}, () => {plus.runtime.restart(); // 重启应用使更新生效
}, (error) => {console.error('安装失败:', error);
});
注意事项:
- 重启会清空内存中的数据
- 确保重要数据已保存
- 仅在 App 环境下可用
2.6 plus.runtime.quit()
功能:退出应用
语法:
plus.runtime.quit();
使用场景:
// 强制更新时用户拒绝更新,退出应用
if (this.updateInfo.forceUpdate) {plus.runtime.quit();
}
注意事项:
- 会完全退出应用进程
- 仅在 App 环境下可用
- 谨慎使用,影响用户体验
3. 关键技术点解析
3.1 异步流程控制
// 获取 App 信息
async checkUpdate(showToast = true) {try {const appInfo = await this.getAppInfo();const res = await this.requestUpdateCheck(appInfo);// ...} catch (error) {// 统一错误处理}
}
优点:
使用 async/await 不仅是为了代码美观,更重要的是实现了错误冒泡机制。任何一个环节出错都会被统一的 catch 捕获,避免了回调地狱中的错误处理分散问题。
3.2 Promise 封装异步操作
// 封装网络请求为 Promise
const signatureRes = await new Promise((resolve, reject) => {uni.request({url: 'http://your-server.com/api/app/check-update',method: 'POST',success: (res) => resolve(res),fail: (err) => reject(err)});
});
优势:
- 避免回调地狱:使用 async/await 简化异步代码
- 统一错误处理:try/catch 统一处理所有异步错误
- 代码可读性:线性代码结构更易理解和维护
4. 常见坑点和注意事项
4.1 权限问题
Android 权限配置(manifest.json):
{"app-plus": {"permissions": {"android": {"permissions": ["<uses-permission android:name=\"android.permission.INTERNET\"/>","<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>","<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>"]}}}
}
4.2 平台差异处理
// iOS 无法直接安装 APK,需要特殊处理
if (uni.getSystemInfoSync().platform === 'ios') {// 跳转到 App Storeplus.runtime.openURL('itms-apps://itunes.apple.com/app/idYOUR_APP_ID');return;
}
4.3 文件路径管理
// 下载的文件是临时文件,安装后需要及时处理
downloadTask.success = (res) => {if (res.statusCode === 200) {// 立即安装,避免文件被系统清理plus.runtime.install(res.tempFilePath, {}, successCB, errorCB);}
};
4.4 错误处理
// 网络错误处理
downloadTask.fail = (err) => {uni.hideLoading();uni.showModal({title: '下载失败',content: '请检查网络连接后重试',showCancel: !this.updateInfo.forceUpdate, // 强制更新时不显示取消按钮success: (res) => {if (this.updateInfo.forceUpdate && res.cancel) {plus.runtime.quit(); // 强制更新时取消则退出应用}}});
};
4.5 用户体验优化
// 显示下载进度
downloadTask.onProgressUpdate((res) => {uni.showLoading({title: `正在下载更新...${res.progress}%`,mask: true // 防止用户操作});
});
5. 完整流程梳理
// 1. 获取当前版本信息
plus.runtime.getProperty(plus.runtime.appid, (inf) => {// 2. 请求服务器检查更新uni.request({url: '/check-update',data: { version: inf.version }}).then(res => {if (res.data.needUpdate) {// 3. 显示更新对话框uni.showModal({content: res.data.updateInfo}).then(modalRes => {if (modalRes.confirm) {// 4. 下载更新文件const task = uni.downloadFile({url: res.data.downloadUrl});// 5. 监听下载进度task.onProgressUpdate((progress) => {uni.showLoading({ title: `下载中...${progress.progress}%` });});// 6. 下载完成后安装task.success = (downloadRes) => {plus.runtime.install(downloadRes.tempFilePath, {}, () => {// 7. 安装成功重启应用plus.runtime.restart();});};}});}});
});
