提交 0dfd3c57 编写于 作者: D DCloud_LXH

chore: 优化 upgrade-center 代码

上级 c0b8a35f
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<view class="content botton-radius"> <view class="content botton-radius">
<view class="content-top"> <view class="content-top">
<text class="content-top-text">{{title}}</text> <text class="content-top-text">{{title}}</text>
<image class="content-top" style="top: 0;" width="100%" height="100%" src="../images/bg_top.png"> <image class="content-top" style="top: 0;" width="100%" height="100%" src="/uni_modules/uni-upgrade-center-app/static/bg_top.png">
</image> </image>
</view> </view>
<view class="content-header"></view> <view class="content-header"></view>
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
</view> </view>
</view> </view>
<image v-if="!is_mandatory" class="close-img" src="../images/app_update_close.png" @click.stop="closeUpdate"> <image v-if="!is_mandatory" class="close-img" src="/uni_modules/uni-upgrade-center-app/static/app_update_close.png" @click.stop="closeUpdate">
</image> </image>
</view> </view>
</view> </view>
...@@ -314,11 +314,11 @@ ...@@ -314,11 +314,11 @@
}, },
downLoadComplete() { downLoadComplete() {
this.downloading = false; this.downloading = false;
this.downLoadPercent = 0 this.downLoadPercent = 0
this.downloadedSize = 0 this.downloadedSize = 0
this.packageFileSize = 0 this.packageFileSize = 0
downloadTask = null; downloadTask = null;
// 强制更新,直接安装 // 强制更新,直接安装
...@@ -555,4 +555,4 @@ ...@@ -555,4 +555,4 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }
</style> </style>
\ No newline at end of file
## 升级中心 - app插件与 `uni-admin` 版本关系 文档已移至 [uni-upgrade-center](https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html)
\ No newline at end of file
### `uni-admin >= 1.9.3`:云函数 `checkVersion` 废弃,使用 uni-admin 自带的 `uni-upgrade-center` 云函数。
# uni-upgrade-center - App
### 概述
> 统一管理App及App在`Android`、`iOS`平台上`App安装包`和`wgt资源包`的发布升级
> uni升级中心分为业务插件和后台管理插件。本插件为业务插件,包括uni升级中心客户端检查更新的前后端逻辑。后台管理系统另见 [uni-upgrade-center - Admin](https://ext.dcloud.net.cn/plugin?id=4470)
### uni升级中心 - 客户端检查更新插件
- 一键式检查更新,同时支持整包升级与wgt资源包更新
- 好看、实用、可自定义的客户端提示框
## 安装指引
1. 依赖数据库`opendb-app-versions`,如果没有此库,请在云服务空间中创建。
2. 使用`HBuilderX 3.1.0+`,因为要使用到`uni_modules`
3. 在插件市场打开本插件页面,在右侧点击`使用 HBuilderX 导入插件`,选择要导入的项目点击确定
4. 绑定一个服务空间。自 `0.6.0` 起,依赖 `uni-admin 1.9.3+``uni-upgrade-center 云函数`,请和 uni-admin 项目关联同一个服务空间
5. 找到`/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version`,右键上传部署。自 `0.6.0` 起,依赖 `uni-admin 1.9.3+``uni-upgrade-center 云函数`,插件不再单独提供云函数,这样可以省下一个云函数名额。
6.`pages.json`中添加页面路径。**注:请不要设置为pages.json中第一项**
```json
"pages": [
// ……其他页面配置
{
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
"style": {
"disableScroll": true,
"app-plus": {
"backgroundColorTop": "transparent",
"background": "transparent",
"titleNView": false,
"scrollIndicator": false,
"popGesture": "none",
"animationType": "fade-in",
"animationDuration": 200
}
}
}
]
```
7.`@/uni_modules/uni-upgrade-center-app/utils/check-update`import到需要用到的地方,调用一下即可
1. 默认使用当前绑定的服务空间,如果要请求其他服务空间,可以使用其他服务空间的 `callFunction`[详情](https://uniapp.dcloud.io/uniCloud/cf-functions.html#call-by-function-cross-space)
8. 升级弹框可自行编写,也可以使用`uni.showModal`,或使用现有的升级弹框样式,如果不满足UI需求请自行替换资源文件。在`utils/check-update.js`中都有实例。
9. wgt更新时,打包前请务必将manifest.json中的版本修改为更高版本。
### 更新下载安装`check-update.js`
*该函数在utils目录下*
1. 如果是静默更新,则不会打开更新弹框,会在后台下载后安装,下次启动应用生效
2. 如果是 iOS,则会直接打开AppStore的链接
3. 其他情况,会将`check-version`返回的结果保存在localStorage中,并跳转进入`upgrade-popup.vue`打开更新弹框
### 检查更新函数`check-version`
*该函数在uniCloud/cloudfunctions目录下*
1. 使用检查更新需要传递三个参数 `appid``appVersion``wgtVersion`
2. `appid` 使用 plus.runtime.appid 获取,*注:真机运行时为固定值HBuilder,在调试的时候请使用本地调试云函数*
3. `appVersion` 使用 plus.runtime.version 获取
4. `wgtVersion` 使用 plus.runtime.getProperty(plus.runtime.appid,(wgtInfo) => { wgtInfo.version }) 获取
5. `check-version`云函数内部会自动获取 App 平台
**Tips**
1. `check-version`云函数内部有版本对比函数(compare)。
- 使用多段式版本格式(如:"3.0.0.0.0.1.0.1", "3.0.0.0.0.1")。如果不满足对比规则,请自行修改。
- 如果修改,请将*pages/upgrade-popup.vue**compare*函数一并修改
## 项目代码说明
### 更新弹框
- `upgrade-popup.vue` - 更新应用:
- 如果云函数`check-version`返回的参数表明需要更新,则将参数保存在localStorage中,带着键值跳转该页面
- 进入时会先从localStorage中尝试取出之前存的安装包路径(此包不会是强制安装类型的包)
- 如果有已经保存的包,则和传进来的 `version` 进行比较,如果相等则安装。大于和小于都不进行安装,因为admin端可能会调整包的版本。不符合更新会将此包删除
- 如果本地没有包或者包不符合安装条件,则进行下载安装包
- 点击下载会有进度条、已下载大小和下载包的大小
- 下载完成会提示安装:
- 如果是 wgt 包,安装时则会提示 正在安装…… 和 安装完成。安装完成会提示是否重启
- 如果是 原生安装包,则直接跳出去覆盖安装
- 下载过程中,如果退出会提示是否取消下载。如果是强制更新,则只会提示正在下载请稍后,此时不可退出
- 如果是下载完成了没有安装就退出,则会将下载完成的包保存在本地。将包的本地路径和包version保存在localStorage中
### 工具类 utils
- `call-check-version`
- 请求云函数`check-version`拿取版本检测结果
- `check-update`
- 调用`call-check-version`并根据结果判断是否显示更新弹框
### 云函数
- `check-version` - 检查应用更新:
- 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传
- 先从数据库取出所有该平台(会从上下文读取平台信息)的所有线上发行更新
- 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新
- 使用上一步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新。必须同时大于这两项,因为上一次可能是wgt热更新,否则返回暂无更新
- 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion
- 返回结果:
|code|message|
|:-:|:-:|
|0|当前版本已经是最新的,不需要更新|
|101|wgt更新|
|102|整包更新|
|-101|暂无更新或检查appid是否填写正确|
|-102|请检查传参是否填写正确|
\ No newline at end of file
...@@ -29,25 +29,25 @@ export type UniUpgradeCenterResult = { ...@@ -29,25 +29,25 @@ export type UniUpgradeCenterResult = {
min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本 min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本
} }
export default function (): Promise<UniUpgradeCenterResult> { export default function () : Promise<UniUpgradeCenterResult> {
// #ifdef APP // #ifdef APP
return new Promise<UniUpgradeCenterResult>((resolve, reject) => { return new Promise<UniUpgradeCenterResult>((resolve, reject) => {
const systemInfo = uni.getSystemInfoSync() const systemInfo = uni.getSystemInfoSync()
const appId = systemInfo.appId const appId = systemInfo.appId
const appVersion = systemInfo.appVersion const appVersion = systemInfo.appVersion
// #ifndef UNI-APP-X // #ifndef UNI-APP-X
if (plus.runtime.appid && plus.runtime.version) { if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) {
plus.runtime.getProperty(plus.runtime.appid, function (widgetInfo) { plus.runtime.getProperty(appId, function (widgetInfo) {
if (widgetInfo.version) { if (widgetInfo.version) {
let data = { let data = {
action: 'checkVersion', action: 'checkVersion',
appid: plus.runtime.appid, appid: appId,
appVersion: plus.runtime.version, appVersion: appVersion,
wgtVersion: widgetInfo.version wgtVersion: widgetInfo.version
} }
uniCloud.callFunction({ uniCloud.callFunction({
name: 'uni-upgrade-center', name: 'uni-upgrade-center',
data: data, data,
success: (e) => { success: (e) => {
resolve(e.result as UniUpgradeCenterResult) resolve(e.result as UniUpgradeCenterResult)
}, },
...@@ -69,7 +69,7 @@ export default function (): Promise<UniUpgradeCenterResult> { ...@@ -69,7 +69,7 @@ export default function (): Promise<UniUpgradeCenterResult> {
action: 'checkVersion', action: 'checkVersion',
appid: appId, appid: appId,
appVersion: appVersion, appVersion: appVersion,
is_uniapp_x: true, is_uniapp_x: true,
wgtVersion: '0.0.0.0.0.1' wgtVersion: '0.0.0.0.0.1'
} }
try { try {
...@@ -77,20 +77,20 @@ export default function (): Promise<UniUpgradeCenterResult> { ...@@ -77,20 +77,20 @@ export default function (): Promise<UniUpgradeCenterResult> {
name: 'uni-upgrade-center', name: 'uni-upgrade-center',
data: data data: data
}).then(res => { }).then(res => {
const code = res.result['code'] const code = res.result['code']
if (['Int', 'Long', 'number'].includes(typeof code) && (code as number) < 0) { if (['Int', 'Long', 'number'].includes(typeof code) && (code as number) < 0) {
reject({ reject({
code: res.result['code'], code: res.result['code'],
message: res.result['message'] message: res.result['message']
}) })
} else { } else {
const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult const result = JSON.parse<UniUpgradeCenterResult>(JSON.stringify(res.result)) as UniUpgradeCenterResult
resolve(result) resolve(result)
} }
}).catch<void>((err : any | null) => { }).catch<void>((err : any | null) => {
const error = err as UniCloudError const error = err as UniCloudError
if (error.errMsg == '未匹配到云函数[uni-upgrade-center]') if (error.errMsg == '未匹配到云函数[uni-upgrade-center]')
error.errMsg = '【uni-upgrade-center-app】未配置uni-upgrade-center,无法升级。参考: https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html' error.errMsg = '【uni-upgrade-center-app】未配置uni-upgrade-center,无法升级。参考: https://uniapp.dcloud.net.cn/uniCloud/upgrade-center.html'
reject(error.errMsg) reject(error.errMsg)
}) })
} catch (e) { } catch (e) {
...@@ -103,10 +103,10 @@ export default function (): Promise<UniUpgradeCenterResult> { ...@@ -103,10 +103,10 @@ export default function (): Promise<UniUpgradeCenterResult> {
}) })
// #endif // #endif
// #ifndef APP-PLUS // #ifndef APP-PLUS
/* return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
reject({ reject({
message: '请在App中使用' message: '请在App中使用'
}) })
}) */ })
// #endif // #endif
} }
import callCheckVersion, { UniUpgradeCenterResult } from "./call-check-version" import callCheckVersion, { UniUpgradeCenterResult } from "./call-check-version"
// #ifdef UNI-APP-X // #ifdef UNI-APP-X
import { ComponentPublicInstance } from 'vue' import { ComponentPublicInstance } from 'vue'
import { openSchema } from './utils.uts'
// #endif // #endif
// 推荐再App.vue中使用 // 推荐再App.vue中使用
const PACKAGE_INFO_KEY = '__package_info__' const PACKAGE_INFO_KEY = '__package_info__'
// uni-app 项目无法从 vue 中导出 ComponentPublicInstance 类型,故使用条件编译
// #ifdef UNI-APP-X // #ifdef UNI-APP-X
export default function (component : ComponentPublicInstance | null = null) : Promise<UniUpgradeCenterResult> { export default function (component : ComponentPublicInstance | null = null) : Promise<UniUpgradeCenterResult> {
// #endif // #endif
...@@ -18,9 +21,6 @@ export default function () : Promise<UniUpgradeCenterResult> { ...@@ -18,9 +21,6 @@ export default function () : Promise<UniUpgradeCenterResult> {
const code = uniUpgradeCenterResult.code const code = uniUpgradeCenterResult.code
const message = uniUpgradeCenterResult.message const message = uniUpgradeCenterResult.message
const url = uniUpgradeCenterResult.url // 安装包下载地址 const url = uniUpgradeCenterResult.url // 安装包下载地址
// const is_silently = uniUpgradeCenterResult.is_silently // 是否静默更新
// const platform = uniUpgradeCenterResult.platform // 安装包平台
// const type = uniUpgradeCenterResult.type // 安装包类型
// 此处逻辑仅为示例,可自行编写 // 此处逻辑仅为示例,可自行编写
if (code > 0) { if (code > 0) {
...@@ -65,82 +65,29 @@ export default function () : Promise<UniUpgradeCenterResult> { ...@@ -65,82 +65,29 @@ export default function () : Promise<UniUpgradeCenterResult> {
// #endif // #endif
} }
// #ifdef UNI-APP-X
/**
* 使用 uni.showModal 升级
*/
function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
const {
title, // 标题
contents, // 升级内容
is_mandatory, // 是否强制更新
url, // 安装包下载地址
} = packageInfo;
let confirmText = '立即下载更新'
return uni.showModal({
title,
content: contents,
showCancel: !is_mandatory,
confirmText,
success: res => {
if (res.cancel) return;
uni.showToast({
title: '后台下载中……',
duration: 1000
});
// wgt 和 安卓下载更新
uni.downloadFile({
url,
success: res => {
if (res.statusCode !== 200) {
console.error('下载安装包失败');
return;
}
// 下载好直接安装,下次启动生效
uni.installApk({
filePath: res.tempFilePath,
success: () => {
uni.showModal({
title: '安装成功请手动重启'
});
},
fail: err => {
uni.showModal({
title: '更新失败',
content: err
.message,
showCancel: false
});
}
});
}
});
}
});
}
// #endif
// #ifndef UNI-APP-X
/** /**
* 使用 uni.showModal 升级 * 使用 uni.showModal 升级
*/ */
function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
// #ifdef APP
const { const {
title, // 标题 title, // 标题
contents, // 升级内容 contents, // 升级内容
is_mandatory, // 是否强制更新 is_mandatory, // 是否强制更新
url, // 安装包下载地址 url, // 安装包下载地址
platform, // 安装包平台 type,
type // 安装包类型 platform
} = packageInfo; } = packageInfo;
let isWGT = type === 'wgt' let isWGT = type === 'wgt'
let isiOS = !isWGT ? platform.includes('iOS') : false; let isiOS = !isWGT ? platform.includes('iOS') : false;
// #ifndef UNI-APP-X
let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' let confirmText = isiOS ? '立即跳转更新' : '立即下载更新'
// #endif
// #ifdef UNI-APP-X
let confirmText = '立即下载更新'
// #endif
return uni.showModal({ return uni.showModal({
title, title,
...@@ -150,9 +97,14 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { ...@@ -150,9 +97,14 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
success: res => { success: res => {
if (res.cancel) return; if (res.cancel) return;
// 安装包下载
if (isiOS) { if (isiOS) {
// iOS 平台跳转 AppStore
// #ifndef UNI-APP-X
plus.runtime.openURL(url); plus.runtime.openURL(url);
// #endif
// #ifdef UNI-APP-X
openSchema(url)
// #endif
return; return;
} }
...@@ -170,6 +122,8 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { ...@@ -170,6 +122,8 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
return; return;
} }
// 下载好直接安装,下次启动生效 // 下载好直接安装,下次启动生效
// uni-app x 项目没有 plus5+ 故使用条件编译
// #ifndef UNI-APP-X
plus.runtime.install(res.tempFilePath, { plus.runtime.install(res.tempFilePath, {
force: false force: false
}, () => { }, () => {
...@@ -195,9 +149,28 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { ...@@ -195,9 +149,28 @@ function updateUseModal(packageInfo : UniUpgradeCenterResult) : void {
showCancel: false showCancel: false
}); });
}); });
// #endif
// #ifdef UNI-APP-X
uni.installApk({
filePath: res.tempFilePath,
success: () => {
uni.showModal({
title: '安装成功请手动重启'
});
},
fail: err => {
uni.showModal({
title: '更新失败',
content: err.message,
showCancel: false
});
}
});
// #endif
} }
}); });
} }
}); });
// #endif
} }
// #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册