29 changed files with 1891 additions and 73 deletions
@ -0,0 +1,4 @@ |
|||
## 0.0.2(2021-04-16) |
|||
- 修改插件package信息 |
|||
## 0.0.1(2021-03-15) |
|||
- 初始化项目 |
@ -0,0 +1,80 @@ |
|||
{ |
|||
"id": "uni-config-center", |
|||
"displayName": "uni-config-center", |
|||
"version": "0.0.2", |
|||
"description": "uniCloud 配置中心", |
|||
"keywords": [ |
|||
"配置", |
|||
"配置中心" |
|||
], |
|||
"repository": "", |
|||
"engines": { |
|||
"HBuilderX": "^3.1.0" |
|||
}, |
|||
"dcloudext": { |
|||
"category": [ |
|||
"uniCloud", |
|||
"云函数模板" |
|||
], |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "无", |
|||
"permissions": "无" |
|||
}, |
|||
"npmurl": "" |
|||
}, |
|||
"directories": { |
|||
"example": "../../../scripts/dist" |
|||
}, |
|||
"uni_modules": { |
|||
"dependencies": [], |
|||
"encrypt": [], |
|||
"platforms": { |
|||
"cloud": { |
|||
"tcb": "y", |
|||
"aliyun": "y" |
|||
}, |
|||
"client": { |
|||
"App": { |
|||
"app-vue": "u", |
|||
"app-nvue": "u" |
|||
}, |
|||
"H5-mobile": { |
|||
"Safari": "u", |
|||
"Android Browser": "u", |
|||
"微信浏览器(Android)": "u", |
|||
"QQ浏览器(Android)": "u" |
|||
}, |
|||
"H5-pc": { |
|||
"Chrome": "u", |
|||
"IE": "u", |
|||
"Edge": "u", |
|||
"Firefox": "u", |
|||
"Safari": "u" |
|||
}, |
|||
"小程序": { |
|||
"微信": "u", |
|||
"阿里": "u", |
|||
"百度": "u", |
|||
"字节跳动": "u", |
|||
"QQ": "u" |
|||
}, |
|||
"快应用": { |
|||
"华为": "u", |
|||
"联盟": "u" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,93 @@ |
|||
# 为什么使用uni-config-center |
|||
|
|||
实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构 |
|||
|
|||
```bash |
|||
cloudfunctions |
|||
└─────common 公共模块 |
|||
├─plugin-a // 插件A对应的目录 |
|||
│ ├─index.js |
|||
│ ├─config.json // plugin-a对应的配置文件 |
|||
│ └─other-file.cert // plugin-a依赖的其他文件 |
|||
└─plugin-b // plugin-b对应的目录 |
|||
├─index.js |
|||
└─config.json // plugin-b对应的配置文件 |
|||
``` |
|||
|
|||
假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。 |
|||
|
|||
uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下 |
|||
|
|||
```bash |
|||
cloudfunctions |
|||
└─────common 公共模块 |
|||
├─plugin-a // 插件A对应的目录 |
|||
│ └─index.js |
|||
├─plugin-b // plugin-b对应的目录 |
|||
│ └─index.js |
|||
└─uni-config-center |
|||
├─index.js // config-center入口文件 |
|||
├─plugin-a |
|||
│ ├─config.json // plugin-a对应的配置文件 |
|||
│ └─other-file.cert // plugin-a依赖的其他文件 |
|||
└─plugin-b |
|||
└─config.json // plugin-b对应的配置文件 |
|||
``` |
|||
|
|||
使用uni-config-center后的优势 |
|||
|
|||
- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便 |
|||
- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持) |
|||
|
|||
# 用法 |
|||
|
|||
在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common) |
|||
|
|||
```js |
|||
const createConfig = require('uni-config-center') |
|||
|
|||
const uniIdConfig = createConfig({ |
|||
pluginId: 'uni-id', // 插件id |
|||
defaultConfig: { // 默认配置 |
|||
tokenExpiresIn: 7200, |
|||
tokenExpiresThreshold: 600, |
|||
}, |
|||
customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并 |
|||
// defaudltConfig 默认配置 |
|||
// userConfig 用户配置 |
|||
return Object.assign(defaultConfig, userConfig) |
|||
} |
|||
}) |
|||
|
|||
|
|||
// 以如下配置为例 |
|||
// { |
|||
// "tokenExpiresIn": 7200, |
|||
// "passwordErrorLimit": 6, |
|||
// "bindTokenToDevice": false, |
|||
// "passwordErrorRetryTime": 3600, |
|||
// "app-plus": { |
|||
// "tokenExpiresIn": 2592000 |
|||
// }, |
|||
// "service": { |
|||
// "sms": { |
|||
// "codeExpiresIn": 300 |
|||
// } |
|||
// } |
|||
// } |
|||
|
|||
// 获取配置 |
|||
uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象 |
|||
uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200 |
|||
uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300 |
|||
uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600 |
|||
|
|||
// 获取文件绝对路径 |
|||
uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径 |
|||
|
|||
// 引用文件(require) |
|||
uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。 |
|||
|
|||
// 判断是否包含某文件 |
|||
uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在 |
|||
``` |
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@ |
|||
{ |
|||
"name": "uni-config-center", |
|||
"version": "0.0.2", |
|||
"description": "配置中心", |
|||
"main": "index.js", |
|||
"keywords": [], |
|||
"author": "DCloud", |
|||
"license": "Apache-2.0" |
|||
} |
@ -0,0 +1,72 @@ |
|||
## 3.3.12(2022-01-15) |
|||
- 新增 preferedAppPlatform 配置用于解决uni-app vue2版本vue3版本获取platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-app-platform) |
|||
- 修复 checkToken 未返回自定义token内容的Bug |
|||
## 3.3.11(2022-01-11) |
|||
- 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug |
|||
## 3.3.10(2022-01-07) |
|||
- 新增 自定义国际化语言支持 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=custom-i8n) |
|||
- 修复 一键登录时未校验重复手机号是否已验证的Bug |
|||
- 修复 Apple登录时用户邮箱为空时报错的Bug |
|||
- 修复 登录接口未传username时错误提示不正确的Bug |
|||
## 3.3.9(2021-11-09) |
|||
- 去除重复的context.xxx未找到的提示语 |
|||
## 3.3.8(2021-10-28) |
|||
- 新增 用户账户封禁接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=ban-account) |
|||
- 新增 用户账户注销接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=close-account) |
|||
- 修复 未传appid时用户重复注册的Bug |
|||
## 3.3.7(2021-10-08) |
|||
- 移除部分接口的废弃提示 |
|||
## 3.3.6(2021-09-08) |
|||
- 修复 邀请码可能重复的Bug |
|||
## 3.3.5(2021-08-10) |
|||
- 修复版本号错误 |
|||
## 3.3.4(2021-08-10) |
|||
- 微信、QQ、支付宝登录新增type参数用于指定当前是登录还是注册 |
|||
## 3.3.3(2021-08-04) |
|||
- 修复使用数组形式的配置文件报错的Bug |
|||
## 3.3.2(2021-08-03) |
|||
- 修复上3.3.0版本引出的createInstance接口传入配置不生效的Bug 感谢[hmh](https://gitee.com/hmh) |
|||
## 3.3.1(2021-07-30) |
|||
- 修复 将设置用户允许登录的应用列表时传入空数组报错的Bug |
|||
## 3.3.0(2021-07-30) |
|||
- 新增 不同端应用配置隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config) |
|||
- 新增 不同端用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user) |
|||
+ 此版本升级需要开发者处理一下用户数据,请参考 [补齐用户dcloud_appid字段](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=makeup-dcloud-appid) |
|||
- 新增 QQ登录、注册相关功能 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=qq) |
|||
- 调整 不再支持绑定手机、邮箱时不填验证码直接绑定 |
|||
## 3.2.1(2021-07-09) |
|||
- 撤销3.2.0版本所做的调整 |
|||
## 3.2.0(2021-07-09) |
|||
- 【重要】支持不同端(管理端、用户端等)用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user) |
|||
- 支持不同端(管理端、用户端等)配置文件隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config) |
|||
## 3.1.3(2021-07-08) |
|||
- 移除插件内误传的node_modules |
|||
## 3.1.2(2021-07-08) |
|||
- 修复 微信小程序绑定微信账号时报错的Bug |
|||
## 3.1.1(2021-07-01) |
|||
- 使用新的错误码规范,兼容旧版 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=errcode) |
|||
- 修复微信登录、绑定时未返回用户accessToken的Bug |
|||
## 3.1.0(2021-04-19) |
|||
- 增加对用户名、邮箱、密码字段的两端去空格 |
|||
- 默认忽略用户名、邮箱的大小写 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=case-sensitive) |
|||
- 修复 customToken导出async方法报错的Bug |
|||
## 3.0.12(2021-04-13) |
|||
- 调整bindTokenToDevice默认值为false |
|||
## 3.0.11(2021-04-12) |
|||
- 修复3.0.7版本引出的多个用户访问时可能出现30201报错的Bug |
|||
## 3.0.10(2021-04-08) |
|||
- 优化错误提示 |
|||
## 3.0.9(2021-04-08) |
|||
- bindMobile接口支持通过一键登录的方式绑定 |
|||
- 优化错误提示 |
|||
## 3.0.8(2021-03-19) |
|||
- 修复 3.0.7版本某些情况下生成token报错的Bug |
|||
## 3.0.7(2021-03-19) |
|||
- 新增 支持uni-config-center,更新uni-id无须再担心配置被覆盖 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=uni-config-center) |
|||
- 新增 自定义token内容,可以缓存角色权限之外的更多信息到客户端 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=custom-token) |
|||
- 新增 支持传入context获取uni-id实例,防止单实例多并发时全局context混乱 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=create-instance) |
|||
## 3.0.6(2021-03-05) |
|||
- 新增[uniID.wxBizDataCrypt](https://uniapp.dcloud.io/uniCloud/uni-id?id=%e5%be%ae%e4%bf%a1%e6%95%b0%e6%8d%ae%e8%a7%a3%e5%af%86)方法 |
|||
- 优化loginByApple方法,提高接口响应速度 |
|||
## 3.0.5(2021-02-03) |
|||
- 调整为uni_modules目录规范 |
@ -0,0 +1,84 @@ |
|||
{ |
|||
"id": "uni-id", |
|||
"displayName": "uni-id", |
|||
"version": "3.3.12", |
|||
"description": "简单、统一、可扩展的用户中心", |
|||
"keywords": [ |
|||
"uniid", |
|||
"uni-id", |
|||
"用户管理", |
|||
"用户中心", |
|||
"短信验证码" |
|||
], |
|||
"repository": "https://gitee.com/dcloud/uni-id.git", |
|||
"engines": { |
|||
"HBuilderX": "^3.1.0" |
|||
}, |
|||
"dcloudext": { |
|||
"category": [ |
|||
"uniCloud", |
|||
"云函数模板" |
|||
], |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "无", |
|||
"permissions": "无" |
|||
}, |
|||
"npmurl": "" |
|||
}, |
|||
"uni_modules": { |
|||
"dependencies": ["uni-config-center"], |
|||
"encrypt": [], |
|||
"platforms": { |
|||
"cloud": { |
|||
"tcb": "y", |
|||
"aliyun": "y" |
|||
}, |
|||
"client": { |
|||
"App": { |
|||
"app-vue": "u", |
|||
"app-nvue": "u" |
|||
}, |
|||
"H5-mobile": { |
|||
"Safari": "u", |
|||
"Android Browser": "u", |
|||
"微信浏览器(Android)": "u", |
|||
"QQ浏览器(Android)": "u" |
|||
}, |
|||
"H5-pc": { |
|||
"Chrome": "u", |
|||
"IE": "u", |
|||
"Edge": "u", |
|||
"Firefox": "u", |
|||
"Safari": "u" |
|||
}, |
|||
"小程序": { |
|||
"微信": "u", |
|||
"阿里": "u", |
|||
"百度": "u", |
|||
"字节跳动": "u", |
|||
"QQ": "u" |
|||
}, |
|||
"快应用": { |
|||
"华为": "u", |
|||
"联盟": "u" |
|||
}, |
|||
"Vue": { |
|||
"vue2": "y", |
|||
"vue3": "u" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,33 @@ |
|||
**文档已移至[uni-id文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id)** |
|||
|
|||
> 一般uni-id升级大版本时为不兼容更新,从低版本迁移到高版本请参考:[uni-id迁移指南](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=migration) |
|||
|
|||
## 重要升级说明 |
|||
|
|||
**uni-id 3.x版本,搭配的uniCloud admin版本需大于1.2.10。** |
|||
|
|||
### 缓存角色权限 |
|||
|
|||
自`uni-id 3.0.0`起,支持在token内缓存用户的角色权限,默认开启此功能,各登录接口的needPermission参数不再生效。如需关闭请在config内配置`"removePermissionAndRoleFromToken": true`。 |
|||
|
|||
为什么要缓存角色权限?要知道云数据库是按照读写次数来收取费用的,并且读写数据库会拖慢接口响应速度。未配置`"removePermissionAndRoleFromToken": true`的情况下,可以在调用checkToken接口时不查询数据库获取用户角色权限。 |
|||
|
|||
详细checkToken流程如下: |
|||
|
|||
 |
|||
|
|||
可以看出,旧版token(removePermissionAndRoleFromToken为true时生成的)在checkToken时如需返回权限需要进行两次数据库查询。新版token不需要查库即可返回权限信息。 |
|||
|
|||
**注意** |
|||
|
|||
- 由于角色权限缓存在token内,可能会存在权限已经更新但是用户token未过期之前依然是旧版角色权限的情况。可以调短一些token过期时间来减少这种情况的影响。 |
|||
- admin角色token内不包含permission,如需自行判断用户是否有某个权限,要注意admin角色需要额外判断一下,写法如下 |
|||
```js |
|||
const { |
|||
role, |
|||
permission |
|||
} = await uniID.checkToken(event.uniIdToken) |
|||
if(role.includes('admin') || permission.includes('your permission id')) { |
|||
// 当前角色拥有'your permission id'对应的权限 |
|||
} |
|||
``` |
@ -0,0 +1,201 @@ |
|||
Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
APPENDIX: How to apply the Apache License to your work. |
|||
|
|||
To apply the Apache License to your work, attach the following |
|||
boilerplate notice, with the fields enclosed by brackets "[]" |
|||
replaced with your own identifying information. (Don't include |
|||
the brackets!) The text should be enclosed in the appropriate |
|||
comment syntax for the file format. We also recommend that a |
|||
file or class name and description of purpose be included on the |
|||
same "printed page" as the copyright notice for easier |
|||
identification within third-party archives. |
|||
|
|||
Copyright [yyyy] [name of copyright owner] |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
File diff suppressed because one or more lines are too long
@ -0,0 +1,16 @@ |
|||
{ |
|||
"name": "uni-id", |
|||
"version": "3.3.12", |
|||
"description": "uni-id for uniCloud", |
|||
"main": "index.js", |
|||
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git+https://gitee.com/dcloud/uni-id.git" |
|||
}, |
|||
"author": "", |
|||
"license": "Apache-2.0", |
|||
"dependencies": { |
|||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
## 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) |
|||
- 升级中心前台检查更新 |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,83 @@ |
|||
{ |
|||
"id": "uni-upgrade-center-app", |
|||
"displayName": "升级中心 uni-upgrade-center - App", |
|||
"version": "0.3.2", |
|||
"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.1.0" |
|||
}, |
|||
"dcloudext": { |
|||
"category": [ |
|||
"uniCloud", |
|||
"云端一体页面模板" |
|||
], |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "插件不采集任何数据", |
|||
"permissions": "无" |
|||
}, |
|||
"npmurl": "" |
|||
}, |
|||
"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" |
|||
}, |
|||
"Vue": { |
|||
"vue2": "y", |
|||
"vue3": "y" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,500 @@ |
|||
<template> |
|||
<view class="mask flex-center"> |
|||
<view class="content botton-radius"> |
|||
<view class="content-top"> |
|||
<text class="content-top-text">{{title}}</text> |
|||
<image class="content-top" style="top: 0;" width="100%" height="100%" src="../images/bg_top.png"> |
|||
</image> |
|||
</view> |
|||
<view class="content-header"></view> |
|||
<view class="content-body"> |
|||
<view class="title"> |
|||
<text>{{subTitle}}</text> |
|||
<!-- <text style="padding-left:20rpx;font-size: 0.5em;color: #666;">v.{{version}}</text> --> |
|||
</view> |
|||
<view class="body"> |
|||
<scroll-view class="box-des-scroll" scroll-y="true"> |
|||
<text class="box-des"> |
|||
{{contents}} |
|||
</text> |
|||
</scroll-view> |
|||
</view> |
|||
<view class="footer flex-center"> |
|||
<template v-if="isiOS"> |
|||
<button class="content-button" style="border: none;color: #fff;" plain @click="jumpToAppStore"> |
|||
{{downLoadBtnTextiOS}} |
|||
</button> |
|||
</template> |
|||
<template v-else> |
|||
<template v-if="!downloadSuccess"> |
|||
<view class="progress-box flex-column" v-if="downloading"> |
|||
<progress class="progress" border-radius="35" :percent="downLoadPercent" |
|||
activeColor="#3DA7FF" show-info stroke-width="10" /> |
|||
<view style="width:100%;font-size: 28rpx;display: flex;justify-content: space-around;"> |
|||
<text>{{downLoadingText}}</text> |
|||
<text>({{downloadedSize}}/{{packageFileSize}}M)</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<button v-else class="content-button" style="border: none;color: #fff;" plain |
|||
@click="downloadPackage"> |
|||
{{downLoadBtnText}} |
|||
</button> |
|||
</template> |
|||
<button v-else-if="downloadSuccess && !installed" class="content-button" |
|||
style="border: none;color: #fff;" plain :loading="installing" :disabled="installing" |
|||
@click="installPackage"> |
|||
{{installing ? '正在安装……' : '下载完成,立即安装'}} |
|||
</button> |
|||
|
|||
<button v-if="installed && isWGT" class="content-button" style="border: none;color: #fff;" plain |
|||
@click="restart"> |
|||
安装完毕,点击重启 |
|||
</button> |
|||
</template> |
|||
</view> |
|||
</view> |
|||
|
|||
<image v-if="!is_mandatory" class="close-img" src="../images/app_update_close.png" |
|||
@click.stop="closeUpdate"></image> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
const localFilePathKey = '__localFilePath__' |
|||
const platform_iOS = 'iOS'; |
|||
let downloadTask = null; |
|||
|
|||
/** |
|||
* 对比版本号,如需要,请自行修改判断规则 |
|||
* 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 |
|||
* @param {Object} v1 |
|||
* @param {Object} v2 |
|||
* v1 > v2 return 1 |
|||
* v1 < v2 return -1 |
|||
* v1 == v2 return 0 |
|||
*/ |
|||
function compare(v1 = '0', v2 = '0') { |
|||
v1 = String(v1).split('.') |
|||
v2 = String(v2).split('.') |
|||
const minVersionLens = Math.min(v1.length, v2.length); |
|||
|
|||
let result = 0; |
|||
for (let i = 0; i < minVersionLens; i++) { |
|||
const curV1 = Number(v1[i]) |
|||
const curV2 = Number(v2[i]) |
|||
|
|||
if (curV1 > curV2) { |
|||
result = 1 |
|||
break; |
|||
} else if(curV1 < curV2) { |
|||
result = -1 |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (result === 0 && (v1.length !== v2.length)) { |
|||
const v1BiggerThenv2 = v1.length > v2.length; |
|||
const maxLensVersion = v1BiggerThenv2 ? v1 : v2; |
|||
for (let i = minVersionLens; i < maxLensVersion.length; i++) { |
|||
const curVersion = Number(maxLensVersion[i]) |
|||
if (curVersion > 0) { |
|||
v1BiggerThenv2 ? result = 1 : result = -1 |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
// 从之前下载安装 |
|||
installForBeforeFilePath: '', |
|||
|
|||
// 安装 |
|||
installed: false, |
|||
installing: false, |
|||
|
|||
// 下载 |
|||
downloadSuccess: false, |
|||
downloading: false, |
|||
|
|||
downLoadPercent: 0, |
|||
downloadedSize: 0, |
|||
packageFileSize: 0, |
|||
|
|||
tempFilePath: '', // 要安装的本地包地址 |
|||
|
|||
// 默认安装包信息 |
|||
title: '更新日志', |
|||
contents: '', |
|||
is_mandatory: false, |
|||
|
|||
// 可自定义属性 |
|||
subTitle: '发现新版本', |
|||
downLoadBtnTextiOS: '立即跳转更新', |
|||
downLoadBtnText: '立即下载更新', |
|||
downLoadingText: '安装包下载中,请稍后' |
|||
} |
|||
}, |
|||
onLoad({ |
|||
local_storage_key |
|||
}) { |
|||
if (!local_storage_key) { |
|||
console.error('local_storage_key为空,请检查后重试') |
|||
uni.navigateBack() |
|||
return; |
|||
}; |
|||
|
|||
const localPackageInfo = uni.getStorageSync(local_storage_key); |
|||
if (!localPackageInfo) { |
|||
console.error('安装包信息为空,请检查后重试') |
|||
uni.navigateBack() |
|||
return; |
|||
}; |
|||
|
|||
const requiredKey = ['version', 'url', 'type'] |
|||
for (let key in localPackageInfo) { |
|||
if (requiredKey.indexOf(key) !== -1 && !localPackageInfo[key]) { |
|||
console.error(`参数 ${key} 必填,请检查后重试`) |
|||
uni.navigateBack() |
|||
return; |
|||
} |
|||
} |
|||
|
|||
Object.assign(this, localPackageInfo) |
|||
this.checkLocalStoragePackage() |
|||
}, |
|||
onBackPress() { |
|||
// 强制更新不允许返回 |
|||
if (this.is_mandatory) { |
|||
return true |
|||
} |
|||
|
|||
downloadTask && downloadTask.abort() |
|||
}, |
|||
computed: { |
|||
isWGT() { |
|||
return this.type === 'wgt' |
|||
}, |
|||
isiOS() { |
|||
return !this.isWGT ? this.platform.includes(platform_iOS) : false; |
|||
} |
|||
}, |
|||
methods: { |
|||
checkLocalStoragePackage() { |
|||
// 如果已经有下载好的包,则直接提示安装 |
|||
const localFilePathRecord = uni.getStorageSync(localFilePathKey) |
|||
if (localFilePathRecord) { |
|||
const { |
|||
version, |
|||
savedFilePath, |
|||
installed |
|||
} = localFilePathRecord |
|||
|
|||
// 比对版本 |
|||
if (!installed && compare(version, this.version) === 0) { |
|||
this.downloadSuccess = true; |
|||
this.installForBeforeFilePath = savedFilePath; |
|||
this.tempFilePath = savedFilePath |
|||
} else { |
|||
// 如果保存的包版本小 或 已安装过,则直接删除 |
|||
this.deleteSavedFile(savedFilePath) |
|||
} |
|||
} |
|||
}, |
|||
async closeUpdate() { |
|||
if (this.downloading) { |
|||
if (this.is_mandatory) { |
|||
return uni.showToast({ |
|||
title: '下载中,请稍后……', |
|||
icon: 'none', |
|||
duration: 500 |
|||
}) |
|||
} |
|||
uni.showModal({ |
|||
title: '是否取消下载?', |
|||
cancelText: '否', |
|||
confirmText: '是', |
|||
success: res => { |
|||
if (res.confirm) { |
|||
downloadTask && downloadTask.abort() |
|||
uni.navigateBack() |
|||
} |
|||
} |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
if (this.downloadSuccess && this.tempFilePath) { |
|||
// 包已经下载完毕,稍后安装,将包保存在本地 |
|||
await this.saveFile(this.tempFilePath, this.version) |
|||
uni.navigateBack() |
|||
return; |
|||
} |
|||
|
|||
uni.navigateBack() |
|||
}, |
|||
downloadPackage() { |
|||
this.downloading = true; |
|||
|
|||
//下载包 |
|||
downloadTask = uni.downloadFile({ |
|||
url: this.url, |
|||
success: res => { |
|||
if (res.statusCode == 200) { |
|||
this.downloadSuccess = true; |
|||
this.tempFilePath = res.tempFilePath |
|||
|
|||
// 强制更新,直接安装 |
|||
if (this.is_mandatory) { |
|||
this.installPackage(); |
|||
} |
|||
} |
|||
}, |
|||
complete: () => { |
|||
this.downloading = false; |
|||
|
|||
this.downLoadPercent = 0 |
|||
this.downloadedSize = 0 |
|||
this.packageFileSize = 0 |
|||
|
|||
downloadTask = null; |
|||
} |
|||
}); |
|||
|
|||
downloadTask.onProgressUpdate(res => { |
|||
this.downLoadPercent = res.progress; |
|||
this.downloadedSize = (res.totalBytesWritten / Math.pow(1024, 2)).toFixed(2); |
|||
this.packageFileSize = (res.totalBytesExpectedToWrite / Math.pow(1024, 2)).toFixed(2); |
|||
}); |
|||
}, |
|||
installPackage() { |
|||
// #ifdef APP-PLUS |
|||
// wgt资源包安装 |
|||
if (this.isWGT) { |
|||
this.installing = true; |
|||
} |
|||
|
|||
plus.runtime.install(this.tempFilePath, { |
|||
force: false |
|||
}, async res => { |
|||
this.installing = false; |
|||
this.installed = true; |
|||
|
|||
// wgt包,安装后会提示 安装成功,是否重启 |
|||
if (this.isWGT) { |
|||
// 强制更新安装完成重启 |
|||
if (this.is_mandatory) { |
|||
uni.showLoading({ |
|||
icon: 'none', |
|||
title: '安装成功,正在重启……' |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
uni.hideLoading() |
|||
this.restart(); |
|||
}, 1000) |
|||
} |
|||
} else { |
|||
const localFilePathRecord = uni.getStorageSync(localFilePathKey) |
|||
uni.setStorageSync(localFilePathKey, { |
|||
...localFilePathRecord, |
|||
installed: true |
|||
}) |
|||
} |
|||
}, async err => { |
|||
// 如果是安装之前的包,安装失败后删除之前的包 |
|||
if (this.installForBeforeFilePath) { |
|||
await this.deleteSavedFile(this.installForBeforeFilePath) |
|||
this.installForBeforeFilePath = ''; |
|||
} |
|||
|
|||
// 安装失败需要重新下载安装包 |
|||
this.installing = false; |
|||
this.installed = false; |
|||
|
|||
uni.showModal({ |
|||
title: `更新失败${this.isWGT ? '' : ',APK文件不存在'},请重新下载`, |
|||
content: err.message, |
|||
showCancel: false |
|||
}); |
|||
}); |
|||
|
|||
// 非wgt包,安装跳出覆盖安装,此处直接返回上一页 |
|||
if (!this.isWGT) { |
|||
uni.navigateBack() |
|||
} |
|||
// #endif |
|||
}, |
|||
restart() { |
|||
this.installed = false; |
|||
// #ifdef APP-PLUS |
|||
//更新完重启app |
|||
plus.runtime.restart(); |
|||
// #endif |
|||
}, |
|||
async saveFile(tempFilePath, version) { |
|||
const [err, res] = await uni.saveFile({ |
|||
tempFilePath |
|||
}) |
|||
if (err) { |
|||
return; |
|||
} |
|||
uni.setStorageSync(localFilePathKey, { |
|||
version, |
|||
savedFilePath: res.savedFilePath |
|||
}) |
|||
}, |
|||
deleteSavedFile(filePath) { |
|||
uni.removeStorageSync(localFilePathKey) |
|||
return uni.removeSavedFile({ |
|||
filePath |
|||
}) |
|||
}, |
|||
jumpToAppStore() { |
|||
plus.runtime.openURL(this.url); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
page { |
|||
background: transparent; |
|||
} |
|||
|
|||
.flex-center { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.mask { |
|||
position: fixed; |
|||
left: 0; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: rgba(0, 0, 0, .65); |
|||
} |
|||
|
|||
.botton-radius { |
|||
border-bottom-left-radius: 30rpx; |
|||
border-bottom-right-radius: 30rpx; |
|||
} |
|||
|
|||
.content { |
|||
position: relative; |
|||
top: 0; |
|||
width: 600rpx; |
|||
background-color: #fff; |
|||
box-sizing: border-box; |
|||
padding: 0 50rpx; |
|||
font-family: Source Han Sans CN; |
|||
} |
|||
|
|||
.text { |
|||
/* #ifndef APP-NVUE */ |
|||
display: block; |
|||
/* #endif */ |
|||
line-height: 200px; |
|||
text-align: center; |
|||
color: #FFFFFF; |
|||
} |
|||
|
|||
.content-top { |
|||
position: absolute; |
|||
top: -195rpx; |
|||
left: 0; |
|||
width: 600rpx; |
|||
height: 270rpx; |
|||
} |
|||
|
|||
.content-top-text { |
|||
font-size: 45rpx; |
|||
font-weight: bold; |
|||
color: #F8F8FA; |
|||
position: absolute; |
|||
top: 120rpx; |
|||
left: 50rpx; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.content-header { |
|||
height: 70rpx; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 33rpx; |
|||
font-weight: bold; |
|||
color: #3DA7FF; |
|||
line-height: 38px; |
|||
} |
|||
|
|||
.footer { |
|||
height: 150rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-around; |
|||
} |
|||
|
|||
.box-des-scroll { |
|||
box-sizing: border-box; |
|||
padding: 0 40rpx; |
|||
height: 200rpx; |
|||
text-align: left; |
|||
} |
|||
|
|||
.box-des { |
|||
font-size: 26rpx; |
|||
color: #000000; |
|||
line-height: 50rpx; |
|||
} |
|||
|
|||
.progress-box { |
|||
width: 100%; |
|||
} |
|||
|
|||
.progress { |
|||
width: 90%; |
|||
height: 40rpx; |
|||
border-radius: 35px; |
|||
} |
|||
|
|||
.close-img { |
|||
width: 70rpx; |
|||
height: 70rpx; |
|||
z-index: 1000; |
|||
position: absolute; |
|||
bottom: -120rpx; |
|||
left: calc(50% - 70rpx / 2); |
|||
} |
|||
|
|||
.content-button { |
|||
text-align: center; |
|||
flex: 1; |
|||
font-size: 30rpx; |
|||
font-weight: 400; |
|||
color: #FFFFFF; |
|||
border-radius: 40rpx; |
|||
margin: 0 18rpx; |
|||
|
|||
height: 80rpx; |
|||
line-height: 80rpx; |
|||
|
|||
background: linear-gradient(to right, #1785ff, #3DA7FF); |
|||
} |
|||
|
|||
.flex-column { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
</style> |
@ -0,0 +1,18 @@ |
|||
{ |
|||
"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 |
|||
|
|||
} |
|||
} |
|||
}] |
|||
} |
@ -0,0 +1,121 @@ |
|||
# uni-upgrade-center - App |
|||
|
|||
### 概述 |
|||
|
|||
> 统一管理App及App在`Android`、`iOS`平台上`App安装包`和`wgt资源包`的发布升级 |
|||
|
|||
> 本插件为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. 绑定一个服务空间 |
|||
|
|||
5. 找到`/uni_modules/uni-upgrade-center-app/uniCloud/cloudfunctions/check-version`,右键上传部署 |
|||
|
|||
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到需要用到的地方,调用一下即可 |
|||
|
|||
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|请检查传参是否填写正确| |
@ -0,0 +1,9 @@ |
|||
// 本文件中的json内容将在云函数【运行】时作为参数传给云函数。 |
|||
|
|||
// 配置教程参考:https://uniapp.dcloud.net.cn/uniCloud/quickstart?id=runparam |
|||
|
|||
{ |
|||
"appid": "__YOUR_APPID__", |
|||
"appVersion": "2.2.0", |
|||
"wgtVersion": "2.2.2" |
|||
} |
@ -0,0 +1,167 @@ |
|||
'use strict'; |
|||
exports.main = async (event, context) => { |
|||
/** |
|||
* 检测升级 使用说明 |
|||
* 上传包: |
|||
* 1. 根据传参,先检测传参是否完整,appid appVersion wgtVersion 必传 |
|||
* 2. 先从数据库取出所有该平台(从上下文读取平台信息,默认 Andriod)的所有线上发行更新 |
|||
* 3. 再从所有线上发行更新中取出版本最大的一版。如果可以,尽量先检测wgt的线上发行版更新 |
|||
* 4. 使用上步取出的版本包的版本号 和传参 appVersion、wgtVersion 来检测是否有更新,必须同时大于这两项,否则返回暂无更新 |
|||
* 5. 如果库中 wgt包 版本大于传参 appVersion,但是不满足 min_uni_version < appVersion,则不会使用wgt更新,会接着判断库中 app包version 是否大于 appVersion |
|||
*/ |
|||
|
|||
let { |
|||
appid, |
|||
appVersion, |
|||
wgtVersion, |
|||
} = event; |
|||
|
|||
const platform_Android = 'Android'; |
|||
const platform_iOS = 'iOS'; |
|||
const package_app = 'native_app'; |
|||
const package_wgt = 'wgt'; |
|||
const app_version_db_name = 'opendb-app-versions' |
|||
|
|||
let platform = platform_Android; |
|||
|
|||
// 云函数URL化请求
|
|||
if (event.headers) { |
|||
let body; |
|||
try { |
|||
if (event.httpMethod.toLocaleLowerCase() === 'get') { |
|||
body = event.queryStringParameters; |
|||
} else { |
|||
body = JSON.parse(event.body); |
|||
} |
|||
} catch (e) { |
|||
return { |
|||
code: 500, |
|||
msg: '请求错误' |
|||
}; |
|||
} |
|||
|
|||
appid = body.appid; |
|||
appVersion = body.appVersion; |
|||
wgtVersion = body.wgtVersion; |
|||
|
|||
platform = /iPhone|iPad/.test(event.headers) ? platform_iOS : platform_Android; |
|||
} else if (context.OS) { |
|||
platform = context.OS === 'android' |
|||
? platform_Android |
|||
: context.OS === 'ios' |
|||
? platform_iOS |
|||
: platform_Android; |
|||
} |
|||
|
|||
if (appid && appVersion && wgtVersion && platform) { |
|||
const collection = uniCloud.database().collection(app_version_db_name); |
|||
|
|||
const record = await collection.where({ |
|||
appid, |
|||
platform, |
|||
stable_publish: true |
|||
}) |
|||
.orderBy('create_date', 'desc') |
|||
.get(); |
|||
|
|||
if (record && record.data && record.data.length > 0) { |
|||
const appVersionInDb = record.data.find(item => item.type === package_app) || {}; |
|||
const wgtVersionInDb = record.data.find(item => item.type === package_wgt) || {}; |
|||
const hasAppPackage = !!Object.keys(appVersionInDb).length; |
|||
const hasWgtPackage = !!Object.keys(wgtVersionInDb).length; |
|||
|
|||
// 取两个版本中版本号最大的包,版本一样,使用wgt包
|
|||
let stablePublishDb = hasAppPackage |
|||
? hasWgtPackage |
|||
? compare(wgtVersionInDb.version, appVersionInDb.version) >= 0 |
|||
? wgtVersionInDb |
|||
: appVersionInDb |
|||
: appVersionInDb |
|||
: wgtVersionInDb; |
|||
|
|||
const { |
|||
version, |
|||
min_uni_version |
|||
} = stablePublishDb; |
|||
|
|||
// 库中的version必须满足同时大于appVersion和wgtVersion才行,因为上次更新可能是wgt更新
|
|||
const appUpdate = compare(version, appVersion) === 1; // app包可用更新
|
|||
const wgtUpdate = compare(version, wgtVersion) === 1; // wgt包可用更新
|
|||
|
|||
if (Object.keys(stablePublishDb).length && appUpdate && wgtUpdate) { |
|||
// 判断是否可用wgt更新
|
|||
if (min_uni_version && compare(min_uni_version, appVersion) < 1) { |
|||
return { |
|||
code: 101, |
|||
message: 'wgt更新', |
|||
...stablePublishDb |
|||
}; |
|||
} else if (hasAppPackage && compare(appVersionInDb.version, appVersion) === 1) { |
|||
return { |
|||
code: 102, |
|||
message: '整包更新', |
|||
...appVersionInDb |
|||
}; |
|||
} |
|||
} |
|||
|
|||
return { |
|||
code: 0, |
|||
message: '当前版本已经是最新的,不需要更新' |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
code: -101, |
|||
message: '暂无更新或检查appid是否填写正确' |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
code: -102, |
|||
message: '请检查传参是否填写正确' |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* 对比版本号,如需要,请自行修改判断规则 |
|||
* 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 |
|||
* @param {Object} v1 |
|||
* @param {Object} v2 |
|||
* v1 > v2 return 1 |
|||
* v1 < v2 return -1 |
|||
* v1 == v2 return 0 |
|||
*/ |
|||
function compare(v1 = '0', v2 = '0') { |
|||
v1 = String(v1).split('.') |
|||
v2 = String(v2).split('.') |
|||
const minVersionLens = Math.min(v1.length, v2.length); |
|||
|
|||
let result = 0; |
|||
for (let i = 0; i < minVersionLens; i++) { |
|||
const curV1 = Number(v1[i]) |
|||
const curV2 = Number(v2[i]) |
|||
|
|||
if (curV1 > curV2) { |
|||
result = 1 |
|||
break; |
|||
} else if(curV1 < curV2) { |
|||
result = -1 |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (result === 0 && (v1.length !== v2.length)) { |
|||
const v1BiggerThenv2 = v1.length > v2.length; |
|||
const maxLensVersion = v1BiggerThenv2 ? v1 : v2; |
|||
for (let i = minVersionLens; i < maxLensVersion.length; i++) { |
|||
const curVersion = Number(maxLensVersion[i]) |
|||
if (curVersion > 0) { |
|||
v1BiggerThenv2 ? result = 1 : result = -1 |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
@ -0,0 +1,29 @@ |
|||
export default function() { |
|||
// #ifdef APP-PLUS
|
|||
return new Promise((resolve, reject) => { |
|||
plus.runtime.getProperty(plus.runtime.appid, function(widgetInfo) { |
|||
uniCloud.callFunction({ |
|||
name: 'check-version', |
|||
data: { |
|||
appid: plus.runtime.appid, |
|||
appVersion: plus.runtime.version, |
|||
wgtVersion: widgetInfo.version |
|||
}, |
|||
success: (e) => { |
|||
resolve(e) |
|||
}, |
|||
fail: (error) => { |
|||
reject(error) |
|||
} |
|||
}) |
|||
}) |
|||
}) |
|||
// #endif
|
|||
// #ifndef APP-PLUS
|
|||
return new Promise((resolve, reject) => { |
|||
reject({ |
|||
message: '请在App中使用' |
|||
}) |
|||
}) |
|||
// #endif
|
|||
} |
@ -0,0 +1,155 @@ |
|||
import callCheckVersion from './call-check-version' |
|||
|
|||
// 推荐再App.vue中使用
|
|||
const PACKAGE_INFO_KEY = '__package_info__' |
|||
|
|||
export default function() { |
|||
// #ifdef APP-PLUS
|
|||
return new Promise((resolve, reject) => { |
|||
callCheckVersion().then(async (e) => { |
|||
if (!e.result) return; |
|||
const { |
|||
code, |
|||
message, |
|||
is_silently, // 是否静默更新
|
|||
url, // 安装包下载地址
|
|||
platform, // 安装包平台
|
|||
type // 安装包类型
|
|||
} = e.result; |
|||
|
|||
// 此处逻辑仅为实例,可自行编写
|
|||
if (code > 0) { |
|||
// 腾讯云和阿里云下载链接不同,需要处理一下,阿里云会原样返回
|
|||
const { |
|||
fileList |
|||
} = await uniCloud.getTempFileURL({ |
|||
fileList: [url] |
|||
}); |
|||
if (fileList[0].tempFileURL) |
|||
e.result.url = fileList[0].tempFileURL; |
|||
|
|||
resolve(e) |
|||
|
|||
// 静默更新,只有wgt有
|
|||
if (is_silently) { |
|||
uni.downloadFile({ |
|||
url: e.result.url, |
|||
success: res => { |
|||
if (res.statusCode == 200) { |
|||
// 下载好直接安装,下次启动生效
|
|||
plus.runtime.install(res.tempFilePath, { |
|||
force: false |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
/** |
|||
* 提示升级一 |
|||
* 使用 uni.showModal |
|||
*/ |
|||
// return updateUseModal(e.result)
|
|||
|
|||
/** |
|||
* 提示升级二 |
|||
* 官方适配的升级弹窗,可自行替换资源适配UI风格 |
|||
*/ |
|||
uni.setStorageSync(PACKAGE_INFO_KEY, e.result) |
|||
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) |
|||
} |
|||
}) |
|||
} else if (code < 0) { |
|||
// TODO 云函数报错处理
|
|||
console.error(message) |
|||
reject(e) |
|||
} |
|||
}).catch(err => { |
|||
// TODO 云函数报错处理
|
|||
console.error(err.message) |
|||
reject(err) |
|||
}) |
|||
}); |
|||
// #endif
|
|||
} |
|||
|
|||
/** |
|||
* 使用 uni.showModal 升级 |
|||
*/ |
|||
function updateUseModal(packageInfo) { |
|||
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 和 安卓下载更新
|
|||
downloadTask = uni.downloadFile({ |
|||
url, |
|||
success: res => { |
|||
if (res.statusCode !== 200) { |
|||
console.error('下载安装包失败', err); |
|||
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 |
|||
}); |
|||
}); |
|||
} |
|||
}); |
|||
} |
|||
}); |
|||
} |
Loading…
Reference in new issue