stellar-ui-v2 1.40.33 → 1.40.34

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.
@@ -2,14 +2,16 @@
2
2
 
3
3
  - 此组件用于APP更新功能
4
4
  - 仅支持APP端
5
+ - 支持整包升级(apk)和资源包升级(wgt)
5
6
 
6
- ---$
7
+ ---
7
8
 
8
9
  ### 基础用法
9
10
 
10
11
  - 属性`clientId`用于设置APP的应用编码
11
12
  - 属性`clientSecret`用于设置APP的应用密钥
12
13
  - 属性`fallbackApiUrl`用于设置兜底检查接口地址
14
+ - 属性`strictVersionCheck`用于设置严格版本检查模式
13
15
  - 函数`start`用于开始检查更新
14
16
  - 函数`getSkippedVersions`用于获取跳过版本列表
15
17
  - 函数`clearSkippedVersions`用于清空跳过版本记录
@@ -59,6 +61,7 @@ export default {
59
61
  clientId="workbench_android"
60
62
  clientSecret="gkS6lEEncqAocYK2qsrvPQZykm3ISeMx"
61
63
  fallbackApiUrl="https://example.com/api/app-update/check"
64
+ :strictVersionCheck="true"
62
65
  @skip-version="onSkipVersion"
63
66
  @fallback="onFallback"
64
67
  ></ste-app-update>
@@ -68,7 +71,7 @@ export default {
68
71
  </template>
69
72
  ```
70
73
 
71
- ---$
74
+ ---
72
75
 
73
76
  ### API
74
77
 
@@ -82,7 +85,8 @@ export default {
82
85
  | `btnText` | 立即体验按钮文本 | `string` | `立即体验` | - | - |
83
86
  | `appVersion` | 应用当前版本 | `string` | - | - | `1.40.9`|
84
87
  | `zIndex` | 弹窗层级 | `string/number` | `998` | - | `1.40.9`|
85
- | `fallbackApiUrl`| 兜底检查接口地址 | `string` | - | - | `1.41.0`|
88
+ | `fallbackApiUrl`| 兜底检查接口地址 | `string` | `https://stellar-public-prd.intecloud.com.cn/api/app-update/check` | - | `1.41.0`|
89
+ | `strictVersionCheck`| 严格版本检查,设为true时只有新版本大于当前版本才触发更新 | `boolean` | `false` | `true/false` | - |
86
90
 
87
91
 
88
92
  #### Events
@@ -101,7 +105,50 @@ export default {
101
105
  | `start(callback)` | 开始检查更新 | - | - |
102
106
  | `getSkippedVersions()` | 获取已跳过的版本列表 | string[] | `1.41.0` |
103
107
  | `clearSkippedVersions()` | 清空跳过版本记录 | - | `1.41.0` |
108
+ | `cancelDownload()` | 取消当前下载任务 | - | - |
109
+ | `install()` | 安装已下载的更新包(仅整包升级时可用) | - | - |
104
110
 
105
111
 
106
- ---$
107
- {{xuyajun}}
112
+ ---
113
+
114
+ ### API 返回数据格式
115
+
116
+ 更新接口(`apiUrl`)返回数据格式:
117
+
118
+ ```json
119
+ {
120
+ "code": 200,
121
+ "data": {
122
+ "code": "101",
123
+ "name": "1.0.1",
124
+ "desc": "更新内容描述",
125
+ "isForce": false,
126
+ "entireFile": "https://example.com/app.apk",
127
+ "updateFile": "https://example.com/app.wgt"
128
+ }
129
+ }
130
+ ```
131
+
132
+ | 字段 | 类型 | 说明 |
133
+ | ----- | ----- | ----- |
134
+ | `code` | string | 版本号 |
135
+ | `name` | string | 版本名称 |
136
+ | `desc` | string | 更新内容描述 |
137
+ | `isForce` | boolean | 是否强制更新 |
138
+ | `entireFile` | string | 整包升级文件地址(apk) |
139
+ | `updateFile` | string | 资源包升级文件地址(wgt) |
140
+
141
+ > 当 `entireFile` 存在时,优先使用整包升级(`package_type=0`),否则使用资源包升级(`package_type=1`)
142
+
143
+ ---
144
+
145
+ ### 更新流程说明
146
+
147
+ 1. 调用 `start()` 方法开始检查更新
148
+ 2. 先检查兜底接口(`fallbackApiUrl`),命中则触发兜底更新流程
149
+ 3. 调用正常更新接口(`apiUrl`)获取版本信息
150
+ 4. 检查是否已跳过该版本
151
+ 5. 检查版本是否需要更新(根据 `strictVersionCheck` 决定比较方式)
152
+ 6. 检查是否存在未完成的下载任务,有则恢复下载
153
+ 7. 弹出更新弹窗,用户可选择立即更新、跳过版本或取消
154
+ 8. 下载完成后自动安装(wgt)或提示安装(apk)
@@ -1,8 +1,9 @@
1
- export function download(data, { success, error, onProgressUpdate, downloadSuccess }) {
2
- const package_type = data.package_type;
3
- let timeout;
1
+ export function download(data, options) {
2
+ const success = options.success;
3
+ const error = options.error;
4
+ const downloadSuccess = options.downloadSuccess;
5
+ const onProgressUpdate = options.onProgressUpdate;
4
6
 
5
- // 参数验证
6
7
  if (!data.updateFile) {
7
8
  const errorMsg = '更新文件地址不能为空';
8
9
  uni.showToast({ title: errorMsg, icon: 'none' });
@@ -10,13 +11,111 @@ export function download(data, { success, error, onProgressUpdate, downloadSucce
10
11
  throw new Error(errorMsg);
11
12
  }
12
13
 
14
+ const package_type = data.package_type;
15
+
16
+ // #ifdef APP-PLUS
17
+ let timeout;
18
+
19
+ const task = plus.downloader.createDownload(
20
+ data.updateFile,
21
+ {
22
+ filename: '_downloads/stellar_update/',
23
+ },
24
+ function(download, status) {
25
+ clearTimeout(timeout);
26
+
27
+ if (status === 200) {
28
+ if (!download.filename) {
29
+ const errorMsg = '下载文件路径为空';
30
+ uni.showToast({ title: errorMsg, icon: 'none' });
31
+ error && error(new Error(errorMsg));
32
+ return;
33
+ }
34
+
35
+ downloadSuccess && downloadSuccess(download.filename);
36
+
37
+ plus.runtime.install(
38
+ download.filename,
39
+ { force: true },
40
+ function() {
41
+ if (package_type == 1) {
42
+ uni.showModal({
43
+ title: '提示',
44
+ content: '升级成功,请重新启动!',
45
+ confirmText: '确定',
46
+ showCancel: false,
47
+ success: function() {
48
+ success && success();
49
+ plus.runtime.restart();
50
+ },
51
+ });
52
+ } else {
53
+ success && success();
54
+ }
55
+ },
56
+ function(e) {
57
+ const errorMsg = e.message || '安装失败';
58
+ uni.showModal({
59
+ title: '提示',
60
+ content: errorMsg,
61
+ showCancel: false,
62
+ success: function() {
63
+ error && error(e);
64
+ },
65
+ });
66
+ }
67
+ );
68
+ } else {
69
+ const errorMsg = '下载失败,状态码:' + status;
70
+ uni.showToast({ title: errorMsg, icon: 'none' });
71
+ error && error(new Error(errorMsg));
72
+ }
73
+ }
74
+ );
75
+
76
+ task.addEventListener('statechanged', function(download) {
77
+ if (download.state === 3 && download.totalSize > 0) {
78
+ const progress = Math.round((download.downloadedSize / download.totalSize) * 100);
79
+ onProgressUpdate && onProgressUpdate({
80
+ progress: progress,
81
+ totalBytesWritten: download.downloadedSize,
82
+ totalBytesExpectedToWrite: download.totalSize,
83
+ });
84
+
85
+ clearTimeout(timeout);
86
+ timeout = setTimeout(function() {
87
+ task.abort();
88
+ const errorMsg = '下载超时,请检查网络连接';
89
+ uni.showToast({ title: errorMsg, icon: 'none' });
90
+ error && error(new Error(errorMsg));
91
+ }, 300000);
92
+ }
93
+
94
+ if (download.state === 4 || download.state === -1) {
95
+ clearTimeout(timeout);
96
+ }
97
+ });
98
+
99
+ timeout = setTimeout(function() {
100
+ task.abort();
101
+ const errorMsg = '下载超时,请检查网络连接';
102
+ uni.showToast({ title: errorMsg, icon: 'none' });
103
+ error && error(new Error(errorMsg));
104
+ }, 300000);
105
+
106
+ task.start();
107
+ return task;
108
+ // #endif
109
+
110
+ // #ifndef APP-PLUS
111
+ let timeoutFallback;
112
+
13
113
  const downloadTask = uni.downloadFile({
14
114
  url: data.updateFile,
15
- success: (res) => {
16
- clearTimeout(timeout);
115
+ success: function(res) {
116
+ clearTimeout(timeoutFallback);
17
117
 
18
118
  if (res.statusCode === 200) {
19
- // 文件完整性检查
20
119
  if (!res.tempFilePath) {
21
120
  const errorMsg = '下载文件路径为空';
22
121
  uni.showToast({ title: errorMsg, icon: 'none' });
@@ -29,70 +128,63 @@ export function download(data, { success, error, onProgressUpdate, downloadSucce
29
128
  plus.runtime.install(
30
129
  res.tempFilePath,
31
130
  { force: true },
32
- () => {
33
- // wgt升级
131
+ function() {
34
132
  if (package_type == 1) {
35
133
  uni.showModal({
36
134
  title: '提示',
37
135
  content: '升级成功,请重新启动!',
38
136
  confirmText: '确定',
39
137
  showCancel: false,
40
- success: () => {
138
+ success: function() {
41
139
  success && success();
42
140
  plus.runtime.restart();
43
141
  },
44
142
  });
45
143
  } else {
46
- // 整包升级
47
144
  success && success();
48
145
  }
49
146
  },
50
- (e) => {
51
- // 提示部分wgt包无法安装的问题
147
+ function(e) {
52
148
  const errorMsg = e.message || '安装失败';
53
149
  uni.showModal({
54
150
  title: '提示',
55
151
  content: errorMsg,
56
152
  showCancel: false,
57
- success: () => {
153
+ success: function() {
58
154
  error && error(e);
59
155
  },
60
156
  });
61
157
  }
62
158
  );
63
159
  } else {
64
- const errorMsg = `下载失败,状态码:${res.statusCode}`;
160
+ const errorMsg = '下载失败,状态码:' + res.statusCode;
65
161
  uni.showToast({ title: errorMsg, icon: 'none' });
66
162
  error && error(new Error(errorMsg));
67
163
  }
68
164
  },
69
- fail: (err) => {
70
- clearTimeout(timeout);
71
- const errorMsg = `网络请求失败:${err.errMsg || '未知错误'}`;
165
+ fail: function(err) {
166
+ clearTimeout(timeoutFallback);
167
+ const errorMsg = '网络请求失败:' + (err.errMsg || '未知错误');
72
168
  uni.showToast({ title: errorMsg, icon: 'none' });
73
169
  error && error(err);
74
- }
170
+ },
75
171
  });
76
172
 
77
- // 下载进度监控
78
- downloadTask.onProgressUpdate((res) => {
79
- // 添加进度验证
173
+ downloadTask.onProgressUpdate(function(res) {
80
174
  if (res.progress >= 0 && res.progress <= 100) {
81
175
  onProgressUpdate && onProgressUpdate(res);
82
176
  }
83
177
 
84
- // 重置超时计时器
85
- clearTimeout(timeout);
86
- timeout = setTimeout(() => {
178
+ clearTimeout(timeoutFallback);
179
+ timeoutFallback = setTimeout(function() {
87
180
  downloadTask.abort();
88
181
  const errorMsg = '下载超时,请检查网络连接';
89
182
  uni.showToast({ title: errorMsg, icon: 'none' });
90
183
  error && error(new Error(errorMsg));
91
- }, 300000); // 5分钟超时
184
+ }, 300000);
92
185
  });
93
186
 
94
- // 初始超时设置
95
- timeout = setTimeout(() => {
187
+ timeoutFallback = setTimeout(function() {
96
188
  downloadTask.abort();
97
189
  const errorMsg = '下载超时,请检查网络连接';
98
190
  uni.showToast({ title: errorMsg, icon: 'none' });
@@ -100,6 +192,7 @@ export function download(data, { success, error, onProgressUpdate, downloadSucce
100
192
  }, 300000);
101
193
 
102
194
  return downloadTask;
195
+ // #endif
103
196
  }
104
197
 
105
198
  // 获取设备唯一标识
@@ -144,3 +237,70 @@ export const getVersion = (appVersion) => {
144
237
  }
145
238
  });
146
239
  };
240
+
241
+ const DOWNLOAD_STATE_KEY = 'app_update_download_state';
242
+ export const DOWNLOAD_TIMEOUT = 30 * 60 * 1000;
243
+
244
+ export const saveDownloadState = (state) => {
245
+ try {
246
+ uni.setStorageSync(DOWNLOAD_STATE_KEY, JSON.stringify(state));
247
+ } catch (e) {
248
+ console.warn('保存下载状态失败:', e);
249
+ }
250
+ };
251
+
252
+ export const getDownloadState = () => {
253
+ try {
254
+ const stored = uni.getStorageSync(DOWNLOAD_STATE_KEY);
255
+ if (stored) {
256
+ return JSON.parse(stored);
257
+ }
258
+ } catch (e) {
259
+ console.warn('读取下载状态失败:', e);
260
+ }
261
+ return null;
262
+ };
263
+
264
+ export const clearDownloadState = () => {
265
+ try {
266
+ uni.removeStorageSync(DOWNLOAD_STATE_KEY);
267
+ } catch (e) {
268
+ console.warn('清除下载状态失败:', e);
269
+ }
270
+ };
271
+
272
+ export const isDownloadStateExpired = (state) => {
273
+ return Date.now() - state.startTime > DOWNLOAD_TIMEOUT;
274
+ };
275
+
276
+ export const findExistingDownloadTask = (url) => {
277
+ return new Promise(function(resolve) {
278
+ // #ifdef APP-PLUS
279
+ plus.downloader.enumerate(function(tasks) {
280
+ if (!tasks || !tasks.length) {
281
+ resolve(null);
282
+ return;
283
+ }
284
+ for (let i = tasks.length - 1; i >= 0; i--) {
285
+ const task = tasks[i];
286
+ if (task.url === url) {
287
+ if (task.state === 0 || task.state === 1 || task.state === 2 || task.state === 3 || task.state === 4) {
288
+ resolve({ task: task, state: task.state, filename: task.filename || '' });
289
+ return;
290
+ }
291
+ if (task.state === -1) {
292
+ try {
293
+ task.abort();
294
+ } catch (_) {}
295
+ }
296
+ break;
297
+ }
298
+ }
299
+ resolve(null);
300
+ });
301
+ // #endif
302
+ // #ifndef APP-PLUS
303
+ resolve(null);
304
+ // #endif
305
+ });
306
+ };
@@ -39,7 +39,7 @@
39
39
  </view>
40
40
  </template>
41
41
  <script>
42
- import { download, getDeviceId, getPlatform, getAppId, getVersion } from './method';
42
+ import { download, getDeviceId, getPlatform, getAppId, getVersion, saveDownloadState, getDownloadState, clearDownloadState, isDownloadStateExpired, findExistingDownloadTask } from './method';
43
43
 
44
44
  const STORAGE_KEY = 'skipped_app_versions';
45
45
 
@@ -86,6 +86,11 @@ export default {
86
86
  type: String,
87
87
  default: 'https://stellar-public-prd.intecloud.com.cn/api/app-update/check',
88
88
  },
89
+ /** 严格版本检查,设为true时只有新版本大于当前版本才触发更新 */
90
+ strictVersionCheck: {
91
+ type: Boolean,
92
+ default: false,
93
+ },
89
94
  },
90
95
  data() {
91
96
  return {
@@ -107,6 +112,9 @@ export default {
107
112
  skippedVersions: [], // 跳过的版本列表
108
113
  timeoutTimer: null, // 超时计时器
109
114
  downloadTask: null, // 下载任务引用
115
+ nativeDownloadTask: null, // 原生下载任务引用
116
+ nativeDownloadListener: null, // 原生下载监听器
117
+ progressPollTimer: null, // 进度轮询计时器
110
118
  };
111
119
  },
112
120
  methods: {
@@ -134,6 +142,19 @@ export default {
134
142
  isVersionSkipped(versionCode) {
135
143
  return this.skippedVersions.includes(versionCode);
136
144
  },
145
+ // 版本比较函数
146
+ compareVersions(newVersion, currentVersion) {
147
+ const newParts = newVersion.split('.').map(function(v) { return parseInt(v) || 0; });
148
+ const currentParts = currentVersion.split('.').map(function(v) { return parseInt(v) || 0; });
149
+ const maxLength = Math.max(newParts.length, currentParts.length);
150
+ for (let i = 0; i < maxLength; i++) {
151
+ const newPart = newParts[i] || 0;
152
+ const currentPart = currentParts[i] || 0;
153
+ if (newPart > currentPart) return 1;
154
+ if (newPart < currentPart) return -1;
155
+ }
156
+ return 0;
157
+ },
137
158
  // 跳过当前版本
138
159
  skipVersion() {
139
160
  if (!this.data.code) return;
@@ -152,7 +173,100 @@ export default {
152
173
  clearTimeout(this.timeoutTimer);
153
174
  this.timeoutTimer = null;
154
175
  }
176
+ this.stopProgressPolling();
177
+ // #ifdef APP-PLUS
178
+ if (this.nativeDownloadTask && this.nativeDownloadListener) {
179
+ try {
180
+ this.nativeDownloadTask.removeEventListener('statechanged', this.nativeDownloadListener);
181
+ } catch (_) {}
182
+ }
183
+ // #endif
155
184
  this.downloadTask = null;
185
+ this.nativeDownloadTask = null;
186
+ this.nativeDownloadListener = null;
187
+ },
188
+ // 停止进度轮询
189
+ stopProgressPolling() {
190
+ if (this.progressPollTimer) {
191
+ clearInterval(this.progressPollTimer);
192
+ this.progressPollTimer = null;
193
+ }
194
+ },
195
+ // 恢复下载进度
196
+ resumeDownloadProgress(task) {
197
+ // #ifdef APP-PLUS
198
+ if (this.nativeDownloadTask && this.nativeDownloadListener) {
199
+ this.nativeDownloadTask.removeEventListener('statechanged', this.nativeDownloadListener);
200
+ }
201
+ this.stopProgressPolling();
202
+
203
+ this.nativeDownloadTask = task;
204
+
205
+ var self = this;
206
+ var updateProgress = function() {
207
+ if (task.downloadedSize !== undefined && task.totalSize > 0) {
208
+ self.percent = Math.round((task.downloadedSize / task.totalSize) * 100);
209
+ self.downloadedSize = (task.downloadedSize / Math.pow(1024, 2)).toFixed(2);
210
+ self.packageFileSize = (task.totalSize / Math.pow(1024, 2)).toFixed(2);
211
+ }
212
+ };
213
+ updateProgress();
214
+
215
+ this.nativeDownloadListener = function(download) {
216
+ if (download.state === 4) {
217
+ self.stopProgressPolling();
218
+ self.percent = 100;
219
+ self.downloadedSize = self.packageFileSize;
220
+ self.tempFilePath = download.filename;
221
+ if (self.open && self.data.package_type === 1 && download.filename) {
222
+ self.installWgt(download.filename);
223
+ }
224
+ } else if (download.state === -1) {
225
+ self.stopProgressPolling();
226
+ self.updateBtn = true;
227
+ clearDownloadState();
228
+ self.cleanup();
229
+ }
230
+ };
231
+
232
+ task.addEventListener('statechanged', this.nativeDownloadListener);
233
+
234
+ if (task.state === 3) {
235
+ this.progressPollTimer = setInterval(updateProgress, 500);
236
+ }
237
+
238
+ if (task.state === 0) {
239
+ task.start();
240
+ }
241
+ // #endif
242
+ },
243
+ // 安装wgt包
244
+ installWgt(filePath) {
245
+ // #ifdef APP-PLUS
246
+ plus.runtime.install(
247
+ filePath,
248
+ { force: true },
249
+ function() {
250
+ uni.showModal({
251
+ title: '提示',
252
+ content: '升级成功,请重新启动!',
253
+ confirmText: '确定',
254
+ showCancel: false,
255
+ success: function() {
256
+ clearDownloadState();
257
+ plus.runtime.restart();
258
+ },
259
+ });
260
+ },
261
+ function(e) {
262
+ uni.showModal({
263
+ title: '安装失败',
264
+ content: e.message || '安装过程中出现错误',
265
+ showCancel: false,
266
+ });
267
+ }
268
+ );
269
+ // #endif
156
270
  },
157
271
  // 获取跳过版本列表
158
272
  getSkippedVersions() {
@@ -237,7 +351,7 @@ export default {
237
351
  header: {
238
352
  Authorization: `Basic ${btoa(this.clientId + ':' + this.clientSecret)}`,
239
353
  },
240
- success: (res) => {
354
+ success: async (res) => {
241
355
  try {
242
356
  const _data = res.data;
243
357
  if (_data.code == 200 && _data.data) {
@@ -278,7 +392,40 @@ export default {
278
392
  nvs.splice(nvs.length - 1);
279
393
  this.data.name = nvs.join('.');
280
394
  }
281
- if (this.data.updateFile && this.data.code !== this.version) {
395
+ const shouldUpdate = this.strictVersionCheck
396
+ ? this.compareVersions(this.data.name, this.version) > 0
397
+ : this.data.code !== this.version;
398
+ if (this.data.updateFile && shouldUpdate) {
399
+ const downloadState = getDownloadState();
400
+ const hasValidDownloadState = downloadState
401
+ && downloadState.versionCode === this.data.code
402
+ && downloadState.updateFile === this.data.updateFile
403
+ && !isDownloadStateExpired(downloadState);
404
+
405
+ if (hasValidDownloadState) {
406
+ const existing = await findExistingDownloadTask(this.data.updateFile);
407
+
408
+ if (existing) {
409
+ this.open = true;
410
+ this.$emit('update');
411
+ if (existing.state === 0 || existing.state === 1 || existing.state === 2 || existing.state === 3) {
412
+ this.updateBtn = false;
413
+ this.resumeDownloadProgress(existing.task);
414
+ } else if (existing.state === 4) {
415
+ this.updateBtn = false;
416
+ this.tempFilePath = existing.filename;
417
+ if (this.data.package_type === 1 && existing.filename) {
418
+ this.installWgt(existing.filename);
419
+ }
420
+ }
421
+ return;
422
+ }
423
+ }
424
+
425
+ if (downloadState) {
426
+ clearDownloadState();
427
+ }
428
+
282
429
  this.open = true;
283
430
  this.$emit('update');
284
431
  // 如果是强制更新,直接开始下载
@@ -330,7 +477,7 @@ export default {
330
477
  }
331
478
  },
332
479
 
333
- confirm() {
480
+ async confirm() {
334
481
  // 先清理之前的任务
335
482
  this.cleanup();
336
483
 
@@ -340,6 +487,20 @@ export default {
340
487
  return;
341
488
  }
342
489
 
490
+ // #ifdef APP-PLUS
491
+ var self = this;
492
+ var stale = await findExistingDownloadTask(this.data.updateFile);
493
+ if (stale) {
494
+ try { stale.task.abort(); } catch (_) {}
495
+ }
496
+ // #endif
497
+
498
+ saveDownloadState({
499
+ versionCode: this.data.code,
500
+ updateFile: this.data.updateFile,
501
+ startTime: Date.now(),
502
+ });
503
+
343
504
  if (this.data.package_type == 0) {
344
505
  // apk整包升级 下载地址必须以.apk结尾
345
506
  if (this.data.updateFile.includes('.apk')) {
@@ -349,9 +510,11 @@ export default {
349
510
  downloadSuccess: (path) => (this.tempFilePath = path),
350
511
  error: () => {
351
512
  this.updateBtn = true;
513
+ clearDownloadState();
352
514
  this.cleanup();
353
515
  },
354
516
  success: () => {
517
+ clearDownloadState();
355
518
  this.cleanup();
356
519
  },
357
520
  });
@@ -370,9 +533,11 @@ export default {
370
533
  downloadSuccess: (path) => (this.tempFilePath = path),
371
534
  error: () => {
372
535
  this.updateBtn = true;
536
+ clearDownloadState();
373
537
  this.cleanup();
374
538
  },
375
539
  success: () => {
540
+ clearDownloadState();
376
541
  this.cleanup();
377
542
  },
378
543
  });
@@ -430,6 +595,7 @@ export default {
430
595
  if (this.downloadTask) {
431
596
  this.downloadTask.abort();
432
597
  }
598
+ clearDownloadState();
433
599
  this.cleanup();
434
600
  this.updateBtn = true;
435
601
  this.percent = 0;