From ad080cdeefaf7a23b0f7c3eaab61cb45adeacbb7 Mon Sep 17 00:00:00 2001 From: DCloud_LXH <283700113@qq.com> Date: Thu, 2 Nov 2023 19:51:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/tabBar/component.uvue | 25 +- .../uni-upgrade-center-app/changelog.md | 72 +++ .../uni-upgrade-center-app/package.json | 81 +++ .../pages/upgrade-popup-uts.uvue | 437 ++++++++++++++ .../pages/upgrade-popup.vue | 554 ++++++++++++++++++ uni_modules/uni-upgrade-center-app/readme.md | 126 ++++ .../static/app_update_close.png | Bin 0 -> 7644 bytes .../uni-upgrade-center-app/static/bg_top.png | Bin 0 -> 30486 bytes .../uniCloud/database/db_init.json | 1 + .../utils/call-check-version.ts | 109 ++++ .../utils/check-update.ts | 206 +++++++ 11 files changed, 1607 insertions(+), 4 deletions(-) create mode 100644 uni_modules/uni-upgrade-center-app/changelog.md create mode 100644 uni_modules/uni-upgrade-center-app/package.json create mode 100644 uni_modules/uni-upgrade-center-app/pages/upgrade-popup-uts.uvue create mode 100644 uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue create mode 100644 uni_modules/uni-upgrade-center-app/readme.md create mode 100644 uni_modules/uni-upgrade-center-app/static/app_update_close.png create mode 100644 uni_modules/uni-upgrade-center-app/static/bg_top.png create mode 100644 uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json create mode 100644 uni_modules/uni-upgrade-center-app/utils/call-check-version.ts create mode 100644 uni_modules/uni-upgrade-center-app/utils/check-update.ts diff --git a/pages/tabBar/component.uvue b/pages/tabBar/component.uvue index a2cf74fa..0ea1d1fe 100644 --- a/pages/tabBar/component.uvue +++ b/pages/tabBar/component.uvue @@ -38,14 +38,19 @@ - + + + - diff --git a/uni_modules/uni-upgrade-center-app/changelog.md b/uni_modules/uni-upgrade-center-app/changelog.md new file mode 100644 index 00000000..21a54c45 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/changelog.md @@ -0,0 +1,72 @@ +## 0.6.5(2023-10-27) +- 修复 安装 wgt 报错 manifest.json 文件不存在的Bug +## 0.6.4(2023-09-01) +chore: 优化代码结构 +## 0.6.3(2023-08-30) +- 修复 下载 wgt 时如果后缀名不正确,重命名后安装 +## 0.6.2(2022-11-21) +- 处理 cloudfunctions 目录 +## 0.6.1(2022-08-17) +- 修复 后台添加应用市场,但都没有启用的情况下报错的Bug (需要 uni-admin 1.9.3+) +## 0.6.0(2022-07-19) +- 新增 支持多应用商店配置(需要 uni-admin 1.9.3+) +## 0.4.1(2022-05-27) +- 修复 上版引出的报错问题 +## 0.4.0(2022-05-27) +- 新增 Android 支持跳转手机自带商店,填写升级包地址时请填写跳转商店链接 +- 新增 改为云对象调用方式,使用更直观 +## 0.3.3(2022-04-14) +- 修复 调用 check-update,当 code 为 0 时没有回调 +## 0.3.2(2022-01-12) +- 优化显示逻辑 +## 0.3.1(2021-11-24) +- 修复 vue3 上图片不显示的Bug +## 0.3.0(2021-11-18) +- 移除 wgt 安装成功后提示,防止重启过快弹框不消失 +## 0.2.2(2021-08-25) +- 兼容vue3.0 +## 0.2.1(2021-07-26) +- 修复 使用腾讯云并手动填写地址时,导致下载链接失效的bug +## 0.2.0(2021-07-13) +- 更新文档 关于报错local_storage_key 为空,请不要将页面路径设置为pages.json中第一项 +## 0.1.9(2021-06-28) +- 更新文档 +- 修复 wgt安装失败时,按钮状态不对 +## 0.1.8(2021-06-16) +- 修复 跳转安装时,导致上次下载的apk还没安装就被删掉的bug +## 0.1.7(2021-06-03) +- 修改 移除static中的图片 +## 0.1.6(2021-06-03) +- 修改 下载更新按钮使用CSS渐变色 +## 0.1.5(2021-04-22) +- 更新check-update函数。现在返回一个Promise,有更新时成功回调,其他情况错误回调 +## 0.1.4(2021-04-13) +- 更新文档。明确云函数调用结果 +## 0.1.3(2021-04-13) +- 解耦云函数与弹框处理。utils中新增 call-check-version.js,可用于单独检测是否有更新 +## 0.1.2(2021-04-07) +- 更新版本对比函数 compare +## 0.1.1(2021-04-07) +- 修复 腾讯云空间下载链接不能下载问题 +## 0.1.0(2021-04-07) +- 新增使用uni.showModal提示升级示例 +- 修改iOS升级提示方式 +## 0.0.7(2021-04-02) +- 修复在iOS上打开弹框报错 +## 0.0.6(2021-04-01) +- 兼容旧版本安卓 +## 0.0.5(2021-04-01) +- 修复低版本安卓上进度条错位 +## 0.0.4(2021-04-01) +- 更新readme +- 修复check-update语法错误 +## 0.0.3(2021-04-01) +- 新增前台更新弹框,详见readme +- 更新前台检查更新方法 + +## 0.0.2(2021-03-29) +- 更新文档 +- 移除 dependencies + +## 0.0.1(2021-03-25) +- 升级中心前台检查更新 diff --git a/uni_modules/uni-upgrade-center-app/package.json b/uni_modules/uni-upgrade-center-app/package.json new file mode 100644 index 00000000..f2750d5c --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-upgrade-center-app", + "displayName": "升级中心 uni-upgrade-center - App", + "version": "0.6.5", + "description": "uni升级中心 - 客户端检查更新", + "keywords": [ + "uniCloud", + "update", + "升级", + "wgt" +], + "repository": "https://gitee.com/dcloud/uni-upgrade-center/tree/master/uni_modules/uni-upgrade-center-app", + "engines": { + "HBuilderX": "^3.2.14" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-page" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-upgrade-center-app/pages/upgrade-popup-uts.uvue b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup-uts.uvue new file mode 100644 index 00000000..f17da292 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup-uts.uvue @@ -0,0 +1,437 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue new file mode 100644 index 00000000..ab786602 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/pages/upgrade-popup.vue @@ -0,0 +1,554 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-upgrade-center-app/readme.md b/uni_modules/uni-upgrade-center-app/readme.md new file mode 100644 index 00000000..3e830b5a --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/readme.md @@ -0,0 +1,126 @@ +## 升级中心 - app插件与 `uni-admin` 版本关系 + +### `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 diff --git a/uni_modules/uni-upgrade-center-app/static/app_update_close.png b/uni_modules/uni-upgrade-center-app/static/app_update_close.png new file mode 100644 index 0000000000000000000000000000000000000000..8b2ffe62cba2466f184ea9f8ee4f9395ed8cf37a GIT binary patch literal 7644 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 U2>e_sb7~9VO{|RT486$z2cgKqd;kCd literal 0 HcmV?d00001 diff --git a/uni_modules/uni-upgrade-center-app/static/bg_top.png b/uni_modules/uni-upgrade-center-app/static/bg_top.png new file mode 100644 index 0000000000000000000000000000000000000000..015f698cdd8c8caa63486a2bd87f5a96f17df630 GIT binary patch literal 30486 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/uniCloud/database/db_init.json @@ -0,0 +1 @@ +{} diff --git a/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts b/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts new file mode 100644 index 00000000..0419e889 --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/call-check-version.ts @@ -0,0 +1,109 @@ +export type StoreListItem = { + enable : boolean + id : string + name : string + scheme : string + priority : number // 优先级 +} + +export type UniUpgradeCenterResult = { + _id : string + appid : string + name : string + title : string + contents : string + url : string // 安装包下载地址 + platform : Array // Array<'Android' | 'iOS'> + version : string // 版本号 1.0.0 + uni_platform : string // "android" | "ios" // 版本号 1.0.0 + stable_publish : boolean // 是否是稳定版 + is_mandatory : boolean // 是否强制更新 + is_silently : boolean // 是否静默更新 + create_env : string // "upgrade-center" + create_date : number + message : string + code : number + + type : string // "native_app" | "wgt" + store_list : StoreListItem[] | null + min_uni_version : string | null // 升级 wgt 的最低 uni-app 版本 +} + +export default function (): Promise { + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + const systemInfo = uni.getSystemInfoSync() + const appId = systemInfo.appId + const appVersion = systemInfo.appVersion + // #ifndef UNI-APP-X + if (plus.runtime.appid && plus.runtime.version) { + plus.runtime.getProperty(plus.runtime.appid, function (widgetInfo) { + if (widgetInfo.version) { + let data = { + action: 'checkVersion', + appid: plus.runtime.appid, + appVersion: plus.runtime.version, + wgtVersion: widgetInfo.version + } + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data: data, + success: (e) => { + resolve(e.result as UniUpgradeCenterResult) + }, + fail: (error) => { + reject(error) + } + }) + } else { + reject('widgetInfo.version is EMPTY') + } + }) + } else { + reject('plus.runtime.appid is EMPTY') + } + // #endif + // // #ifdef UNI-APP-X + if (typeof appId === 'string' && typeof appVersion === 'string' && appId.length > 0 && appVersion.length > 0) { + let data = { + action: 'checkVersion', + appid: appId, + appVersion: appVersion, + wgtVersion: '0.0.0.0.0.1' + } + try { + uniCloud.callFunction({ + name: 'uni-upgrade-center', + data: data + }).then(res => { + const result = JSON.parse(JSON.stringify(res.result)) + if (result === null ){ + reject({ + code: res.result['code'], + message: res.result['message'] + }) + } else { + resolve(result) + } + }).catch((err : any | null) => { + console.log('err: ', err); + const error = err as UniCloudError + reject(error.errMsg) + }) + } catch (e) { + reject(e.message) + } + } else { + reject('plus.runtime.appid is EMPTY') + } + // #endif + }) + // #endif + // #ifndef APP-PLUS + /* return new Promise((resolve, reject) => { + reject({ + message: '请在App中使用' + }) + }) */ + // #endif +} diff --git a/uni_modules/uni-upgrade-center-app/utils/check-update.ts b/uni_modules/uni-upgrade-center-app/utils/check-update.ts new file mode 100644 index 00000000..16fdc9dd --- /dev/null +++ b/uni_modules/uni-upgrade-center-app/utils/check-update.ts @@ -0,0 +1,206 @@ +import callCheckVersion, { UniUpgradeCenterResult } from "./call-check-version" +// #ifdef UNI-APP-X +import { ComponentPublicInstance } from 'vue' +// #endif + +// 推荐再App.vue中使用 +const PACKAGE_INFO_KEY = '__package_info__' +// #ifdef UNI-APP-X +export default function (component : ComponentPublicInstance | null = null) : Promise { +// #endif +// #ifndef UNI-APP-X +export default function () : Promise { +// #endif + // #ifdef APP-PLUS + return new Promise((resolve, reject) => { + callCheckVersion().then(async (uniUpgradeCenterResult) => { + // NOTE uni-app x 3.96 解构有问题 + const code = uniUpgradeCenterResult.code + const message = uniUpgradeCenterResult.message + const url = uniUpgradeCenterResult.url // 安装包下载地址 + // const is_silently = uniUpgradeCenterResult.is_silently // 是否静默更新 + // const platform = uniUpgradeCenterResult.platform // 安装包平台 + // const type = uniUpgradeCenterResult.type // 安装包类型 + + // 此处逻辑仅为实例,可自行编写 + if (code > 0) { + // 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回 + const tcbRes = await uniCloud.getTempFileURL({ fileList: [url] }); + if (typeof tcbRes.fileList[0].tempFileURL !== 'undefined') uniUpgradeCenterResult.url = tcbRes.fileList[0].tempFileURL; + + /** + * 提示升级一 + * 使用 uni.showModal + */ + // return updateUseModal(uniUpgradeCenterResult) + + /** + * 提示升级二 + * 官方适配的升级弹窗,可自行替换资源适配UI风格 + */ + // #ifndef UNI-APP-X + uni.setStorageSync(PACKAGE_INFO_KEY, uniUpgradeCenterResult) + uni.navigateTo({ + url: `/uni_modules/uni-upgrade-center-app/pages/upgrade-popup?local_storage_key=${PACKAGE_INFO_KEY}`, + fail: (err) => { + console.error('更新弹框跳转失败', err) + uni.removeStorageSync(PACKAGE_INFO_KEY) + } + }) + // #endif + // #ifdef UNI-APP-X + component?.$callMethod('show', true, uniUpgradeCenterResult) + // #endif + + return resolve(uniUpgradeCenterResult) + } else if (code < 0) { + // TODO 云函数报错处理 + console.error(message) + return reject(uniUpgradeCenterResult) + } + return resolve(uniUpgradeCenterResult) + }).catch((err) => { + // TODO 云函数报错处理 + console.error(err) + reject(err) + }) + }); + // #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 升级 + */ +function updateUseModal(packageInfo : UniUpgradeCenterResult) : void { + const { + title, // 标题 + contents, // 升级内容 + is_mandatory, // 是否强制更新 + url, // 安装包下载地址 + platform, // 安装包平台 + type // 安装包类型 + } = packageInfo; + + let isWGT = type === 'wgt' + let isiOS = !isWGT ? platform.includes('iOS') : false; + let confirmText = isiOS ? '立即跳转更新' : '立即下载更新' + + return uni.showModal({ + title, + content: contents, + showCancel: !is_mandatory, + confirmText, + success: res => { + if (res.cancel) return; + + // 安装包下载 + if (isiOS) { + plus.runtime.openURL(url); + return; + } + + uni.showToast({ + title: '后台下载中……', + duration: 1000 + }); + + // wgt 和 安卓下载更新 + uni.downloadFile({ + url, + success: res => { + if (res.statusCode !== 200) { + console.error('下载安装包失败'); + return; + } + // 下载好直接安装,下次启动生效 + plus.runtime.install(res.tempFilePath, { + force: false + }, () => { + if (is_mandatory) { + //更新完重启app + plus.runtime.restart(); + return; + } + uni.showModal({ + title: '安装成功是否重启?', + success: res => { + if (res.confirm) { + //更新完重启app + plus.runtime.restart(); + } + } + }); + }, err => { + uni.showModal({ + title: '更新失败', + content: err + .message, + showCancel: false + }); + }); + } + }); + } + }); +} +// #endif \ No newline at end of file -- GitLab