@zfqh/uniapp 0.2.11 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.2.14](http://10.10.10.16/caoben/front-end/compare/@zfqh/uniapp@0.2.13...@zfqh/uniapp@0.2.14) (2026-06-25)
7
+
8
+ **Note:** Version bump only for package @zfqh/uniapp
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.2.13](http://10.10.10.16/caoben/front-end/compare/@zfqh/uniapp@0.2.12...@zfqh/uniapp@0.2.13) (2026-06-25)
15
+
16
+ **Note:** Version bump only for package @zfqh/uniapp
17
+
18
+
19
+
20
+
21
+
22
+ ## [0.2.12](http://10.10.10.16/caoben/front-end/compare/@zfqh/uniapp@0.2.11...@zfqh/uniapp@0.2.12) (2026-06-25)
23
+
24
+ **Note:** Version bump only for package @zfqh/uniapp
25
+
26
+
27
+
28
+
29
+
6
30
  ## [0.2.11](http://10.10.10.16/caoben/front-end/compare/@zfqh/uniapp@0.2.10...@zfqh/uniapp@0.2.11) (2026-06-24)
7
31
 
8
32
  **Note:** Version bump only for package @zfqh/uniapp
@@ -109,7 +109,6 @@ export default defineEnvConfig({
109
109
  | `path` | `configs/path.ts` | 页面别名配置。 |
110
110
  | `link` | `configs/link.ts` | 外部链接配置。 |
111
111
  | `page` | `configs/page.ts` | 页面集合、tabBar、原生页、登录页集合。 |
112
- | `update` | `configs/update.ts` | App 更新请求函数。 |
113
112
  | `upload` | `configs/upload.ts` | 上传临时凭证请求函数。 |
114
113
  | `navigate` | `configs/navigate.ts` | 登录跳转方式和来源页策略。 |
115
114
  | `ver` | `configs/ver.ts` | 当前版本号和版本名。 |
@@ -316,22 +315,6 @@ defineConfig({
316
315
  }
317
316
  ```
318
317
 
319
- ## update
320
-
321
- App 更新能力依赖 `update.request`:
322
-
323
- ```ts
324
- defineConfig({
325
- update: {
326
- request(data) {
327
- return POST('/app-api/system/app/version/latest', data);
328
- },
329
- },
330
- });
331
- ```
332
-
333
- 返回数据可包含 `hot_update`、`force_update`、`wgt_url`、`apk_url`、`ipa_url`、`exe_url`、`dmg_url` 等字段。
334
-
335
318
  ## storage
336
319
 
337
320
  ```ts
@@ -5,10 +5,10 @@ App.vue 全局生命周期 mixin。发布路径:`@zfqh/uniapp/lib/mixins/app`
5
5
  | 项 | 说明 |
6
6
  | --- | --- |
7
7
  | `computed isConnected/isLogin/unreadCount` | 读取网络、登录、未读数 getter。 |
8
- | `watch isConnected` | 网络恢复后非 H5 端触发 update.check()。 |
8
+ | `watch isConnected` | 网络恢复后触发网络状态更新。 |
9
9
  | `watch unreadCount` | App 端同步应用角标。 |
10
10
  | `onLaunch(e)` | 初始化网络监听,并在启动页命中 needLoginPages 且未登录时触发登录导航。 |
11
- | `onShow(e)` | 记录 launch 信息,并在非开发环境检查更新。 |
11
+ | `onShow(e)` | 记录 launch 信息。 |
12
12
 
13
13
  ## 基本使用
14
14
 
@@ -25,7 +25,7 @@
25
25
  | [throttle](./throttle) | 节流类和默认实例。 |
26
26
  | [toast](./toast) | loading、toast、success、error、fail、exception 和自定义提示适配。 |
27
27
  | [uni](./uni) | 平台运行时补丁或内部实现。 |
28
- | [update](./update) | App、Electron H5、小程序更新。 |
28
+ | [update](./update) | 版本检查、应用安装和重启。 |
29
29
 
30
30
  ## 通用工具
31
31
 
@@ -4,162 +4,160 @@
4
4
  `@zfqh/uniapp/lib/utils/update`
5
5
  :::
6
6
 
7
- 统一检查 App、Electron H5、小程序更新,处理热更新、整包更新和应用重启。
7
+ 提供版本检查、应用安装和重启能力,支持 App 和 H5(Electron / WebView)多端。
8
8
 
9
9
  ## 平台兼容性
10
10
 
11
- | App | H5 | 微信小程序 | 其他小程序 | WebView |
12
- | --- | --- | --- | --- | --- |
13
- | √ | √ | √ | 视平台 API 而定 | 视运行容器而定 |
11
+ | App | H5(Electron) | H5(WebView) |
12
+ | --- | --- | --- |
13
+ | √ | √ | √ |
14
14
 
15
15
  ## 基本使用
16
16
 
17
17
  ```ts
18
- import { update } from '@zfqh/uniapp';
18
+ import { checkVersion, installUpdate, restartApp } from '@zfqh/uniapp';
19
19
  ```
20
20
 
21
- ## 检查更新
21
+ ## API
22
22
 
23
- ```ts
24
- import { update } from '@zfqh/uniapp';
23
+ 发布路径:`@zfqh/uniapp/lib/utils/update`
25
24
 
26
- // 常规检查(弹出确认框让用户选择)
27
- await update.check();
25
+ ### checkVersion
28
26
 
29
- // 强制更新(跳过确认框,直接下载)
30
- await update.check(true);
27
+ 检查指定应用是否有新版本可用。
28
+
29
+ ```ts
30
+ function checkVersion(appid: string): Promise<VersionInfo | null>
31
31
  ```
32
32
 
33
- `check(immediate?: boolean)` 会根据平台自动选择更新方式:
33
+ - 返回 `VersionInfo` 表示有可用更新
34
+ - 返回 `null` 表示已是最新版本或检查失败
34
35
 
35
- | 平台 | 更新方式 |
36
- | --- | --- |
37
- | App(Android/iOS) | 热更新(wgt)或整包更新(apk/ipa) |
38
- | H5(Electron) | 热更新(zip)或整包更新(exe/dmg) |
39
- | 微信小程序 | `getUpdateManager` 原生更新 |
36
+ ```ts
37
+ const versionInfo = await checkVersion('com.example.app');
38
+ if (versionInfo) {
39
+ console.log('发现新版本', versionInfo.name, versionInfo.version);
40
+ }
41
+ ```
40
42
 
41
- ## 配置 update.request
43
+ ### installUpdate
42
44
 
43
- 需要在 `defineConfig` 中配置获取版本信息的请求函数:
45
+ 下载并安装更新包。
44
46
 
45
47
  ```ts
46
- import { defineConfig } from '@zfqh/uniapp';
47
- import { POST } from '@zfqh/uniapp/lib/apis';
48
+ function installUpdate(options: InstallOptions): void
49
+ ```
48
50
 
49
- defineConfig({
50
- update: {
51
- request(data) {
52
- return POST('/app-api/system/app/version/latest', data);
53
- },
51
+ ```ts
52
+ installUpdate({
53
+ appid: 'com.example.app',
54
+ url: versionInfo.fileUrl || versionInfo.hotUpdateUrl,
55
+ progress(p) {
56
+ console.log(`下载进度: ${p}%`);
57
+ },
58
+ success() {
59
+ restartApp();
60
+ },
61
+ fail(error) {
62
+ console.error('安装失败', error.message);
54
63
  },
55
64
  });
56
65
  ```
57
66
 
58
- 请求参数包含:
59
-
60
- | 字段 | 说明 |
61
- | --- | --- |
62
- | `appId` | 当前应用 ID |
63
- | `appName` | 当前应用名称 |
64
- | `versionCode` | 当前资源版本号 |
65
- | `versionName` | 当前资源版本名 |
66
- | `appVersionCode` | 当前程序版本号 |
67
- | `appVersionName` | 当前程序版本名 |
68
- | `platform` | 当前平台 |
69
-
70
- 响应字段:
71
-
72
- | 字段 | 说明 |
67
+ | 平台 | 行为 |
73
68
  | --- | --- |
74
- | `hot_update` | 是否热更新(1 = 热更新) |
75
- | `force_update` | 是否强制更新 |
76
- | `external_install` | 是否外部安装(Android 整包更新时跳浏览器) |
77
- | `wgt_url` | App WGT 热更新资源地址 |
78
- | `zip_url` | H5 Electron 热更新资源包地址 |
79
- | `apk_url` | Android 安装包地址 |
80
- | `ipa_url` | iOS 安装包地址 |
81
- | `exe_url` | Windows 安装包地址 |
82
- | `dmg_url` | macOS 安装包地址 |
69
+ | App(主应用) | 下载文件后调用 `plus.runtime.install` 安装 |
70
+ | App(子应用) | 下载后解压到 `_doc/` |
71
+ | H5 WebView | 通过 `postMessage` 通知宿主安装 |
72
+ | H5 Electron | 调用 `electron.webUtils.updateApp` |
83
73
 
84
- ## 典型用法
74
+ ### restartApp
85
75
 
86
- 在 `App.vue` 的 `onLaunch` 或 `onShow` 中检查更新:
76
+ 重启当前应用。
87
77
 
88
78
  ```ts
89
- import { update } from '@zfqh/uniapp';
90
-
91
- export default {
92
- onShow() {
93
- // 非开发环境检查更新
94
- // #ifndef H5
95
- update.check();
96
- // #endif
97
- },
98
- };
79
+ function restartApp(): void
99
80
  ```
100
81
 
101
- 在 Updater 组件中使用强制更新:
102
-
103
82
  ```ts
104
- // 用户点击"立即更新"按钮
105
- async function onUpdate() {
106
- await update.check(true); // 立即更新,不弹确认框
107
- }
83
+ restartApp();
108
84
  ```
109
85
 
110
- ## API
111
-
112
- 发布路径:`@zfqh/uniapp/lib/utils/update`
113
-
114
- | 名称 | 签名/声明 | 说明 |
115
- | --- | --- | --- |
116
- | `update.check(immediate?)` | `default export member` | 检查 App/H5 Electron/小程序更新;immediate 为 true 时尽量跳过确认直接下载或应用更新。 |
86
+ | 平台 | 行为 |
87
+ | --- | --- |
88
+ | App | `plus.runtime.restart()` |
89
+ | H5 WebView | 通过 `postMessage` 通知宿主重启 |
90
+ | H5 Electron | `ipcRenderer.send('relaunch')` |
117
91
 
118
- ## App 更新
92
+ ## 类型定义
119
93
 
120
- 根入口导出:
94
+ ### VersionInfo
121
95
 
122
96
  ```ts
123
- import { update } from '@zfqh/uniapp';
97
+ interface VersionInfo {
98
+ name: string;
99
+ version: string | number;
100
+ comment: string;
101
+ status: number;
102
+ hotUpdateUrl: string;
103
+ fileUrl: string;
104
+ }
124
105
  ```
125
106
 
126
- 更新配置:
107
+ | 字段 | 说明 |
108
+ | --- | --- |
109
+ | `name` | 版本名称 |
110
+ | `version` | 版本号 |
111
+ | `comment` | 更新说明 |
112
+ | `status` | 版本状态(> 2 为可用) |
113
+ | `hotUpdateUrl` | 热更新资源地址 |
114
+ | `fileUrl` | 整包下载地址 |
115
+
116
+ ### InstallOptions
127
117
 
128
118
  ```ts
129
- defineConfig({
130
- update: {
131
- request(data) {
132
- return POST('/app-api/system/app/version/latest', data);
133
- },
134
- },
135
- });
119
+ interface InstallOptions {
120
+ appid: string;
121
+ url: string;
122
+ progress?: (p: number) => void;
123
+ success?: () => void;
124
+ fail?: (error: { message: string }) => void;
125
+ }
136
126
  ```
137
127
 
138
- 请求参数可能包含:
139
-
140
128
  | 字段 | 说明 |
141
129
  | --- | --- |
142
- | `appId` | 当前应用 ID。 |
143
- | `appName` | 当前应用名称。 |
144
- | `versionCode` | 当前资源版本号。 |
145
- | `versionName` | 当前资源版本名。 |
146
- | `appVersionCode` | 当前程序版本号。 |
147
- | `appVersionName` | 当前程序版本名。 |
148
- | `platform` | 当前平台。 |
130
+ | `appid` | 目标应用 ID |
131
+ | `url` | 安装包下载地址 |
132
+ | `progress` | 下载进度回调(0-100) |
133
+ | `success` | 安装成功回调 |
134
+ | `fail` | 安装失败回调 |
149
135
 
150
- 响应字段可能包含:
136
+ ## 完整更新流程示例
151
137
 
152
- | 字段 | 说明 |
153
- | --- | --- |
154
- | `hot_update` | 是否热更新。 |
155
- | `version_code` | 新版本号。 |
156
- | `force_update` | 是否强制更新。 |
157
- | `external_install` | 是否外部安装。 |
158
- | `wgt_url` | App WGT 资源地址。 |
159
- | `zip_url` | 桌面资源包地址。 |
160
- | `apk_url` | Android 安装包地址。 |
161
- | `ipa_url` | iOS 安装包地址。 |
162
- | `exe_url` | Windows 安装包地址。 |
163
- | `dmg_url` | macOS 安装包地址。 |
164
-
165
- 具体更新执行逻辑以 `@zfqh/uniapp/lib/utils/update` 的发布实现为准。
138
+ ```ts
139
+ import { checkVersion, installUpdate, restartApp } from '@zfqh/uniapp';
140
+ import { config } from '@zfqh/uniapp';
141
+
142
+ async function doUpdate() {
143
+ const info = await checkVersion(config.app.appId);
144
+ if (!info) return;
145
+
146
+ const url = info.hotUpdateUrl || info.fileUrl;
147
+ if (!url) return;
148
+
149
+ installUpdate({
150
+ appid: config.app.appId,
151
+ url,
152
+ progress(p) {
153
+ // 更新进度 UI
154
+ },
155
+ success() {
156
+ restartApp();
157
+ },
158
+ fail(err) {
159
+ uni.showToast({ title: err.message, icon: 'none' });
160
+ },
161
+ });
162
+ }
163
+ ```
@@ -102,8 +102,3 @@ Options API 组件可使用 `this.$store`。普通 TS 模块中使用 `uni.$stor
102
102
  | [`g-trtc-room`](./g-trtc-room) | 音视频房间 UI 组件,包装 g-trtc、来电铃声、缩小悬浮和房间头部信息。 |
103
103
  | [`g-trtc-tui`](./g-trtc-tui) | 基于腾讯 TUIChatEngine 的通话邀请层,处理接听、挂断、消息监听和房间状态。 |
104
104
 
105
- ### 运行时
106
-
107
- | 组件 | 说明 |
108
- | --- | --- |
109
- | [`g-env`](./g-env) | 环境切换入口,主要给 H5/Electron 调试环境使用,用于查看和切换当前 env。 |
@@ -42,7 +42,7 @@
42
42
  | 弹层反馈 | `g-mask`、`g-popup`、`g-permission-popup`、`g-float` | 遮罩、弹窗、权限提示、悬浮入口。 |
43
43
  | 分享 | `g-share-view`、`g-share-photo`、`g-share-weixin` | 分享面板、保存图片、微信分享。 |
44
44
  | 音视频/图表 | `g-trtc`、`g-trtc-room`、`g-trtc-tui`、`g-polyline-view`、`g-polyline-chat`、`g-timer` | TRTC、TUI 通话、折线展示、计时器。 |
45
- | 调试 | `g-env`、`g-back-button` | 环境切换、自定义返回/首页按钮。 |
45
+ | 调试 | `g-back-button` | 自定义返回/首页按钮。 |
46
46
 
47
47
  ## Store 用法
48
48
 
@@ -5,7 +5,6 @@ import { TabbarConfig } from './tabbar';
5
5
  import { PathConfig } from './path';
6
6
  import { PageConfig } from './page';
7
7
  import { LinkConfig } from './link';
8
- import { UpdateConfig } from './update';
9
8
  import { UploadConfig } from './upload';
10
9
  import { NavigateConfig } from './navigate';
11
10
  import { ToastConfig } from './toast';
@@ -24,8 +23,6 @@ export interface DefineBaseConfig {
24
23
  link?: LinkConfig;
25
24
  /** 页面配置 */
26
25
  page?: PageConfig;
27
- /** 更新配置 */
28
- update?: UpdateConfig;
29
26
  /** 导航配置 */
30
27
  navigate?: NavigateConfig;
31
28
  /** 上传配置 */
@@ -126,8 +123,6 @@ declare const conf: {
126
123
  needLoginPages: string[];
127
124
  notRedirectPages: string[];
128
125
  };
129
- /** 更新配置 */
130
- update: UpdateConfig;
131
126
  /** 上传配置 */
132
127
  upload: UploadConfig;
133
128
  /** 导航配置 */
@@ -10,7 +10,6 @@ import tabbar from './tabbar';
10
10
  import path from './path';
11
11
  import page from './page';
12
12
  import link from './link';
13
- import update from './update';
14
13
  import upload from './upload';
15
14
  import navigate from './navigate';
16
15
  import toast from './toast';
@@ -41,8 +40,6 @@ const conf = {
41
40
  link,
42
41
  /** 页面配置 */
43
42
  page,
44
- /** 更新配置 */
45
- update,
46
43
  /** 上传配置 */
47
44
  upload,
48
45
  /** 导航配置 */
package/lib/index.d.ts CHANGED
@@ -16,7 +16,6 @@ export * from './utils/subscribe';
16
16
  export * from './utils/permit';
17
17
  export * from './utils/audio';
18
18
  export { default as query } from './utils/query';
19
- export { default as update } from './utils/update';
20
19
  export { default as Debounce, debounce } from './utils/debounce';
21
20
  export { default as Throttle, throttle } from './utils/throttle';
22
21
  export { defineConfig, defineEnvConfig } from './configs';
package/lib/index.js CHANGED
@@ -17,7 +17,6 @@ export * from './utils/subscribe';
17
17
  export * from './utils/permit';
18
18
  export * from './utils/audio';
19
19
  export { default as query } from './utils/query';
20
- export { default as update } from './utils/update';
21
20
  export { default as Debounce, debounce } from './utils/debounce';
22
21
  export { default as Throttle, throttle } from './utils/throttle';
23
22
  export { defineConfig, defineEnvConfig } from './configs';
package/lib/mixins/app.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { IS_WEBVIEW_ENV } from '../utils/consts';
2
- import update from '../utils/update';
3
2
  import navigate from '../utils/navigate';
4
3
  import { inPages } from '../utils/pages';
5
4
  import page from '../configs/page';
@@ -17,12 +16,7 @@ export default {
17
16
  },
18
17
  watch: {
19
18
  isConnected(connected) {
20
- // 网络恢复后检测更新
21
- if (connected) {
22
- // #ifndef H5
23
- update.check().catch(() => { });
24
- // #endif
25
- }
19
+ // 网络恢复
26
20
  },
27
21
  // #ifdef APP
28
22
  unreadCount(e) {
@@ -92,14 +86,6 @@ export default {
92
86
  // 设置启动信息
93
87
  this.$store.commit('setLaunchInfo', e);
94
88
  }
95
- if (process.env.NODE_ENV !== 'development') {
96
- // 检测更新
97
- setTimeout(() => {
98
- if (uni.showAppFromBackground) {
99
- update.check().catch(() => { });
100
- }
101
- }, 1000);
102
- }
103
89
  }
104
90
  },
105
91
  };
@@ -1,9 +1,20 @@
1
- /**
2
- * 检测更新
3
- * @param immediate 是否立即更新,不显示确认框
4
- */
5
- declare function check(immediate?: boolean): Promise<void>;
6
- declare const _default: {
7
- check: typeof check;
8
- };
9
- export default _default;
1
+ export interface VersionInfo {
2
+ name: string;
3
+ version: string | number;
4
+ comment: string;
5
+ status: number;
6
+ hotUpdateUrl: string;
7
+ fileUrl: string;
8
+ }
9
+ export interface InstallOptions {
10
+ appid: string;
11
+ url: string;
12
+ progress?: (p: number) => void;
13
+ success?: () => void;
14
+ fail?: (error: {
15
+ message: string;
16
+ }) => void;
17
+ }
18
+ export declare function checkVersion(appid: string): Promise<VersionInfo | null>;
19
+ export declare function installUpdate(options: InstallOptions): void;
20
+ export declare function restartApp(): void;
@@ -1,376 +1,170 @@
1
- import color from '../configs/color';
2
- import update from '../configs/update';
3
- import ver from '../configs/ver';
4
1
  import app from '../configs/app';
5
- import { SYSTEM_INFO } from './consts';
6
- // 防止弹窗多次弹出
7
- let visibleModal = false;
8
- function showModal(options) {
9
- uni.showModal({
10
- title: '更新提示',
11
- content: options?.content || '检测到新版本,下载并重启应用?',
12
- confirmColor: color.primary,
13
- showCancel: options?.showCancel,
14
- fail() {
15
- visibleModal = false;
16
- },
17
- success(res) {
18
- if (res.confirm) {
19
- options?.confirm && options.confirm();
20
- }
21
- else {
22
- visibleModal = false;
23
- }
24
- },
25
- });
26
- }
2
+ import env from '../configs/env';
3
+ import ver from '../configs/ver';
4
+ import { SYSTEM_INFO, IS_WEBVIEW_ENV, TYPES } from './consts';
5
+ import { postMessage } from './index';
6
+ import { getLastVersion } from '../apis/core';
7
+ const { platform, brand } = SYSTEM_INFO;
8
+ let _installMessageHandler = null;
27
9
  // #ifdef APP
28
- function appFileDownload(url, restart = true) {
29
- let downloaded = false;
30
- const showWaiting = plus.nativeUI.showWaiting('下载中...');
31
- const downloadTask = uni.downloadFile({
32
- url,
33
- success(downloadResult) {
34
- if (downloadResult.statusCode === 200) {
35
- showWaiting.setTitle('安装中...');
36
- setTimeout(() => {
37
- plus.runtime.install(downloadResult.tempFilePath, {
38
- force: true,
39
- }, () => {
40
- plus.nativeUI.closeWaiting();
41
- if (restart) {
42
- visibleModal = false;
43
- uni.showModal({
44
- title: '提示',
45
- content: '应用更新完成',
46
- showCancel: false,
47
- confirmText: '重启应用',
48
- confirmColor: color.primary,
49
- success() {
50
- plus.runtime.restart();
51
- },
52
- });
53
- }
54
- });
55
- }, 500);
56
- }
57
- else {
58
- visibleModal = false;
59
- plus.nativeUI.alert('更新失败');
60
- plus.nativeUI.closeWaiting();
61
- }
62
- },
63
- fail() {
64
- visibleModal = false;
65
- plus.nativeUI.closeWaiting();
66
- },
67
- });
68
- downloadTask.onProgressUpdate(({ progress }) => {
69
- if (!downloaded) {
70
- showWaiting.setTitle('下载中...' + progress + '%');
71
- if (progress === 100) {
72
- downloaded = true;
73
- }
10
+ function appGetProperty(appid) {
11
+ return new Promise((resolve) => {
12
+ if (appid === app.appId) {
13
+ plus.runtime.getProperty(String(plus.runtime.appid), (res) => resolve(res));
74
14
  }
75
- });
76
- }
77
- function checkAppUpdate(immediate = false) {
78
- return new Promise((resolve, reject) => {
79
- plus.runtime.getProperty(plus.runtime.appid, async ({ versionCode, version: versionName }) => {
80
- try {
81
- const { platform, appName, appId, appVersion: appVersionName, appVersionCode } = SYSTEM_INFO;
82
- const params = {
83
- appId: app.appId || appId,
84
- appName: app.name || appName,
85
- versionCode: Number(ver.code || versionCode),
86
- versionName: ver.name || versionName,
87
- appVersionCode: Number(appVersionCode),
88
- appVersionName,
89
- platform,
90
- };
91
- const data = await update.request(params);
92
- if (data) {
93
- let url = '';
94
- if (data.hot_update == 1) {
95
- url = data.wgt_url;
96
- }
97
- else {
98
- if (platform === 'android') {
99
- url = data.apk_url;
100
- }
101
- else if (platform === 'ios') {
102
- url = data.ipa_url;
15
+ else {
16
+ plus.io.resolveLocalFileSystemURL(`_doc/${appid}/manifest.json`, (entry) => {
17
+ entry.file((file) => {
18
+ const reader = new plus.io.FileReader();
19
+ reader.onloadend = (e) => {
20
+ try {
21
+ resolve(JSON.parse(e.target.result));
103
22
  }
104
- }
105
- if (url) {
106
- resolve();
107
- if (!visibleModal) {
108
- visibleModal = true;
109
- if (data.hot_update == 1) {
110
- // 热更新
111
- if (immediate) {
112
- appFileDownload(url);
113
- }
114
- else {
115
- showModal({
116
- showCancel: !data.force_update,
117
- confirm() {
118
- appFileDownload(url);
119
- },
120
- });
121
- }
122
- }
123
- else {
124
- // 整包更新
125
- if (params.platform == 'android') {
126
- if (immediate) {
127
- if (data.external_install) {
128
- plus.runtime.openURL(url);
129
- }
130
- else {
131
- appFileDownload(url, false);
132
- }
133
- }
134
- else {
135
- showModal({
136
- showCancel: !data.force_update,
137
- confirm() {
138
- if (data.external_install) {
139
- plus.runtime.openURL(url);
140
- }
141
- else {
142
- appFileDownload(url, false);
143
- }
144
- },
145
- });
146
- }
147
- }
148
- else if (params.platform == 'ios') {
149
- showModal({
150
- content: '检测到新版本,前往应用市场更新?',
151
- confirm() {
152
- plus.runtime.openURL(url);
153
- },
154
- });
155
- }
156
- }
23
+ catch {
24
+ resolve({});
157
25
  }
158
- }
159
- else {
160
- reject();
161
- }
162
- }
163
- else {
164
- reject();
165
- }
166
- }
167
- catch (e) {
168
- reject(e);
169
- }
170
- });
26
+ };
27
+ reader.readAsText(file);
28
+ }, () => resolve({}));
29
+ }, () => resolve({}));
30
+ }
171
31
  });
172
32
  }
173
33
  // #endif
174
34
  // #ifdef H5
175
- function fileDownload(url, restart = true) {
176
- const ipcRenderer = window['electron'].ipcRenderer;
177
- ipcRenderer.send('update', url);
178
- function updateDownload() {
179
- uni.showLoading({
180
- title: '下载中...',
181
- mask: true,
182
- });
183
- }
184
- function uploadProgress(e, progress) {
185
- uni.showLoading({
186
- title: `下载中...${progress}%`,
187
- mask: true,
35
+ function h5GetProperty(appid) {
36
+ return new Promise((resolve) => {
37
+ if (appid === app.appId) {
38
+ resolve({ version: ver.name, versionCode: ver.code });
39
+ }
40
+ else if (window.electron) {
41
+ window.electron.webUtils.getProperty(appid, (manifest) => resolve(manifest || {}));
42
+ }
43
+ });
44
+ }
45
+ // #endif
46
+ export async function checkVersion(appid) {
47
+ try {
48
+ let version = 0;
49
+ let packageName = appid;
50
+ let data = null;
51
+ // #ifdef APP
52
+ data = await appGetProperty(appid);
53
+ version = data.versionCode || 0;
54
+ // #endif
55
+ // #ifdef H5
56
+ data = await h5GetProperty(appid);
57
+ version = data.versionCode || 0;
58
+ // #endif
59
+ let type = 1;
60
+ // #ifdef H5
61
+ if (IS_WEBVIEW_ENV) {
62
+ type = 3;
63
+ }
64
+ // #endif
65
+ const res = await getLastVersion({
66
+ version,
67
+ packageName,
68
+ type,
69
+ platform: { android: 1, ios: 2, windows: 4 }[platform],
188
70
  });
189
- }
190
- function updateSuccess() {
191
- if (restart) {
192
- uni.showModal({
193
- title: '提示',
194
- content: '应用更新完成',
195
- showCancel: false,
196
- confirmText: '重启应用',
197
- confirmColor: color.primary,
198
- success() {
199
- ipcRenderer.send('relaunch');
200
- },
201
- });
71
+ const lastVer = { ...res?.data };
72
+ // #ifdef APP
73
+ if (uni.$store.state.dict && platform === 'android' && appid === app.appId && env.key === 'prod') {
74
+ await uni.$store.dispatch('getDictInfo', { name: 'group_relation', cache: true });
75
+ if (uni.$store.state.dict.info.group_relation?.values?.includes(brand)) {
76
+ lastVer.hotUpdateUrl = '';
77
+ }
202
78
  }
79
+ // #endif
80
+ if (lastVer.status > 2 && Number(lastVer.version) > Number(version)) {
81
+ return lastVer;
82
+ }
83
+ return null;
203
84
  }
204
- function updateFail() {
205
- setTimeout(() => {
206
- uni.showToast({
207
- title: '更新失败',
208
- icon: 'error',
209
- duration: 2000,
210
- });
211
- }, 300);
212
- }
213
- function updateComplete() {
214
- visibleModal = false;
215
- uni.hideLoading();
216
- ipcRenderer.removeListener('update-download', updateDownload);
217
- ipcRenderer.removeListener('update-progress', uploadProgress);
218
- ipcRenderer.removeListener('update-success', updateSuccess);
219
- ipcRenderer.removeListener('update-fail', updateFail);
85
+ catch {
86
+ return null;
220
87
  }
221
- ipcRenderer.on('update-download', updateDownload);
222
- ipcRenderer.on('update-progress', uploadProgress);
223
- ipcRenderer.on('update-success', updateSuccess);
224
- ipcRenderer.on('update-fail', updateFail);
225
- ipcRenderer.once('update-complete', updateComplete);
226
88
  }
227
- async function checkUpdate(immediate = false) {
228
- return new Promise((resolve, reject) => {
229
- const { platform, appName, appId, appVersion: versionName, appVersionCode: versionCode } = SYSTEM_INFO;
230
- const params = {
231
- appId: app.appId || appId,
232
- appName: app.name || appName,
233
- versionCode: Number(ver.code || versionCode),
234
- versionName: ver.name || versionName,
235
- appVersionCode: Number(window['versionCode'] || versionCode),
236
- appVersionName: window['versionName'] || versionName,
237
- platform: window['platform'] || platform,
238
- };
239
- update
240
- .request(params)
241
- .then((data) => {
242
- if (data) {
243
- let url = '';
244
- if (data.hot_update == 1) {
245
- url = data.zip_url;
246
- }
247
- else {
248
- if (params.platform === 'windows') {
249
- url = data.exe_url;
250
- }
251
- else if (params.platform === 'macos') {
252
- url = data.dmg_url;
253
- }
254
- }
255
- if (url) {
256
- resolve();
257
- if (!visibleModal) {
258
- visibleModal = true;
259
- if (data.hot_update == 1) {
260
- // 热更新
261
- if (immediate) {
262
- fileDownload(url);
263
- }
264
- else {
265
- showModal({
266
- showCancel: !data.force_update,
267
- confirm() {
268
- fileDownload(url);
269
- },
270
- });
271
- }
272
- }
273
- else {
274
- // 整包更新
275
- if (immediate) {
276
- fileDownload(url, false);
277
- }
278
- else {
279
- showModal({
280
- showCancel: !data.force_update,
281
- confirm() {
282
- fileDownload(url, false);
283
- },
284
- });
285
- }
286
- }
287
- }
288
- }
289
- else {
290
- reject();
291
- }
89
+ // #ifdef APP
90
+ function appInstall({ appid, url, progress, success, fail }) {
91
+ const downloadTask = uni.downloadFile({
92
+ url,
93
+ success(res) {
94
+ if (res.statusCode !== 200)
95
+ return fail?.({ message: 'download failed' });
96
+ progress?.(100);
97
+ if (appid === app.appId) {
98
+ plus.runtime.install(res.tempFilePath, { force: true }, success, fail);
292
99
  }
293
100
  else {
294
- reject();
101
+ plus.io.resolveLocalFileSystemURL('_doc/', (docDir) => {
102
+ plus.zip.decompress(res.tempFilePath, docDir.fullPath, success, () => {
103
+ plus.zip.decompress(res.tempFilePath, docDir.fullPath, success, fail);
104
+ });
105
+ }, (e) => fail?.({ message: e?.message || String(e) }));
295
106
  }
296
- })
297
- .catch((e) => {
298
- reject(e);
299
- });
107
+ },
108
+ fail: (e) => fail?.({ message: e?.errMsg || String(e) }),
300
109
  });
110
+ downloadTask.onProgressUpdate(({ progress: p }) => progress?.(p));
301
111
  }
302
112
  // #endif
303
- // #ifdef MP
304
- function mpDownload(updateManager) {
305
- uni.showLoading({ title: '更新中...' });
306
- updateManager.onUpdateReady(() => {
307
- uni.hideLoading();
308
- setTimeout(() => {
309
- visibleModal = false;
310
- updateManager.applyUpdate();
311
- }, 300);
312
- });
313
- updateManager.onUpdateFailed(() => {
314
- visibleModal = false;
315
- uni.hideLoading();
316
- uni.showModal({
317
- title: '更新失败',
318
- content: `请您删除当前小程序,并搜索“${app.name || SYSTEM_INFO.appName}”重新打开应用`,
319
- confirmColor: color.primary,
113
+ // #ifdef H5
114
+ function h5Install(options) {
115
+ if (IS_WEBVIEW_ENV) {
116
+ postMessage({
117
+ type: TYPES.MESSAGE.APP_INSTALL,
118
+ payload: {
119
+ appid: options.appid,
120
+ url: options.url,
121
+ },
320
122
  });
321
- });
322
- }
323
- function checkMpUpdate(immediate = false) {
324
- return new Promise((resolve, reject) => {
325
- if (uni.canIUse('getUpdateManager')) {
326
- const updateManager = uni.getUpdateManager();
327
- updateManager.onCheckForUpdate((e) => {
328
- if (e.hasUpdate) {
329
- visibleModal = true;
330
- resolve();
331
- if (immediate) {
332
- mpDownload(updateManager);
333
- }
334
- else {
335
- showModal({
336
- confirm() {
337
- mpDownload(updateManager);
338
- },
339
- });
340
- }
123
+ if (_installMessageHandler) {
124
+ uni.$off(TYPES.MESSAGE.WEBVIEW_MESSAGE, _installMessageHandler);
125
+ _installMessageHandler = null;
126
+ }
127
+ _installMessageHandler = (e) => {
128
+ if (e?.type === TYPES.MESSAGE.APP_INSTALL) {
129
+ if (e.payload?.progress != null) {
130
+ options.progress?.(e.payload.progress);
131
+ }
132
+ else if (e.payload?.success) {
133
+ options.success?.();
341
134
  }
342
135
  else {
343
- reject();
136
+ options.fail?.({ message: e.payload.message });
344
137
  }
345
- });
346
- }
347
- else {
348
- reject();
349
- }
350
- });
138
+ }
139
+ };
140
+ uni.$on(TYPES.MESSAGE.WEBVIEW_MESSAGE, _installMessageHandler);
141
+ }
142
+ else if (window.electron) {
143
+ window.electron.webUtils.updateApp(options);
144
+ }
351
145
  }
352
146
  // #endif
353
- /**
354
- * 检测更新
355
- * @param immediate 是否立即更新,不显示确认框
356
- */
357
- function check(immediate = false) {
358
- let res = Promise.resolve();
359
- if (!visibleModal) {
360
- // #ifdef H5
361
- if (typeof window['electron'] === 'object') {
362
- res = checkUpdate(immediate);
363
- }
364
- // #endif
365
- // #ifdef APP
366
- res = checkAppUpdate(immediate);
367
- // #endif
368
- // #ifdef MP
369
- res = checkMpUpdate(immediate);
370
- // #endif
147
+ export function installUpdate(options) {
148
+ // #ifdef H5
149
+ h5Install(options);
150
+ // #endif
151
+ // #ifdef APP
152
+ appInstall(options);
153
+ // #endif
154
+ }
155
+ export function restartApp() {
156
+ // #ifdef H5
157
+ if (IS_WEBVIEW_ENV) {
158
+ postMessage({
159
+ type: TYPES.MESSAGE.APP_RESTART,
160
+ payload: {},
161
+ });
162
+ }
163
+ else if (window.electron) {
164
+ window.electron.ipcRenderer.send('relaunch');
371
165
  }
372
- return res;
166
+ // #endif
167
+ // #ifdef APP
168
+ plus.runtime.restart();
169
+ // #endif
373
170
  }
374
- export default {
375
- check,
376
- };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zfqh/uniapp",
3
- "version": "0.2.11",
3
+ "version": "0.2.14",
4
4
  "description": "uniapp公共模块",
5
5
  "author": "yinjiazeng@163.com",
6
6
  "license": "MIT",
@@ -46,5 +46,5 @@
46
46
  "@types/qs": "^6.9.16",
47
47
  "@types/url-parse": "^1.4.11"
48
48
  },
49
- "gitHead": "4f9aae7510f83a5cd4b63d74f91993e12351e04f"
49
+ "gitHead": "7d5e40d024158c954ee9bd913650d11f87aac083"
50
50
  }
@@ -1,25 +0,0 @@
1
- # update
2
-
3
- 更新配置。发布路径:`@zfqh/uniapp/lib/configs/update`
4
-
5
- | 字段 | 类型 | 默认值 | 说明 |
6
- | --- | --- | --- | --- |
7
- | `request(data)` | `function` | `Promise&lt;null&gt;` | 获取最新版本信息;返回 hot_update、force_update、wgt_url/apk_url/ipa_url/zip_url 等字段。 |
8
-
9
- ## 基本使用
10
-
11
- App.vue 全局 mixin 会在合适时机调用更新检查;业务项目只需要配置获取最新版本的请求函数。
12
-
13
- ```ts
14
- import { defineConfig } from '@zfqh/uniapp';
15
- import { POST } from '@zfqh/uniapp/lib/apis';
16
-
17
- defineConfig({
18
- update: {
19
- async request(data) {
20
- const { data: version } = await POST('/app-api/system/app/version/get-last-version', data);
21
- return version;
22
- },
23
- },
24
- });
25
- ```
@@ -1,75 +0,0 @@
1
- # g-env 环境显示
2
-
3
- ::: tip 组件名
4
- `g-env`
5
-
6
- 发布路径:`@zfqh/uniapp/lib/components/g-env/g-env.vue`
7
- :::
8
-
9
- 环境切换入口,主要给 H5/Electron 调试环境使用,用于查看和切换当前 env。
10
-
11
- ## 平台兼容性
12
-
13
- | App(vue) | App(nvue) | H5 | 小程序 | Vue 2 | Vue 3 |
14
- | --- | --- | --- | --- | --- | --- |
15
- | √ | 依赖源码条件编译 | √ | √ | - | √ |
16
-
17
- ## 使用前提
18
-
19
- - 已安装并注册 `@zfqh/uniapp` 插件。
20
- - 已按 [项目接入](./usage) 配置 easycom,或手动从构建产物导入组件。
21
- - 尺寸类属性通常支持数字或带单位字符串;数字值会在组件内部通过 `uni.$uv.addUnit` 转成样式单位。
22
- - 样式类属性中,`customStyle`、`xxxStyle` 接收对象,`customClass`、`xxxClass` 接收 class 字符串。
23
-
24
- ## 基本使用
25
-
26
- ```vue
27
- <template>
28
- <view class="user-version">
29
- 当前环境
30
- <g-env :env="env" prefix="(" suffix=")" />
31
- </view>
32
- </template>
33
-
34
- <script setup>
35
- import { config } from '@zfqh/uniapp';
36
-
37
- const env = config.env;
38
- </script>
39
- ```
40
-
41
- ## API
42
-
43
- ### 环境显示 Props
44
-
45
- | 属性 | 类型 | 默认值 | 必填 | 说明 |
46
- | --- | --- | --- | --- | --- |
47
- | `env` | `Object` | `() => ({})` | 否 | 组件公开属性 env,用于控制该组件对应的渲染、交互或业务参数。 |
48
- | `data` | `Array` | `() => [ { name: '开发环境', key: 'dev', }, { name: '测试环境', key: 'sit', }, { name: '演示环境', key: 'uat', }, { name: '预生产环境', key: 'pre', }, ]` | 否 | 组件渲染或业务计算使用的数据源。 |
49
- | `prefix` | `String` | `''` | 否 | 组件公开属性 prefix,用于控制该组件对应的渲染、交互或业务参数。 |
50
- | `suffix` | `String` | `''` | 否 | 组件公开属性 suffix,用于控制该组件对应的渲染、交互或业务参数。 |
51
- | `switchable` | `Boolean` | `true` | 否 | 组件公开属性 switchable,用于控制该组件对应的渲染、交互或业务参数。 |
52
-
53
- ### 环境显示 Events
54
-
55
- 无显式组件事件。
56
-
57
- ### 环境显示 Slots
58
-
59
- | 插槽 | 说明 |
60
- | --- | --- |
61
- | `default` | 默认内容区域。 |
62
-
63
- ### 环境显示 Methods
64
-
65
- | 方法 | 说明 |
66
- | --- | --- |
67
- | `open()` | 打开组件或弹层;部分组件支持传入选项覆盖当前展示内容。 |
68
- | `select(e)` | 处理选中/取消选中逻辑并触发 change。 |
69
-
70
- ### 环境显示 Internal State
71
-
72
- | 类型 | 名称 | 说明 |
73
- | --- | --- | --- |
74
- | computed | `show` | 内部计算属性,用于把 props、平台信息或样式配置转换为模板可用值。 |
75
- | computed | `list` | 内部计算属性,用于把 props、平台信息或样式配置转换为模板可用值。 |
@@ -1,123 +0,0 @@
1
- <template>
2
- <template v-if="show">
3
- <slot name="default" :open="open">
4
- <text @tap.stop="open"> {{ prefix }}{{ env.name }}{{ suffix }} </text>
5
- </slot>
6
- <!-- #ifndef MP -->
7
- <uv-action-sheet v-if="switchable" ref="actionSheet" :actions="list" title="切换环境" @select="select" />
8
- <!-- #endif -->
9
- </template>
10
- </template>
11
-
12
- <script>
13
- import color from '../../configs/color';
14
- import ver from '../../configs/ver';
15
- import update from '../../utils/update';
16
- import { requestDelay } from '../../utils';
17
-
18
- export default {
19
- props: {
20
- env: {
21
- type: Object,
22
- default: () => ({}),
23
- },
24
- data: {
25
- type: Array,
26
- default: () => [
27
- {
28
- name: '开发环境',
29
- key: 'dev',
30
- },
31
- {
32
- name: '测试环境',
33
- key: 'sit',
34
- },
35
- {
36
- name: '演示环境',
37
- key: 'uat',
38
- },
39
- {
40
- name: '预生产环境',
41
- key: 'pre',
42
- },
43
- ],
44
- },
45
- prefix: {
46
- type: String,
47
- default: '',
48
- },
49
- suffix: {
50
- type: String,
51
- default: '',
52
- },
53
- switchable: {
54
- type: Boolean,
55
- default: true,
56
- },
57
- },
58
- computed: {
59
- show() {
60
- return this.env.name !== 'prod';
61
- },
62
- list() {
63
- return this.data.map((item) => ({
64
- ...item,
65
- disabled: item.disabled || (item.key === this.env.name ? true : false),
66
- }));
67
- },
68
- },
69
- methods: {
70
- open() {
71
- if (this.switchable) {
72
- // #ifdef MP-WEIXIN
73
- uni.showModal({
74
- title: '提示',
75
- content: '请在"小程序助手"中切换环境',
76
- showCancel: false,
77
- confirmColor: color.primary,
78
- });
79
- // #endif
80
- // #ifdef H5
81
- if (!window.electron) {
82
- return;
83
- }
84
- // #endif
85
- // #ifndef MP
86
- this.$refs.actionSheet.open();
87
- // #endif
88
- }
89
- },
90
- // #ifndef MP
91
- select(e) {
92
- this.$refs.actionSheet.close();
93
- if (this.current !== e.key) {
94
- uni.showModal({
95
- title: '提示',
96
- content: `是否切换到${e.name}并重启应用?`,
97
- confirmColor: color.primary,
98
- success: async (res) => {
99
- if (res.confirm) {
100
- this.env.set(e.key);
101
- ver.code = -1;
102
- try {
103
- uni.showLoading({ title: '切换中...' });
104
- await requestDelay(() => Promise.resolve());
105
- uni.hideLoading();
106
- await update.check(true);
107
- } catch (e) {
108
- // #ifdef APP
109
- plus.runtime.restart();
110
- // #endif
111
- // #ifdef H5
112
- window.location.reload();
113
- // #endif
114
- }
115
- }
116
- },
117
- });
118
- }
119
- },
120
- // #endif
121
- },
122
- };
123
- </script>
@@ -1,45 +0,0 @@
1
- type UpdateRequestParams = {
2
- /** 当前应用ID */
3
- appId?: string;
4
- /** 当前应用名称 */
5
- appName?: string;
6
- /** 当前应用资源版本号 */
7
- versionCode?: number;
8
- /** 当前应用资源版本名称 */
9
- versionName?: string;
10
- /** 当前应用程序版本号 */
11
- appVersionCode?: number;
12
- /** 当前应用程序版本名称 */
13
- appVersionName?: string;
14
- /** 应用平台 */
15
- platform?: string;
16
- };
17
- type UpdateResponceData = {
18
- /** 资源包热更新,0否 1是 */
19
- hot_update?: number;
20
- /** 新包版本号 */
21
- version_code?: number;
22
- /** 强制更新,0否 1是 */
23
- force_update?: number;
24
- /** 在APP外部安装 */
25
- external_install?: number;
26
- /** app资源包路径 */
27
- wgt_url?: string;
28
- /** 客户端资源包路径 */
29
- zip_url?: string;
30
- /** android包路径 */
31
- apk_url?: string;
32
- /** ios包路径 */
33
- ipa_url?: string;
34
- /** windows包路径 */
35
- exe_url?: string;
36
- /** macos包路径 */
37
- dmg_url?: string;
38
- };
39
- export type UpdateConfig = {
40
- /** 自动更新请求,获取最新更新资源 */
41
- request: (data: UpdateRequestParams) => Promise<UpdateResponceData>;
42
- };
43
- /** 自动更新配置 */
44
- declare const update: UpdateConfig;
45
- export default update;
@@ -1,6 +0,0 @@
1
- /** 自动更新配置 */
2
- const update = {
3
- /** 自动更新请求,获取最新更新资源 */
4
- request: () => Promise.resolve(null),
5
- };
6
- export default update;