react-native-update 10.31.2 → 10.32.0

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.
@@ -10,28 +10,9 @@
10
10
  -keepnames class com.facebook.react.devsupport.** { *; }
11
11
 
12
12
  # Keep fields used in reflection
13
- -keepclassmembers class com.facebook.react.ReactInstanceManager {
14
- private JSBundleLoader mBundleLoader;
15
- private String mJSBundleFile;
16
- }
13
+ -keepclassmembers class com.facebook.react.ReactActivity { *; }
14
+ -keepclassmembers class com.facebook.react.ReactInstanceManager { *; }
15
+ -keepclassmembers class com.facebook.react.ReactDelegate { *; }
16
+ -keepclassmembers class com.facebook.react.ReactHost { *; }
17
17
 
18
- -keepclassmembers class com.facebook.react.ReactDelegate {
19
- private ReactHost mReactHost;
20
- }
21
-
22
- -keepclassmembers class com.facebook.react.ReactHost {
23
- private boolean mUseDevSupport;
24
- private ReactHostDelegate mReactHostDelegate;
25
- }
26
-
27
- # Keep Expo related classes
28
18
  -keepnames class expo.modules.ExpoReactHostFactory$ExpoReactHostDelegate { *; }
29
-
30
- # Keep methods used in reflection
31
- -keepclassmembers class com.facebook.react.ReactActivity {
32
- public ReactDelegate getReactDelegate();
33
- }
34
-
35
- -keepclassmembers class com.facebook.react.ReactHost {
36
- public void reload(java.lang.String);
37
- }
@@ -60,13 +60,13 @@ export class DownloadTask {
60
60
  const exists = fileIo.accessSync(params.targetFile);
61
61
  if (exists) {
62
62
  await fileIo.unlink(params.targetFile);
63
- }else{
63
+ } else {
64
64
  const targetDir = params.targetFile.substring(
65
65
  0,
66
66
  params.targetFile.lastIndexOf('/'),
67
67
  );
68
68
  const exists = fileIo.accessSync(targetDir);
69
- if(!exists){
69
+ if (!exists) {
70
70
  await fileIo.mkdir(targetDir);
71
71
  }
72
72
  }
@@ -83,7 +83,7 @@ export class DownloadTask {
83
83
  },
84
84
  });
85
85
  if (response.responseCode > 299) {
86
- throw new Error(`Server error: ${response.responseCode}`);
86
+ throw Error(`Server error: ${response.responseCode}`);
87
87
  }
88
88
 
89
89
  const contentLength = parseInt(response.header['content-length'] || '0');
@@ -108,9 +108,10 @@ export class DownloadTask {
108
108
  const stats = await fileIo.stat(params.targetFile);
109
109
  const fileSize = stats.size;
110
110
  if (fileSize !== contentLength) {
111
- throw new Error(`Download incomplete: expected ${contentLength} bytes but got ${stats.size} bytes`);
111
+ throw Error(
112
+ `Download incomplete: expected ${contentLength} bytes but got ${stats.size} bytes`,
113
+ );
112
114
  }
113
-
114
115
  } catch (error) {
115
116
  console.error('Download failed:', error);
116
117
  throw error;
@@ -142,7 +143,7 @@ export class DownloadTask {
142
143
  bytesRead = await fileIo
143
144
  .read(reader.fd, arrayBuffer)
144
145
  .catch((err: BusinessError) => {
145
- throw new Error(
146
+ throw Error(
146
147
  `Error reading file: ${err.message}, code: ${err.code}`,
147
148
  );
148
149
  });
@@ -154,7 +155,7 @@ export class DownloadTask {
154
155
  length: bytesRead,
155
156
  })
156
157
  .catch((err: BusinessError) => {
157
- throw new Error(
158
+ throw Error(
158
159
  `Error writing file: ${err.message}, code: ${err.code}`,
159
160
  );
160
161
  });
@@ -295,16 +296,16 @@ export class DownloadTask {
295
296
  }
296
297
  }
297
298
 
298
- if(fn !== '.DS_Store'){
299
+ if (fn !== '.DS_Store') {
299
300
  await zip.decompressFile(fn, params.unzipDirectory);
300
301
  }
301
302
  }
302
303
 
303
304
  if (!foundDiff) {
304
- throw new Error('diff.json not found');
305
+ throw Error('diff.json not found');
305
306
  }
306
307
  if (!foundBundlePatch) {
307
- throw new Error('bundle patch not found');
308
+ throw Error('bundle patch not found');
308
309
  }
309
310
  await this.copyFromResource(copyList);
310
311
  }
@@ -366,12 +367,18 @@ export class DownloadTask {
366
367
  new Uint8Array(entry.content),
367
368
  );
368
369
  const outputFile = `${params.unzipDirectory}/bundle.harmony.js`;
369
- const writer = await fileIo.open(outputFile, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);
370
+ const writer = await fileIo.open(
371
+ outputFile,
372
+ fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY,
373
+ );
370
374
  const chunkSize = 4096;
371
375
  let bytesWritten = 0;
372
376
  const totalLength = patched.byteLength;
373
377
  while (bytesWritten < totalLength) {
374
- const chunk = patched.slice(bytesWritten, bytesWritten + chunkSize);
378
+ const chunk = patched.slice(
379
+ bytesWritten,
380
+ bytesWritten + chunkSize,
381
+ );
375
382
  await fileIo.write(writer.fd, chunk);
376
383
  bytesWritten += chunk.byteLength;
377
384
  }
@@ -387,10 +394,10 @@ export class DownloadTask {
387
394
  }
388
395
 
389
396
  if (!foundDiff) {
390
- throw new Error('diff.json not found');
397
+ throw Error('diff.json not found');
391
398
  }
392
399
  if (!foundBundlePatch) {
393
- throw new Error('bundle patch not found');
400
+ throw Error('bundle patch not found');
394
401
  }
395
402
  console.info('Patch from PPK completed');
396
403
  }
