diff --git a/pages/tabBar/component.uvue b/pages/tabBar/component.uvue index a2cf74fa095650350340069a4903ce39771523aa..0ea1d1fe8a96210e11076ce015344c30e6fadd91 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 0000000000000000000000000000000000000000..21a54c451df9770bc47b6dac793b829c3a17d04a --- /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 0000000000000000000000000000000000000000..f2750d5c4fb439ad0dbd3a8e48ee3a17f39ced36 --- /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 0000000000000000000000000000000000000000..f17da29291d0f2b0d7df616e6ce8ef7104f943a3 --- /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 0000000000000000000000000000000000000000..ab7866025f38998955ea2c8e875f2d9d710dc4c0 --- /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 0000000000000000000000000000000000000000..3e830b5acf2e6744239e1fba529e50265533683f --- /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 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/static/app_update_close.png differ 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 Binary files /dev/null and b/uni_modules/uni-upgrade-center-app/static/bg_top.png differ 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 0000000000000000000000000000000000000000..0967ef424bce6791893e9a57bb952f80fd536e93 --- /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 0000000000000000000000000000000000000000..0419e889cc894c6eacdcc87f831cd7f102c5c931 --- /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 0000000000000000000000000000000000000000..16fdc9dd58b48e339e88174ac9ce03c1a5fdbefa --- /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