@@ -478,7 +485,7 @@ export class DownloadTask {
478
485
  await this.downloadFile(params);
479
486
  break;
480
487
  default:
481
- throw new Error(`Unknown task type: ${params.type}`);
488
+ throw Error(`Unknown task type: ${params.type}`);
482
489
  }
483
490
 
484
491
  params.listener?.onDownloadCompleted(params);
@@ -6,249 +6,276 @@ import common from '@ohos.app.ability.common';
6
6
  import { DownloadTaskParams } from './DownloadTaskParams';
7
7
 
8
8
  export class UpdateContext {
9
- private context: common.UIAbilityContext;
10
- private rootDir: string;
11
- private preferences: preferences.Preferences;
12
- private static DEBUG: boolean = false;
13
- private static isUsingBundleUrl: boolean = false;
14
-
15
- constructor(context: common.UIAbilityContext) {
16
- this.context = context;
17
- this.rootDir = context.filesDir + '/_update';
18
-
19
- try {
20
- if (!fileIo.accessSync(this.rootDir)) {
21
- fileIo.mkdirSync(this.rootDir);
22
- }
23
- } catch (e) {
24
- console.error('Failed to create root directory:', e);
25
- }
26
- this.initPreferences();
27
- }
9
+ private context: common.UIAbilityContext;
10
+ private rootDir: string;
11
+ private preferences: preferences.Preferences;
12
+ private static DEBUG: boolean = false;
13
+ private static isUsingBundleUrl: boolean = false;
28
14
 
29
- private initPreferences() {
30
- try {
31
- this.preferences = preferences.getPreferencesSync(this.context, {name:'update'});
32
- const packageVersion = this.getPackageVersion();
33
- const storedVersion = this.preferences.getSync('packageVersion', '');
34
- if(!storedVersion){
35
- this.preferences.putSync('packageVersion', packageVersion);
36
- this.preferences.flush();
37
- } else if (storedVersion && packageVersion !== storedVersion) {
38
- this.preferences.clear();
39
- this.preferences.putSync('packageVersion', packageVersion);
40
- this.preferences.flush();
41
- this.cleanUp();
42
- }
43
- } catch (e) {
44
- console.error('Failed to init preferences:', e);
45
- }
46
- }
15
+ constructor(context: common.UIAbilityContext) {
16
+ this.context = context;
17
+ this.rootDir = context.filesDir + '/_update';
47
18
 
48
- public setKv(key: string, value: string): void {
49
- this.preferences.putSync(key, value);
50
- this.preferences.flush();
19
+ try {
20
+ if (!fileIo.accessSync(this.rootDir)) {
21
+ fileIo.mkdirSync(this.rootDir);
22
+ }
23
+ } catch (e) {
24
+ console.error('Failed to create root directory:', e);
51
25
  }
26
+ this.initPreferences();
27
+ }
52
28
 
53
- public getKv(key: string): string {
54
- return this.preferences.getSync(key, '') as string;
29
+ private initPreferences() {
30
+ try {
31
+ this.preferences = preferences.getPreferencesSync(this.context, {
32
+ name: 'update',
33
+ });
34
+ const packageVersion = this.getPackageVersion();
35
+ const storedVersion = this.preferences.getSync('packageVersion', '');
36
+ if (!storedVersion) {
37
+ this.preferences.putSync('packageVersion', packageVersion);
38
+ this.preferences.flush();
39
+ } else if (storedVersion && packageVersion !== storedVersion) {
40
+ this.preferences.clear();
41
+ this.preferences.putSync('packageVersion', packageVersion);
42
+ this.preferences.flush();
43
+ this.cleanUp();
44
+ }
45
+ } catch (e) {
46
+ console.error('Failed to init preferences:', e);
55
47
  }
48
+ }
56
49
 
57
- public isFirstTime(): boolean {
58
- return this.preferences.getSync('firstTime', false) as boolean;
59
- }
50
+ public setKv(key: string, value: string): void {
51
+ this.preferences.putSync(key, value);
52
+ this.preferences.flush();
53
+ }
60
54
 
61
- public rolledBackVersion(): string {
62
- return this.preferences.getSync('rolledBackVersion', '') as string;
63
- }
55
+ public getKv(key: string): string {
56
+ return this.preferences.getSync(key, '') as string;
57
+ }
64
58
 
65
- public markSuccess(): void {
66
- this.preferences.putSync('firstTimeOk', true);
67
- const lastVersion = this.preferences.getSync('lastVersion', '') as string;
68
- const curVersion = this.preferences.getSync('currentVersion', '') as string;
69
-
70
- if (lastVersion && lastVersion !== curVersion) {
71
- this.preferences.deleteSync('lastVersion');
72
- this.preferences.deleteSync(`hash_${lastVersion}`);
73
- }
74
- this.preferences.flush();
75
- this.cleanUp();
76
- }
59
+ public isFirstTime(): boolean {
60
+ return this.preferences.getSync('firstTime', false) as boolean;
61
+ }
77
62
 
78
- public clearFirstTime(): void {
79
- this.preferences.putSync('firstTime', false);
80
- this.preferences.flush();
81
- this.cleanUp();
82
- }
63
+ public rolledBackVersion(): string {
64
+ return this.preferences.getSync('rolledBackVersion', '') as string;
65
+ }
83
66
 
84
- public clearRollbackMark(): void {
85
- this.preferences.putSync('rolledBackVersion', null);
86
- this.preferences.flush();
87
- this.cleanUp();
88
- }
67
+ public markSuccess(): void {
68
+ this.preferences.putSync('firstTimeOk', true);
69
+ const lastVersion = this.preferences.getSync('lastVersion', '') as string;
70
+ const curVersion = this.preferences.getSync('currentVersion', '') as string;
89
71
 
90
- public async downloadFullUpdate(url: string, hash: string, listener: DownloadFileListener): Promise<void> {
91
- try {
92
- const params = new DownloadTaskParams();
93
- params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
94
- params.url = url;
95
- params.hash = hash;
96
- params.listener = listener;
97
- params.targetFile = `${this.rootDir}/${hash}.ppk`;
98
- const downloadTask = new DownloadTask(this.context);
99
- await downloadTask.execute(params);
100
- } catch (e) {
101
- console.error('Failed to download full update:', e);
102
- }
72
+ if (lastVersion && lastVersion !== curVersion) {
73
+ this.preferences.deleteSync('lastVersion');
74
+ this.preferences.deleteSync(`hash_${lastVersion}`);
103
75
  }
76
+ this.preferences.flush();
77
+ this.cleanUp();
78
+ }
104
79
 
105
- public async downloadFile(url: string, hash: string, fileName: string, listener: DownloadFileListener): Promise<void> {
106
- const params = new DownloadTaskParams();
107
- params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
108
- params.url = url;
109
- params.hash = hash;
110
- params.listener = listener;
111
- params.targetFile = this.rootDir + '/' + fileName;
80
+ public clearFirstTime(): void {
81
+ this.preferences.putSync('firstTime', false);
82
+ this.preferences.flush();
83
+ this.cleanUp();
84
+ }
112
85
 
113
- const downloadTask = new DownloadTask(this.context);
114
- await downloadTask.execute(params);
115
- }
86
+ public clearRollbackMark(): void {
87
+ this.preferences.putSync('rolledBackVersion', null);
88
+ this.preferences.flush();
89
+ this.cleanUp();
90
+ }
116
91
 
117
- public async downloadPatchFromPpk(url: string, hash: string, originHash: string, listener: DownloadFileListener): Promise<void> {
118
- const params = new DownloadTaskParams();
119
- params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
120
- params.url = url;
121
- params.hash = hash;
122
- params.originHash = originHash;
123
- params.listener = listener;
124
- params.targetFile = `${this.rootDir}/${originHash}_${hash}.ppk.patch`;
125
- params.unzipDirectory = `${this.rootDir}/${hash}`;
126
- params.originDirectory = `${this.rootDir}/${params.originHash}`;
127
-
128
- const downloadTask = new DownloadTask(this.context);
129
- await downloadTask.execute(params);
92
+ public async downloadFullUpdate(
93
+ url: string,
94
+ hash: string,
95
+ listener: DownloadFileListener,
96
+ ): Promise<void> {
97
+ try {
98
+ const params = new DownloadTaskParams();
99
+ params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
100
+ params.url = url;
101
+ params.hash = hash;
102
+ params.listener = listener;
103
+ params.targetFile = `${this.rootDir}/${hash}.ppk`;
104
+ const downloadTask = new DownloadTask(this.context);
105
+ await downloadTask.execute(params);
106
+ } catch (e) {
107
+ console.error('Failed to download full update:', e);
130
108
  }
109
+ }
131
110
 
132
- public async downloadPatchFromPackage(url: string, hash: string, listener: DownloadFileListener): Promise<void> {
133
- try {
134
- const params = new DownloadTaskParams();
135
- params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APP;
136
- params.url = url;
137
- params.hash = hash;
138
- params.listener = listener;
139
- params.targetFile = `${this.rootDir}/${hash}.app.patch`;
140
- params.unzipDirectory = `${this.rootDir}/${hash}`;
141
-
142
- const downloadTask = new DownloadTask(this.context);
143
- return await downloadTask.execute(params);
144
- } catch (e) {
145
- throw e;
146
- console.error('Failed to download APK patch:', e);
147
- }
148
- }
111
+ public async downloadFile(
112
+ url: string,
113
+ hash: string,
114
+ fileName: string,
115
+ listener: DownloadFileListener,
116
+ ): Promise<void> {
117
+ const params = new DownloadTaskParams();
118
+ params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
119
+ params.url = url;
120
+ params.hash = hash;
121
+ params.listener = listener;
122
+ params.targetFile = this.rootDir + '/' + fileName;
149
123
 
150
- public switchVersion(hash: string): void {
151
- try {
152
- const bundlePath = `${this.rootDir}/${hash}/bundle.harmony.js`;
153
- if (!fileIo.accessSync(bundlePath)) {
154
- throw new Error(`Bundle version ${hash} not found.`);
155
- }
156
-
157
- const lastVersion = this.getKv('currentVersion');
158
- this.setKv('currentVersion', hash);
159
- if (lastVersion && lastVersion !== hash) {
160
- this.setKv('lastVersion', lastVersion);
161
- }
162
-
163
- this.setKv('firstTime', 'true');
164
- this.setKv('firstTimeOk', 'false');
165
- this.setKv('rolledBackVersion', "");
166
- } catch (e) {
167
- console.error('Failed to switch version:', e);
168
- }
169
- }
124
+ const downloadTask = new DownloadTask(this.context);
125
+ await downloadTask.execute(params);
126
+ }
170
127
 
171
- public static getBundleUrl(context: common.UIAbilityContext, defaultAssetsUrl?: string): string {
172
- return new UpdateContext(context).getBundleUrl(defaultAssetsUrl);
173
- }
128
+ public async downloadPatchFromPpk(
129
+ url: string,
130
+ hash: string,
131
+ originHash: string,
132
+ listener: DownloadFileListener,
133
+ ): Promise<void> {
134
+ const params = new DownloadTaskParams();
135
+ params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
136
+ params.url = url;
137
+ params.hash = hash;
138
+ params.originHash = originHash;
139
+ params.listener = listener;
140
+ params.targetFile = `${this.rootDir}/${originHash}_${hash}.ppk.patch`;
141
+ params.unzipDirectory = `${this.rootDir}/${hash}`;
142
+ params.originDirectory = `${this.rootDir}/${params.originHash}`;
174
143
 
175
- public getBundleUrl(defaultAssetsUrl?: string): string {
176
- UpdateContext.isUsingBundleUrl = true;
177
- const currentVersion = this.getCurrentVersion();
178
- if (!currentVersion) {
179
- return defaultAssetsUrl;
180
- }
181
- if (!this.isFirstTime()) {
182
- if (!this.preferences.getSync('firstTimeOk', true)) {
183
- return this.rollBack();
184
- }
185
- }
186
- let version = currentVersion;
187
- while (version) {
188
- const bundleFile = `${this.rootDir}/${version}/bundle.harmony.js`;
189
- try {
190
- if (!fileIo.accessSync(bundleFile)) {
191
- console.error(`Bundle version ${version} not found.`);
192
- version = this.rollBack();
193
- continue;
194
- }
195
- return bundleFile;
196
- } catch (e) {
197
- console.error('Failed to access bundle file:', e);
198
- version = this.rollBack();
199
- }
200
- }
201
- return defaultAssetsUrl;
202
- }
144
+ const downloadTask = new DownloadTask(this.context);
145
+ await downloadTask.execute(params);
146
+ }
203
147
 
204
- getPackageVersion(): string {
205
- let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
206
- let packageVersion = '';
207
- try {
208
- const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleFlags);
209
- packageVersion = bundleInfo?.versionName || "Unknown";
210
- } catch (error) {
211
- console.error("获取包信息失败:", error);
212
- }
213
- return packageVersion;
148
+ public async downloadPatchFromPackage(
149
+ url: string,
150
+ hash: string,
151
+ listener: DownloadFileListener,
152
+ ): Promise<void> {
153
+ try {
154
+ const params = new DownloadTaskParams();
155
+ params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APP;
156
+ params.url = url;
157
+ params.hash = hash;
158
+ params.listener = listener;
159
+ params.targetFile = `${this.rootDir}/${hash}.app.patch`;
160
+ params.unzipDirectory = `${this.rootDir}/${hash}`;
161
+
162
+ const downloadTask = new DownloadTask(this.context);
163
+ return await downloadTask.execute(params);
164
+ } catch (e) {
165
+ throw e;
166
+ console.error('Failed to download APK patch:', e);
214
167
  }
168
+ }
169
+
170
+ public switchVersion(hash: string): void {
171
+ try {
172
+ const bundlePath = `${this.rootDir}/${hash}/bundle.harmony.js`;
173
+ if (!fileIo.accessSync(bundlePath)) {
174
+ throw Error(`Bundle version ${hash} not found.`);
175
+ }
176
+
177
+ const lastVersion = this.getKv('currentVersion');
178
+ this.setKv('currentVersion', hash);
179
+ if (lastVersion && lastVersion !== hash) {
180
+ this.setKv('lastVersion', lastVersion);
181
+ }
215
182
 
216
- public getCurrentVersion() : string {
217
- const currentVersion = this.getKv('currentVersion');
218
- return currentVersion;
183
+ this.setKv('firstTime', 'true');
184
+ this.setKv('firstTimeOk', 'false');
185
+ this.setKv('rolledBackVersion', '');
186
+ } catch (e) {
187
+ console.error('Failed to switch version:', e);
219
188
  }
189
+ }
220
190
 
221
- private rollBack(): string {
222
- const lastVersion = this.preferences.getSync('lastVersion', '') as string;
223
- const currentVersion = this.preferences.getSync('currentVersion', '') as string;
224
- if (!lastVersion) {
225
- this.preferences.deleteSync('currentVersion');
226
- } else {
227
- this.preferences.putSync('currentVersion', lastVersion);
191
+ public static getBundleUrl(
192
+ context: common.UIAbilityContext,
193
+ defaultAssetsUrl?: string,
194
+ ): string {
195
+ return new UpdateContext(context).getBundleUrl(defaultAssetsUrl);
196
+ }
197
+
198
+ public getBundleUrl(defaultAssetsUrl?: string): string {
199
+ UpdateContext.isUsingBundleUrl = true;
200
+ const currentVersion = this.getCurrentVersion();
201
+ if (!currentVersion) {
202
+ return defaultAssetsUrl;
203
+ }
204
+ if (!this.isFirstTime()) {
205
+ if (!this.preferences.getSync('firstTimeOk', true)) {
206
+ return this.rollBack();
207
+ }
208
+ }
209
+ let version = currentVersion;
210
+ while (version) {
211
+ const bundleFile = `${this.rootDir}/${version}/bundle.harmony.js`;
212
+ try {
213
+ if (!fileIo.accessSync(bundleFile)) {
214
+ console.error(`Bundle version ${version} not found.`);
215
+ version = this.rollBack();
216
+ continue;
228
217
  }
229
- this.preferences.putSync('firstTimeOk', true);
230
- this.preferences.putSync('firstTime', false);
231
- this.preferences.putSync('rolledBackVersion', currentVersion);
232
- this.preferences.flush();
233
- return lastVersion;
218
+ return bundleFile;
219
+ } catch (e) {
220
+ console.error('Failed to access bundle file:', e);
221
+ version = this.rollBack();
222
+ }
234
223
  }
224
+ return defaultAssetsUrl;
225
+ }
235
226
 
236
- private cleanUp(): void {
237
- const params = new DownloadTaskParams();
238
- params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
239
- params.hash = this.preferences.getSync('currentVersion', '') as string;
240
- params.originHash = this.preferences.getSync('lastVersion', '') as string;
241
- params.unzipDirectory = this.rootDir;
242
- const downloadTask = new DownloadTask(this.context);
243
- downloadTask.execute(params);
227
+ getPackageVersion(): string {
228
+ let bundleFlags =
229
+ bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
230
+ let packageVersion = '';
231
+ try {
232
+ const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleFlags);
233
+ packageVersion = bundleInfo?.versionName || 'Unknown';
234
+ } catch (error) {
235
+ console.error('获取包信息失败:', error);
244
236
  }
237
+ return packageVersion;
238
+ }
239
+
240
+ public getCurrentVersion(): string {
241
+ const currentVersion = this.getKv('currentVersion');
242
+ return currentVersion;
243
+ }
245
244
 
246
- public getIsUsingBundleUrl(): boolean {
247
- return UpdateContext.isUsingBundleUrl;
245
+ private rollBack(): string {
246
+ const lastVersion = this.preferences.getSync('lastVersion', '') as string;
247
+ const currentVersion = this.preferences.getSync(
248
+ 'currentVersion',
249
+ '',
250
+ ) as string;
251
+ if (!lastVersion) {
252
+ this.preferences.deleteSync('currentVersion');
253
+ } else {
254
+ this.preferences.putSync('currentVersion', lastVersion);
248
255
  }
256
+ this.preferences.putSync('firstTimeOk', true);
257
+ this.preferences.putSync('firstTime', false);
258
+ this.preferences.putSync('rolledBackVersion', currentVersion);
259
+ this.preferences.flush();
260
+ return lastVersion;
261
+ }
262
+
263
+ private cleanUp(): void {
264
+ const params = new DownloadTaskParams();
265
+ params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
266
+ params.hash = this.preferences.getSync('currentVersion', '') as string;
267
+ params.originHash = this.preferences.getSync('lastVersion', '') as string;
268
+ params.unzipDirectory = this.rootDir;
269
+ const downloadTask = new DownloadTask(this.context);
270
+ downloadTask.execute(params);
271
+ }
272
+
273
+ public getIsUsingBundleUrl(): boolean {
274
+ return UpdateContext.isUsingBundleUrl;
275
+ }
249
276
  }
250
277
 
251
278
  export interface DownloadFileListener {
252
- onDownloadCompleted(params: DownloadTaskParams): void;
253
- onDownloadFailed(error: Error): void;
254
- }
279
+ onDownloadCompleted(params: DownloadTaskParams): void;
280
+ onDownloadFailed(error: Error): void;
281
+ }
@@ -4,14 +4,14 @@ import { UpdateContext } from './UpdateContext';
4
4
  import { DownloadTaskParams } from './DownloadTaskParams';
5
5
  import logger from './Logger';
6
6
 
7
- const TAG = "UpdateModuleImpl";
7
+ const TAG = 'UpdateModuleImpl';
8
8
 
9
9
  export class UpdateModuleImpl {
10
- static readonly NAME = "Pushy";
10
+ static readonly NAME = 'Pushy';
11
11
 
12
12
  static async downloadFullUpdate(
13
- updateContext: UpdateContext,
14
- options: { updateUrl: string; hash: string }
13
+ updateContext: UpdateContext,
14
+ options: { updateUrl: string; hash: string },
15
15
  ): Promise<void> {
16
16
  try {
17
17
  await updateContext.downloadFullUpdate(options.updateUrl, options.hash, {
@@ -20,7 +20,7 @@ export class UpdateModuleImpl {
20
20
  },
21
21
  onDownloadFailed: (error: Error) => {
22
22
  return Promise.reject(error);
23
- }
23
+ },
24
24
  });
25
25
  } catch (error) {
26
26
  logger.error(TAG, `downloadFullUpdate failed: ${error}`);
@@ -30,18 +30,18 @@ export class UpdateModuleImpl {
30
30
 
31
31
  static async downloadAndInstallApk(
32
32
  context: common.UIAbilityContext,
33
- options: { url: string; hash: string; target: string }
33
+ options: { url: string; hash: string; target: string },
34
34
  ): Promise<void> {
35
35
  try {
36
36
  const want = {
37
37
  action: 'action.system.home',
38
38
  parameters: {
39
- uri: 'appmarket://details'
40
- }
39
+ uri: 'appmarket://details',
40
+ },
41
41
  };
42
42
 
43
43
  if (!context) {
44
- throw new Error('获取context失败');
44
+ throw Error('获取context失败');
45
45
  }
46
46
 
47
47
  await context.startAbility(want);
@@ -53,17 +53,21 @@ export class UpdateModuleImpl {
53
53
 
54
54
  static async downloadPatchFromPackage(
55
55
  updateContext: UpdateContext,
56
- options: { updateUrl: string; hash: string }
56
+ options: { updateUrl: string; hash: string },
57
57
  ): Promise<void> {
58
58
  try {
59
- return await updateContext.downloadPatchFromPackage(options.updateUrl, options.hash, {
60
- onDownloadCompleted: (params: DownloadTaskParams) => {
61
- return Promise.resolve();
59
+ return await updateContext.downloadPatchFromPackage(
60
+ options.updateUrl,
61
+ options.hash,
62
+ {
63
+ onDownloadCompleted: (params: DownloadTaskParams) => {
64
+ return Promise.resolve();
65
+ },
66
+ onDownloadFailed: (error: Error) => {
67
+ return Promise.reject(error);
68
+ },
62
69
  },
63
- onDownloadFailed: (error: Error) => {
64
- return Promise.reject(error);
65
- }
66
- });
70
+ );
67
71
  } catch (error) {
68
72
  logger.error(TAG, `downloadPatchFromPackage failed: ${error}`);
69
73
  throw error;
@@ -72,7 +76,7 @@ export class UpdateModuleImpl {
72
76
 
73
77
  static async downloadPatchFromPpk(
74
78
  updateContext: UpdateContext,
75
- options: { updateUrl: string; hash: string; originHash: string }
79
+ options: { updateUrl: string; hash: string; originHash: string },
76
80
  ): Promise<void> {
77
81
  try {
78
82
  await updateContext.downloadPatchFromPpk(
@@ -85,49 +89,49 @@ export class UpdateModuleImpl {
85
89
  },
86
90
  onDownloadFailed: (error: Error) => {
87
91
  return Promise.reject(error);
88
- }
89
- }
92
+ },
93
+ },
90
94
  );
91
95
  } catch (error) {
92
96
  logger.error(TAG, `downloadPatchFromPpk failed: ${error}`);
93
- throw new Error(`执行报错: ${error.message}`);
97
+ throw Error(`执行报错: ${error.message}`);
94
98
  }
95
99
  }
96
100
 
97
101
  static async reloadUpdate(
98
102
  updateContext: UpdateContext,
99
103
  context: common.UIAbilityContext,
100
- options: { hash: string }
104
+ options: { hash: string },
101
105
  ): Promise<void> {
102
106
  const hash = options.hash;
103
107
  if (!hash) {
104
- throw new Error('hash不能为空');
108
+ throw Error('hash不能为空');
105
109
  }
106
110
 
107
111
  try {
108
112
  await updateContext.switchVersion(hash);
109
113
  const bundleInfo = await bundleManager.getBundleInfoForSelf(
110
- bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION
114
+ bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION,
111
115
  );
112
116
  await context.terminateSelf();
113
117
  const want = {
114
118
  bundleName: bundleInfo.name,
115
- abilityName: context.abilityInfo?.name
119
+ abilityName: context.abilityInfo?.name,
116
120
  };
117
121
  await context.startAbility(want);
118
122
  } catch (error) {
119
123
  logger.error(TAG, `reloadUpdate failed: ${error}`);
120
- throw new Error(`pushy:switchVersion failed ${error.message}`);
124
+ throw Error(`pushy:switchVersion failed ${error.message}`);
121
125
  }
122
126
  }
123
127
 
124
128
  static async setNeedUpdate(
125
129
  updateContext: UpdateContext,
126
- options: { hash: string }
130
+ options: { hash: string },
127
131
  ): Promise<boolean> {
128
132
  const hash = options.hash;
129
133
  if (!hash) {
130
- throw new Error('hash不能为空');
134
+ throw Error('hash不能为空');
131
135
  }
132
136
 
133
137
  try {
@@ -135,7 +139,7 @@ export class UpdateModuleImpl {
135
139
  return true;
136
140
  } catch (error) {
137
141
  logger.error(TAG, `setNeedUpdate failed: ${error}`);
138
- throw new Error(`switchVersionLater failed: ${error.message}`);
142
+ throw Error(`switchVersionLater failed: ${error.message}`);
139
143
  }
140
144
  }
141
145
 
@@ -145,20 +149,20 @@ export class UpdateModuleImpl {
145
149
  return true;
146
150
  } catch (error) {
147
151
  logger.error(TAG, `markSuccess failed: ${error}`);
148
- throw new Error(`执行报错: ${error.message}`);
152
+ throw Error(`执行报错: ${error.message}`);
149
153
  }
150
154
  }
151
155
 
152
156
  static async setUuid(
153
157
  updateContext: UpdateContext,
154
- uuid: string
158
+ uuid: string,
155
159
  ): Promise<boolean> {
156
160
  try {
157
161
  await updateContext.setKv('uuid', uuid);
158
162
  return true;
159
163
  } catch (error) {
160
164
  logger.error(TAG, `setUuid failed: ${error}`);
161
- throw new Error(`执行报错: ${error.message}`);
165
+ throw Error(`执行报错: ${error.message}`);
162
166
  }
163
167
  }
164
168
 
@@ -174,17 +178,14 @@ export class UpdateModuleImpl {
174
178
  static setLocalHashInfo(
175
179
  updateContext: UpdateContext,
176
180
  hash: string,
177
- info: string
181
+ info: string,
178
182
  ): boolean {
179
183
  updateContext.setKv(`hash_${hash}`, info);
180
184
  return true;
181
185
  }
182
186
 
183
- static getLocalHashInfo(
184
- updateContext: UpdateContext,
185
- hash: string
186
- ): string {
187
+ static getLocalHashInfo(updateContext: UpdateContext, hash: string): string {
187
188
  const value = updateContext.getKv(`hash_${hash}`);
188
189
  return value;
189
190
  }
190
- }
191
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-update",
3
- "version": "10.31.2",
3
+ "version": "10.32.0",
4
4
  "description": "react-native hot update",
5
5
  "main": "src/index",
6
6
  "scripts": {
@@ -72,6 +72,5 @@
72
72
  "react-native": "0.73",
73
73
  "ts-jest": "^29.3.2",
74
74
  "typescript": "^5.6.3"
75
- },
76
- "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
75
+ }
77
76
  }
package/src/client.ts CHANGED
@@ -93,7 +93,6 @@ export class Pushy {
93
93
  clientType: 'Pushy' | 'Cresc' = 'Pushy';
94
94
  lastChecking?: number;
95
95
  lastRespJson?: Promise<CheckResult>;
96
- lastRespText?: Promise<string>;
97
96
 
98
97
  version = cInfo.rnu;
99
98
  loggerPromise = (() => {
@@ -116,7 +115,7 @@ export class Pushy {
116
115
 
117
116
  if (Platform.OS === 'ios' || Platform.OS === 'android') {
118
117
  if (!options.appKey) {
119
- throw new Error(i18n.t('error_appkey_required'));
118
+ throw Error(i18n.t('error_appkey_required'));
120
119
  }
121
120
  }
122
121
 
@@ -293,10 +292,10 @@ export class Pushy {
293
292
  ),
294
293
  );
295
294
  } catch (err: any) {
296
- this.throwIfEnabled(new Error('errorCheckingUseBackup'));
295
+ this.throwIfEnabled(Error('errorCheckingUseBackup'));
297
296
  }
298
297
  } else {
299
- this.throwIfEnabled(new Error('errorCheckingGetBackup'));
298
+ this.throwIfEnabled(Error('errorCheckingGetBackup'));
300
299
  }
301
300
  }
302
301
  if (!resp) {
@@ -304,21 +303,21 @@ export class Pushy {
304
303
  type: 'errorChecking',
305
304
  message: this.t('error_cannot_connect_server'),
306
305
  });
307
- this.throwIfEnabled(new Error('errorChecking'));
306
+ this.throwIfEnabled(Error('errorChecking'));
308
307
  return this.lastRespJson ? await this.lastRespJson : emptyObj;
309
308
  }
310
309
 
311
- if (resp.status !== 200) {
310
+ if (!resp.ok) {
311
+ const respText = await resp.text();
312
312
  const errorMessage = this.t('error_http_status', {
313
313
  status: resp.status,
314
- statusText: resp.statusText,
314
+ statusText: respText,
315
315
  });
316
316
  this.report({
317
317
  type: 'errorChecking',
318
318
  message: errorMessage,
319
319
  });
320
- this.throwIfEnabled(new Error(errorMessage));
321
- log('error checking response:', resp.status, await resp.text());
320
+ this.throwIfEnabled(Error(errorMessage));
322
321
  return this.lastRespJson ? await this.lastRespJson : emptyObj;
323
322
  }
324
323
  this.lastRespJson = resp.json();
@@ -435,7 +434,7 @@ export class Pushy {
435
434
  message: e.message,
436
435
  });
437
436
  errorMessages.push(errorMessage);
438
- lastError = new Error(errorMessage);
437
+ lastError = Error(errorMessage);
439
438
  log(errorMessage);
440
439
  }
441
440
  }
@@ -454,7 +453,7 @@ export class Pushy {
454
453
  message: e.message,
455
454
  });
456
455
  errorMessages.push(errorMessage);
457
- lastError = new Error(errorMessage);
456
+ lastError = Error(errorMessage);
458
457
  log(errorMessage);
459
458
  }
460
459
  }
@@ -474,7 +473,7 @@ export class Pushy {
474
473
  message: e.message,
475
474
  });
476
475
  errorMessages.push(errorMessage);
477
- lastError = new Error(errorMessage);
476
+ lastError = Error(errorMessage);
478
477
  log(errorMessage);
479
478
  }
480
479
  } else if (__DEV__) {
@@ -532,7 +531,7 @@ export class Pushy {
532
531
  }
533
532
  if (sharedState.apkStatus === 'downloaded') {
534
533
  this.report({ type: 'errorInstallApk' });
535
- this.throwIfEnabled(new Error('errorInstallApk'));
534
+ this.throwIfEnabled(Error('errorInstallApk'));
536
535
  return;
537
536
  }
538
537
  if (Platform.Version <= 23) {
@@ -542,7 +541,7 @@ export class Pushy {
542
541
  );
543
542
  if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
544
543
  this.report({ type: 'rejectStoragePermission' });
545
- this.throwIfEnabled(new Error('rejectStoragePermission'));
544
+ this.throwIfEnabled(Error('rejectStoragePermission'));
546
545
  return;
547
546
  }
548
547
  } catch (e: any) {
@@ -575,7 +574,7 @@ export class Pushy {
575
574
  }).catch(() => {
576
575
  sharedState.apkStatus = null;
577
576
  this.report({ type: 'errorDownloadAndInstallApk' });
578
- this.throwIfEnabled(new Error('errorDownloadAndInstallApk'));
577
+ this.throwIfEnabled(Error('errorDownloadAndInstallApk'));
579
578
  });
580
579
  sharedState.apkStatus = 'downloaded';
581
580
  if (sharedState.progressHandlers[progressKey]) {
package/src/core.ts CHANGED
@@ -18,7 +18,7 @@ export const PushyModule =
18
18
  export const UpdateModule = PushyModule;
19
19
 
20
20
  if (!PushyModule) {
21
- throw new Error(
21
+ throw Error(
22
22
  'Failed to load react-native-update native module, please try to recompile',
23
23
  );
24
24
  }
package/src/provider.tsx CHANGED
@@ -16,9 +16,9 @@ import { Pushy, Cresc, sharedState } from './client';
16
16
  import { currentVersion, packageVersion, getCurrentVersionInfo, currentVersionInfo } from './core';
17
17
  import {
18
18
  CheckResult,
19
- MixedCheckResult,
20
19
  ProgressData,
21
20
  UpdateTestPayload,
21
+ VersionInfo,
22
22
  } from './type';
23
23
  import { UpdateContext } from './context';
24
24
  import { URL } from 'react-native-url-polyfill';
@@ -163,7 +163,7 @@ export const UpdateProvider = ({
163
163
  return;
164
164
  }
165
165
  lastChecking.current = now;
166
- let rootInfo: MixedCheckResult | undefined;
166
+ let rootInfo: CheckResult | undefined;
167
167
  try {
168
168
  rootInfo = await client.checkUpdate(extra);
169
169
  } catch (e: any) {
@@ -175,8 +175,8 @@ export const UpdateProvider = ({
175
175
  if (!rootInfo) {
176
176
  return;
177
177
  }
178
- const versions = rootInfo.versions || [rootInfo as CheckResult];
179
- delete rootInfo.versions;
178
+ const versions = [rootInfo.expVersion, rootInfo].filter(Boolean) as VersionInfo[];
179
+ delete rootInfo.expVersion;
180
180
  for (const versionInfo of versions) {
181
181
  const info: CheckResult = {
182
182
  ...versionInfo,
@@ -242,7 +242,7 @@ export const UpdateProvider = ({
242
242
  alertUpdate(
243
243
  client.t('alert_title'),
244
244
  client.t('alert_new_version_found', {
245
- name: info.name,
245
+ name: info.name!,
246
246
  description: info.description,
247
247
  }),
248
248
  [
package/src/type.ts CHANGED
@@ -24,14 +24,10 @@ interface RootResult {
24
24
  paths?: string[];
25
25
  }
26
26
 
27
- export type CheckResult = RootResult & VersionInfo;
28
-
29
- export type CheckResultV2 = RootResult & {
30
- versions?: VersionInfo[];
31
- };
32
-
33
- export type MixedCheckResult = CheckResult | CheckResultV2;
34
-
27
+ export type CheckResult = RootResult &
28
+ Partial<VersionInfo> & {
29
+ expVersion?: VersionInfo;
30
+ };
35
31
 
36
32
  export interface ProgressData {
37
33
  hash: string;
package/src/utils.ts CHANGED
@@ -17,7 +17,7 @@ export function promiseAny<T>(promises: Promise<T>[]) {
17
17
  .catch(() => {
18
18
  count++;
19
19
  if (count === promises.length) {
20
- reject(new Error(i18n.t('error_all_promises_rejected')));
20
+ reject(Error(i18n.t('error_all_promises_rejected')));
21
21
  }
22
22
  });
23
23
  });
@@ -51,7 +51,7 @@ const ping = isWeb
51
51
  return finalUrl;
52
52
  }
53
53
  log('ping failed', url, status, statusText);
54
- throw new Error(i18n.t('error_ping_failed'));
54
+ throw Error(i18n.t('error_ping_failed'));
55
55
  })
56
56
  .catch(e => {
57
57
  pingFinished = true;
@@ -60,7 +60,7 @@ const ping = isWeb
60
60
  }),
61
61
  new Promise((_, reject) =>
62
62
  setTimeout(() => {
63
- reject(new Error(i18n.t('error_ping_timeout')));
63
+ reject(Error(i18n.t('error_ping_timeout')));
64
64
  if (!pingFinished) {
65
65
  log('ping timeout', url);
66
66
  }
@@ -115,7 +115,7 @@ export const enhancedFetch = async (
115
115
  if (r.ok) {
116
116
  return r;
117
117
  }
118
- throw new Error(
118
+ throw Error(
119
119
  i18n.t('error_http_status', {
120
120
  status: r.status,
121
121
  statusText: r.statusText,