react-native-update 10.39.1 → 10.40.0-beta.1

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.
Files changed (39) hide show
  1. package/android/build.gradle +0 -1
  2. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +314 -0
  3. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +253 -586
  4. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +220 -0
  5. package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +9 -3
  6. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +36 -0
  7. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +36 -26
  8. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +39 -0
  9. package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +74 -0
  10. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +143 -260
  11. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleSupport.java +63 -0
  12. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +1 -5
  13. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +26 -73
  14. package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +28 -242
  15. package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +89 -135
  16. package/harmony/pushy/src/main/cpp/PushyTurboModule.h +5 -5
  17. package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +7 -7
  18. package/harmony/pushy/src/main/ets/PushyPackage.ets +3 -9
  19. package/harmony/pushy/src/main/ets/PushyPackageCompat.ts +3 -9
  20. package/harmony/pushy/src/main/ets/PushyPackageFactory.ts +14 -0
  21. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +124 -24
  22. package/harmony/pushy/src/main/ets/UpdateContext.ts +92 -70
  23. package/harmony/pushy.har +0 -0
  24. package/ios/Expo/ExpoPushyReactDelegateHandler.swift +6 -26
  25. package/ios/RCTPushy/RCTPushy.mm +315 -259
  26. package/ios/RCTPushy/RCTPushyDownloader.mm +52 -29
  27. package/package/harmony/pushy.har +0 -0
  28. package/package.json +11 -11
  29. package/react-native-update-10.40.0-beta.0.tgz +0 -0
  30. package/react-native-update.podspec +3 -3
  31. package/src/utils.ts +7 -1
  32. package/harmony/pushy/src/main/ets/UpdateModuleImpl.ts +0 -123
  33. package/ios/ImportReact.h +0 -2
  34. package/ios/RCTPushy/HDiffPatch/HDiffPatch.h +0 -16
  35. package/ios/RCTPushy/HDiffPatch/HDiffPatch.mm +0 -35
  36. package/ios/RCTPushy/RCTPushyManager.h +0 -27
  37. package/ios/RCTPushy/RCTPushyManager.mm +0 -181
  38. package/ios/RCTPushy.xcodeproj/project.pbxproj +0 -479
  39. package/react-native-update-10.39.0.tgz +0 -0
@@ -1,6 +1,6 @@
1
1
  #import "RCTPushy.h"
2
2
  #import "RCTPushyDownloader.h"
3
- #import "RCTPushyManager.h"
3
+ #import "ZipArchive.h"
4
4
  #include "../../cpp/patch_core/archive_patch_core.h"
5
5
  #include "../../cpp/patch_core/patch_core.h"
6
6
  #include "../../cpp/patch_core/state_core.h"
@@ -8,14 +8,12 @@
8
8
  #if __has_include("RCTReloadCommand.h")
9
9
  #import "RCTReloadCommand.h"
10
10
  #endif
11
- // Thanks to this guard, we won't import this header when we build for the old architecture.
12
11
  #ifdef RCT_NEW_ARCH_ENABLED
13
12
  #import "RCTPushySpec.h"
14
13
  #endif
15
14
 
16
15
  #import <React/RCTConvert.h>
17
16
  #import <React/RCTLog.h>
18
- // #import <React/RCTReloadCommand.h>
19
17
 
20
18
  static NSString *const keyPushyInfo = @"REACTNATIVECN_PUSHY_INFO_KEY";
21
19
  static NSString *const paramPackageVersion = @"packageVersion";
@@ -29,10 +27,7 @@ static NSString *const keyHashInfo = @"REACTNATIVECN_PUSHY_HASH_";
29
27
  static NSString *const keyFirstLoadMarked = @"REACTNATIVECN_PUSHY_FIRSTLOADMARKED_KEY";
30
28
  static NSString *const keyRolledBackMarked = @"REACTNATIVECN_PUSHY_ROLLEDBACKMARKED_KEY";
31
29
  static NSString *const KeyPackageUpdatedMarked = @"REACTNATIVECN_PUSHY_ISPACKAGEUPDATEDMARKED_KEY";
32
-
33
- // app info
34
- static NSString * const AppVersionKey = @"appVersion";
35
- static NSString * const BuildVersionKey = @"buildVersion";
30
+ static NSString *const PushyErrorDomain = @"cn.reactnative.pushy";
36
31
 
37
32
  // file def
38
33
  static NSString * const BUNDLE_FILE_NAME = @"index.bundlejs";
@@ -41,12 +36,10 @@ static NSString * const BUNDLE_PATCH_NAME = @"index.bundlejs.patch";
41
36
 
42
37
  // error def
43
38
  static NSString * const ERROR_OPTIONS = @"options error";
44
- static NSString * const ERROR_HDIFFPATCH = @"hdiffpatch error";
45
39
  static NSString * const ERROR_FILE_OPERATION = @"file operation error";
46
40
 
47
41
  // event def
48
42
  static NSString * const EVENT_PROGRESS_DOWNLOAD = @"RCTPushyDownloadProgress";
49
- // static NSString * const EVENT_PROGRESS_UNZIP = @"RCTPushyUnzipProgress";
50
43
  static NSString * const PARAM_PROGRESS_HASH = @"hash";
51
44
  static NSString * const PARAM_PROGRESS_RECEIVED = @"received";
52
45
  static NSString * const PARAM_PROGRESS_TOTAL = @"total";
@@ -69,11 +62,15 @@ static std::string PushyToStdString(NSString *value) {
69
62
  }
70
63
 
71
64
  static NSError *PushyNSErrorFromStatus(const pushy::patch::Status &status) {
72
- return [NSError errorWithDomain:@"cn.reactnative.pushy"
65
+ return [NSError errorWithDomain:PushyErrorDomain
73
66
  code:-1
74
67
  userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithUTF8String:status.message.c_str()] }];
75
68
  }
76
69
 
70
+ static NSUserDefaults *PushyDefaults(void) {
71
+ return [NSUserDefaults standardUserDefaults];
72
+ }
73
+
77
74
  static NSString *PushyFromStdString(const std::string &value) {
78
75
  if (value.empty()) {
79
76
  return nil;
@@ -89,6 +86,37 @@ static void PushySetNullableString(NSUserDefaults *defaults, NSString *key, NSSt
89
86
  }
90
87
  }
91
88
 
89
+ static NSString *PushyHashInfoKey(NSString *hash) {
90
+ return [keyHashInfo stringByAppendingString:hash ?: @""];
91
+ }
92
+
93
+ static NSString *PushyOptionString(NSDictionary *options, NSString *key) {
94
+ return [RCTConvert NSString:options[key]];
95
+ }
96
+
97
+ static BOOL PushyStringIsBlank(NSString *value) {
98
+ if (value == nil || [value isKindOfClass:[NSNull class]]) {
99
+ return YES;
100
+ }
101
+ return [[value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;
102
+ }
103
+
104
+ static void PushyRejectError(RCTPromiseRejectBlock reject, NSError *error) {
105
+ reject([NSString stringWithFormat:@"%ld", (long)error.code], error.localizedDescription, error);
106
+ }
107
+
108
+ static NSError *PushyErrorWithMessage(NSString *message) {
109
+ return [NSError errorWithDomain:PushyErrorDomain
110
+ code:-1
111
+ userInfo:@{
112
+ NSLocalizedDescriptionKey: message ?: @"unknown error",
113
+ }];
114
+ }
115
+
116
+ static void PushyRejectMessage(RCTPromiseRejectBlock reject, NSString *message) {
117
+ PushyRejectError(reject, PushyErrorWithMessage(message));
118
+ }
119
+
92
120
  static pushy::patch::PatchManifest PushyPatchManifestFromJson(NSDictionary *json) {
93
121
  pushy::patch::PatchManifest manifest;
94
122
 
@@ -155,36 +183,48 @@ static void PushyApplyStateToDefaults(NSUserDefaults *defaults, const pushy::sta
155
183
  }
156
184
 
157
185
  @interface RCTPushy ()
158
- - (void)_dopatch:(NSString *)hash
159
- type:(PushyType)type
160
- fromBundle:(NSString *)bundleOrigin
161
- source:(NSString *)sourceOrigin
162
- callback:(void (^)(NSError *error))callback;
163
- - (void)patch:(NSString *)hash
164
- type:(PushyType)type
165
- fromBundle:(NSString *)bundleOrigin
166
- source:(NSString *)sourceOrigin
167
- callback:(void (^)(NSError *error))callback;
186
+ - (void)downloadUpdate:(PushyType)type
187
+ options:(NSDictionary *)options
188
+ resolver:(RCTPromiseResolveBlock)resolve
189
+ rejecter:(RCTPromiseRejectBlock)reject;
190
+ - (void)performUpdate:(PushyType)type
191
+ options:(NSDictionary *)options
192
+ callback:(void (^)(NSError *error))callback;
193
+ - (void)reloadBridgeWithReason:(NSString *)reason;
194
+ - (void)unzipDownloadedPackage:(NSString *)zipFilePath
195
+ hash:(NSString *)hash
196
+ type:(PushyType)type
197
+ originHash:(NSString *)originHash
198
+ callback:(void (^)(NSError *error))callback;
199
+ - (void)finishDownloadedPackage:(NSString *)hash
200
+ type:(PushyType)type
201
+ originHash:(NSString *)originHash
202
+ callback:(void (^)(NSError *error))callback;
203
+ - (void)applyPatchForHash:(NSString *)hash
204
+ type:(PushyType)type
205
+ fromBundle:(NSString *)bundleOrigin
206
+ source:(NSString *)sourceOrigin
207
+ callback:(void (^)(NSError *error))callback;
208
+ - (BOOL)switchVersion:(NSString *)hash error:(NSError **)error;
209
+ - (BOOL)ensureDirectoryExistsAtPath:(NSString *)path;
210
+ - (void)unzipFileAtPath:(NSString *)path
211
+ toDestination:(NSString *)destination
212
+ completionHandler:(void (^)(NSError *error))completionHandler;
168
213
  @end
169
214
 
170
215
  @implementation RCTPushy {
171
- RCTPushyManager *_fileManager;
216
+ dispatch_queue_t _fileQueue;
172
217
  bool hasListeners;
173
218
  }
174
219
 
175
- @synthesize methodQueue = _methodQueue;
176
-
177
220
  RCT_EXPORT_MODULE(RCTPushy);
178
221
 
179
222
  + (NSURL *)bundleURL
180
223
  {
181
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
224
+ NSUserDefaults *defaults = PushyDefaults();
182
225
 
183
- // Check for version changes first
184
226
  NSString *curPackageVersion = [RCTPushy packageVersion];
185
227
  NSString *curBuildTime = [RCTPushy buildTime];
186
- NSString *storedPackageVersion = [defaults stringForKey:paramPackageVersion];
187
- NSString *storedBuildTime = [defaults stringForKey:paramBuildTime];
188
228
 
189
229
  pushy::state::State state = PushyStateFromDefaults(defaults);
190
230
  pushy::state::BinaryVersionSyncResult sync = pushy::state::SyncBinaryVersion(
@@ -235,20 +275,20 @@ RCT_EXPORT_MODULE(RCTPushy);
235
275
  }
236
276
 
237
277
  + (NSString *) rollback {
238
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
278
+ NSUserDefaults *defaults = PushyDefaults();
239
279
  pushy::state::State state = pushy::state::Rollback(PushyStateFromDefaults(defaults));
240
280
  PushyApplyStateToDefaults(defaults, state);
241
281
  return PushyFromStdString(state.current_version);
242
282
  }
243
283
 
244
- + (BOOL)requiresMainQueueSetup {
245
- // only set to YES if your module initialization relies on calling UIKit!
246
- return NO;
284
+ + (BOOL)requiresMainQueueSetup
285
+ {
286
+ return NO;
247
287
  }
248
288
 
249
289
  - (NSDictionary *)constantsToExport
250
290
  {
251
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
291
+ NSUserDefaults *defaults = PushyDefaults();
252
292
 
253
293
  NSMutableDictionary *ret = [NSMutableDictionary new];
254
294
  ret[@"downloadRootDir"] = [RCTPushy downloadDir];
@@ -261,23 +301,20 @@ RCT_EXPORT_MODULE(RCTPushy);
261
301
  NSString *currentVersion = [pushyInfo objectForKey:paramCurrentVersion];
262
302
  ret[@"currentVersion"] = currentVersion;
263
303
  if (currentVersion != nil) {
264
- ret[@"currentVersionInfo"] = [defaults objectForKey:[keyHashInfo stringByAppendingString:currentVersion]];
304
+ ret[@"currentVersionInfo"] = [defaults objectForKey:PushyHashInfoKey(currentVersion)];
265
305
  }
266
306
 
267
- // clear isFirstTimemarked
268
307
  if (ret[@"isFirstTime"]) {
269
- [defaults setObject:nil forKey:keyFirstLoadMarked];
308
+ [defaults removeObjectForKey:keyFirstLoadMarked];
270
309
  }
271
310
 
272
- // clear rolledbackmark
273
311
  if (ret[@"rolledBackVersion"] != nil) {
274
- [defaults setObject:nil forKey:keyRolledBackMarked];
312
+ [defaults removeObjectForKey:keyRolledBackMarked];
275
313
  [self clearInvalidFiles];
276
314
  }
277
315
 
278
- // clear packageupdatemarked
279
316
  if ([[defaults objectForKey:KeyPackageUpdatedMarked] boolValue]) {
280
- [defaults setObject:nil forKey:KeyPackageUpdatedMarked];
317
+ [defaults removeObjectForKey:KeyPackageUpdatedMarked];
281
318
  [self clearInvalidFiles];
282
319
  }
283
320
 
@@ -289,7 +326,7 @@ RCT_EXPORT_MODULE(RCTPushy);
289
326
  {
290
327
  self = [super init];
291
328
  if (self) {
292
- _fileManager = [RCTPushyManager new];
329
+ _fileQueue = dispatch_queue_create("cn.reactnative.pushy.file", DISPATCH_QUEUE_SERIAL);
293
330
  }
294
331
  return self;
295
332
  }
@@ -297,31 +334,35 @@ RCT_EXPORT_MODULE(RCTPushy);
297
334
  RCT_EXPORT_METHOD(setUuid:(NSString *)uuid resolver:(RCTPromiseResolveBlock)resolve
298
335
  rejecter:(RCTPromiseRejectBlock)reject)
299
336
  {
300
- @try {
301
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
302
- [defaults setObject:uuid forKey:keyUuid];
303
-
304
- resolve(@true);
305
- }
306
- @catch (NSException *exception) {
307
- reject(@"json格式校验报错", nil, nil);
337
+ if (PushyStringIsBlank(uuid)) {
338
+ PushyRejectError(reject, PushyErrorWithMessage(ERROR_OPTIONS));
339
+ return;
308
340
  }
341
+
342
+ NSUserDefaults *defaults = PushyDefaults();
343
+ [defaults setObject:uuid forKey:keyUuid];
344
+ resolve(@true);
309
345
  }
310
346
 
311
347
  RCT_EXPORT_METHOD(setLocalHashInfo:(NSString *)hash
312
348
  value:(NSString *)value resolver:(RCTPromiseResolveBlock)resolve
313
349
  rejecter:(RCTPromiseRejectBlock)reject)
314
350
  {
351
+ if (PushyStringIsBlank(hash) || PushyStringIsBlank(value)) {
352
+ PushyRejectMessage(reject, ERROR_OPTIONS);
353
+ return;
354
+ }
355
+
315
356
  NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
316
357
  NSError *error = nil;
317
358
  id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
318
359
  if (object && [object isKindOfClass:[NSDictionary class]]) {
319
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
320
- [defaults setObject:value forKey:[keyHashInfo stringByAppendingString:hash]];
360
+ NSUserDefaults *defaults = PushyDefaults();
361
+ [defaults setObject:value forKey:PushyHashInfoKey(hash)];
321
362
 
322
363
  resolve(@true);
323
364
  } else {
324
- reject(@"json格式校验报错", nil, nil);
365
+ PushyRejectError(reject, error ?: PushyErrorWithMessage(@"json格式校验报错"));
325
366
  }
326
367
  }
327
368
 
@@ -331,121 +372,63 @@ RCT_EXPORT_METHOD(getLocalHashInfo:(NSString *)hash
331
372
  rejecter:(RCTPromiseRejectBlock)reject)
332
373
  {
333
374
 
334
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
335
- resolve([defaults stringForKey:[keyHashInfo stringByAppendingString:hash]]);
375
+ NSUserDefaults *defaults = PushyDefaults();
376
+ resolve([defaults stringForKey:PushyHashInfoKey(hash)]);
336
377
  }
337
378
 
338
379
  RCT_EXPORT_METHOD(downloadFullUpdate:(NSDictionary *)options
339
380
  resolver:(RCTPromiseResolveBlock)resolve
340
381
  rejecter:(RCTPromiseRejectBlock)reject)
341
382
  {
342
- [self doPushy:PushyTypeFullDownload options:options callback:^(NSError *error) {
343
- if (error) {
344
- reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
345
- }
346
- else {
347
- resolve(nil);
348
- }
349
- }];
383
+ [self downloadUpdate:PushyTypeFullDownload options:options resolver:resolve rejecter:reject];
350
384
  }
351
385
 
352
386
  RCT_EXPORT_METHOD(downloadPatchFromPackage:(NSDictionary *)options
353
387
  resolver:(RCTPromiseResolveBlock)resolve
354
388
  rejecter:(RCTPromiseRejectBlock)reject)
355
389
  {
356
- [self doPushy:PushyTypePatchFromPackage options:options callback:^(NSError *error) {
357
- if (error) {
358
- reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
359
- }
360
- else {
361
- resolve(nil);
362
- }
363
- }];
390
+ [self downloadUpdate:PushyTypePatchFromPackage options:options resolver:resolve rejecter:reject];
364
391
  }
365
392
 
366
393
  RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
367
394
  resolver:(RCTPromiseResolveBlock)resolve
368
395
  rejecter:(RCTPromiseRejectBlock)reject)
369
396
  {
370
- [self doPushy:PushyTypePatchFromPpk options:options callback:^(NSError *error) {
371
- if (error) {
372
- reject([NSString stringWithFormat: @"%lu", (long)error.code], error.localizedDescription, error);
373
- }
374
- else {
375
- resolve(nil);
376
- }
377
- }];
397
+ [self downloadUpdate:PushyTypePatchFromPpk options:options resolver:resolve rejecter:reject];
378
398
  }
379
399
 
380
400
  RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options
381
401
  resolver:(RCTPromiseResolveBlock)resolve
382
402
  rejecter:(RCTPromiseRejectBlock)reject)
383
403
  {
384
- NSString *hash = options[@"hash"];
385
-
386
- if (hash.length) {
387
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
388
- pushy::state::State next = pushy::state::SwitchVersion(
389
- PushyStateFromDefaults(defaults),
390
- PushyToStdString(hash)
391
- );
392
- PushyApplyStateToDefaults(defaults, next);
393
- resolve(@true);
394
- } else {
395
- reject(@"执行报错", nil, nil);
404
+ NSError *error = nil;
405
+ if (![self switchVersion:PushyOptionString(options, @"hash") error:&error]) {
406
+ PushyRejectError(reject, error);
407
+ return;
396
408
  }
409
+
410
+ resolve(@true);
397
411
  }
398
412
 
399
413
  RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
400
414
  resolver:(RCTPromiseResolveBlock)resolve
401
415
  rejecter:(RCTPromiseRejectBlock)reject)
402
416
  {
403
- @try {
404
- NSString *hash = options[@"hash"];
405
- if (hash.length) {
406
- // 只在 setNeedUpdate 成功后 resolve
407
- [self setNeedUpdate:options resolver:^(id result) {
408
- dispatch_async(dispatch_get_main_queue(), ^{
409
- #if __has_include("RCTReloadCommand.h")
410
- // reload 0.62+
411
- RCTReloadCommandSetBundleURL([[self class] bundleURL]);
412
- RCTTriggerReloadCommandListeners(@"pushy reloadUpdate");
413
- #else
414
- [self.bridge reload];
415
- #endif
416
- });
417
- resolve(@true);
418
- } rejecter:^(NSString *code, NSString *message, NSError *error) {
419
- reject(code, message, error);
420
- }];
421
- } else {
422
- reject(@"执行报错", nil, nil);
423
- }
424
- }
425
- @catch (NSException *exception) {
426
- reject(@"执行报错", nil, nil);
417
+ NSError *error = nil;
418
+ if (![self switchVersion:PushyOptionString(options, @"hash") error:&error]) {
419
+ PushyRejectError(reject, error);
420
+ return;
427
421
  }
422
+
423
+ [self reloadBridgeWithReason:@"pushy reloadUpdate"];
424
+ resolve(@true);
428
425
  }
429
426
 
430
427
  RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
431
428
  rejecter:(RCTPromiseRejectBlock)reject)
432
429
  {
433
- @try {
434
- dispatch_async(dispatch_get_main_queue(), ^{
435
- #if __has_include("RCTReloadCommand.h")
436
- // reload 0.62+
437
- RCTReloadCommandSetBundleURL([[self class] bundleURL]);
438
- RCTTriggerReloadCommandListeners(@"pushy restartApp");
439
- #else
440
- [self.bridge reload];
441
- #endif
442
- });
443
-
444
- resolve(@true);
445
- }
446
- @catch (NSException *exception) {
447
- reject(@"执行报错", exception.reason, nil);
448
- }
430
+ [self reloadBridgeWithReason:@"pushy restartApp"];
431
+ resolve(@true);
449
432
  }
450
433
 
451
434
  RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
@@ -454,23 +437,17 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
454
437
  #if DEBUG
455
438
  resolve(@true);
456
439
  #else
457
-
458
- @try {
459
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
460
- pushy::state::MarkSuccessResult result =
461
- pushy::state::MarkSuccess(PushyStateFromDefaults(defaults));
462
- if (!result.stale_version_to_delete.empty()) {
463
- [defaults removeObjectForKey:[keyHashInfo stringByAppendingString:PushyFromStdString(result.stale_version_to_delete)]];
464
- }
465
- PushyApplyStateToDefaults(defaults, result.state);
466
-
467
- // clear other package dir
468
- [self clearInvalidFiles];
469
- resolve(@true);
470
- }
471
- @catch (NSException *exception) {
472
- reject(@"执行报错", nil, nil);
440
+
441
+ NSUserDefaults *defaults = PushyDefaults();
442
+ pushy::state::MarkSuccessResult result =
443
+ pushy::state::MarkSuccess(PushyStateFromDefaults(defaults));
444
+ if (!result.stale_version_to_delete.empty()) {
445
+ [defaults removeObjectForKey:PushyHashInfoKey(PushyFromStdString(result.stale_version_to_delete))];
473
446
  }
447
+ PushyApplyStateToDefaults(defaults, result.state);
448
+
449
+ [self clearInvalidFiles];
450
+ resolve(@true);
474
451
  #endif
475
452
  }
476
453
 
@@ -480,61 +457,67 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
480
457
  - (NSArray<NSString *> *)supportedEvents
481
458
  {
482
459
  return @[
483
- EVENT_PROGRESS_DOWNLOAD,
484
- // EVENT_PROGRESS_UNZIP
485
- ];
460
+ EVENT_PROGRESS_DOWNLOAD,
461
+ ];
486
462
  }
487
463
 
488
- // Will be called when this module's first listener is added.
489
464
  -(void)startObserving {
490
465
  hasListeners = YES;
491
- // Set up any upstream listeners or background tasks as necessary
492
466
  }
493
467
 
494
- // Will be called when this module's last listener is removed, or on dealloc.
495
468
  -(void)stopObserving {
496
469
  hasListeners = NO;
497
- // Remove upstream listeners, stop unnecessary background tasks
498
470
  }
499
471
 
500
- - (BOOL) isBlankString:(NSString *)string {
501
- if (string == nil || string == NULL) {
502
- return YES;
503
- }
504
- if ([string isKindOfClass:[NSNull class]]) {
505
- return YES;
506
- }
507
- if ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0) {
508
- return YES;
509
- }
510
- return NO;
472
+ - (void)downloadUpdate:(PushyType)type
473
+ options:(NSDictionary *)options
474
+ resolver:(RCTPromiseResolveBlock)resolve
475
+ rejecter:(RCTPromiseRejectBlock)reject
476
+ {
477
+ [self performUpdate:type options:options callback:^(NSError *error) {
478
+ if (error != nil) {
479
+ PushyRejectError(reject, error);
480
+ return;
481
+ }
482
+ resolve(nil);
483
+ }];
511
484
  }
512
485
 
486
+ - (void)reloadBridgeWithReason:(NSString *)reason
487
+ {
488
+ dispatch_async(dispatch_get_main_queue(), ^{
489
+ #if __has_include("RCTReloadCommand.h")
490
+ RCTReloadCommandSetBundleURL([[self class] bundleURL]);
491
+ RCTTriggerReloadCommandListeners(reason);
492
+ #else
493
+ [self.bridge reload];
494
+ #endif
495
+ });
496
+ }
513
497
 
514
- - (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
498
+ - (void)performUpdate:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
515
499
  {
516
- NSString *updateUrl = [RCTConvert NSString:options[@"updateUrl"]];
517
- NSString *hash = [RCTConvert NSString:options[@"hash"]];
500
+ NSString *updateUrl = PushyOptionString(options, @"updateUrl");
501
+ NSString *hash = PushyOptionString(options, @"hash");
518
502
 
519
- if (updateUrl.length <= 0 || hash.length <= 0) {
520
- callback([self errorWithMessage:ERROR_OPTIONS]);
503
+ if (PushyStringIsBlank(updateUrl) || PushyStringIsBlank(hash)) {
504
+ callback(PushyErrorWithMessage(ERROR_OPTIONS));
521
505
  return;
522
506
  }
523
- NSString *originHash = [RCTConvert NSString:options[@"originHash"]];
524
- if (type == PushyTypePatchFromPpk && [self isBlankString:originHash]) {
525
- callback([self errorWithMessage:ERROR_OPTIONS]);
507
+ NSString *originHash = PushyOptionString(options, @"originHash");
508
+ if (type == PushyTypePatchFromPpk && PushyStringIsBlank(originHash)) {
509
+ callback(PushyErrorWithMessage(ERROR_OPTIONS));
526
510
  return;
527
511
  }
528
512
 
529
513
  NSString *dir = [RCTPushy downloadDir];
530
- BOOL success = [_fileManager createDir:dir];
514
+ BOOL success = [self ensureDirectoryExistsAtPath:dir];
531
515
  if (!success) {
532
- callback([self errorWithMessage:ERROR_FILE_OPERATION]);
516
+ callback(PushyErrorWithMessage(ERROR_FILE_OPERATION));
533
517
  return;
534
518
  }
535
519
 
536
520
  NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hash, [self zipExtension:type]]];
537
- // NSString *unzipDir = [dir stringByAppendingPathComponent:hash];
538
521
 
539
522
  RCTLogInfo(@"RCTPushy -- download file %@", updateUrl);
540
523
  [RCTPushyDownloader download:updateUrl savePath:zipFilePath progressHandler:^(long long receivedBytes, long long totalBytes) {
@@ -546,61 +529,72 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
546
529
  }];
547
530
  }
548
531
  } completionHandler:^(NSString *path, NSError *error) {
549
- if (error) {
532
+ if (error != nil) {
550
533
  callback(error);
534
+ return;
551
535
  }
552
- else {
553
- RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath);
554
- NSString *unzipFilePath = [dir stringByAppendingPathComponent:hash];
555
- [self->_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) {
556
- // if (self->hasListeners) {
557
- // [self sendEventWithName:EVENT_PROGRESS_UNZIP
558
- // body:@{
559
- // PARAM_PROGRESS_HASH:hash,
560
- // PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber],
561
- // PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total]
562
- // }];
563
- // }
564
-
565
- } completionHandler:^(NSString *path, BOOL succeeded, NSError *error) {
566
- dispatch_async(self->_methodQueue, ^{
567
- if (error) {
568
- callback(error);
569
- }
570
- else {
571
- switch (type) {
572
- case PushyTypePatchFromPackage:
573
- {
574
- NSString *sourceOrigin = [[NSBundle mainBundle] resourcePath];
575
- NSString *bundleOrigin = [[RCTPushy binaryBundleURL] path];
576
- [self patch:hash type:type fromBundle:bundleOrigin source:sourceOrigin callback:callback];
577
- }
578
- break;
579
- case PushyTypePatchFromPpk:
580
- {
581
- NSString *lastVersionDir = [dir stringByAppendingPathComponent:originHash];
582
-
583
- NSString *sourceOrigin = lastVersionDir;
584
- NSString *bundleOrigin = [lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
585
- [self patch:hash type:type fromBundle:bundleOrigin source:sourceOrigin callback:callback];
586
- }
587
- break;
588
- default:
589
- callback(nil);
590
- break;
591
- }
592
- }
593
- });
594
- }];
595
- }
536
+ [self unzipDownloadedPackage:zipFilePath
537
+ hash:hash
538
+ type:type
539
+ originHash:originHash
540
+ callback:callback];
596
541
  }];
597
542
  }
598
543
 
599
- - (void)_dopatch:(NSString *)hash
600
- type:(PushyType)type
601
- fromBundle:(NSString *)bundleOrigin
602
- source:(NSString *)sourceOrigin
603
- callback:(void (^)(NSError *error))callback
544
+ - (void)unzipDownloadedPackage:(NSString *)zipFilePath
545
+ hash:(NSString *)hash
546
+ type:(PushyType)type
547
+ originHash:(NSString *)originHash
548
+ callback:(void (^)(NSError *error))callback
549
+ {
550
+ RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath);
551
+ NSString *unzipFilePath = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
552
+ [self unzipFileAtPath:zipFilePath
553
+ toDestination:unzipFilePath
554
+ completionHandler:^(NSError *error) {
555
+ dispatch_async(self->_fileQueue, ^{
556
+ if (error != nil) {
557
+ callback(error);
558
+ return;
559
+ }
560
+ [self finishDownloadedPackage:hash type:type originHash:originHash callback:callback];
561
+ });
562
+ }];
563
+ }
564
+
565
+ - (void)finishDownloadedPackage:(NSString *)hash
566
+ type:(PushyType)type
567
+ originHash:(NSString *)originHash
568
+ callback:(void (^)(NSError *error))callback
569
+ {
570
+ switch (type) {
571
+ case PushyTypePatchFromPackage:
572
+ [self applyPatchForHash:hash
573
+ type:type
574
+ fromBundle:[[RCTPushy binaryBundleURL] path]
575
+ source:[[NSBundle mainBundle] resourcePath]
576
+ callback:callback];
577
+ return;
578
+ case PushyTypePatchFromPpk: {
579
+ NSString *lastVersionDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:originHash];
580
+ [self applyPatchForHash:hash
581
+ type:type
582
+ fromBundle:[lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME]
583
+ source:lastVersionDir
584
+ callback:callback];
585
+ return;
586
+ }
587
+ case PushyTypeFullDownload:
588
+ callback(nil);
589
+ return;
590
+ }
591
+ }
592
+
593
+ - (void)applyPatchForHash:(NSString *)hash
594
+ type:(PushyType)type
595
+ fromBundle:(NSString *)bundleOrigin
596
+ source:(NSString *)sourceOrigin
597
+ callback:(void (^)(NSError *error))callback
604
598
  {
605
599
  NSString *unzipDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
606
600
  NSString *sourcePatch = [unzipDir stringByAppendingPathComponent:SOURCE_PATCH_NAME];
@@ -608,12 +602,22 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
608
602
 
609
603
  NSString *destination = [unzipDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
610
604
  NSData *data = [NSData dataWithContentsOfFile:sourcePatch];
605
+ if (data == nil) {
606
+ callback(PushyErrorWithMessage(@"missing patch manifest"));
607
+ return;
608
+ }
609
+
611
610
  NSError *error = nil;
612
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
613
- if (error) {
611
+ id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
612
+ if (error != nil) {
614
613
  callback(error);
615
614
  return;
616
615
  }
616
+ if (![jsonObject isKindOfClass:[NSDictionary class]]) {
617
+ callback(PushyErrorWithMessage(@"invalid patch manifest"));
618
+ return;
619
+ }
620
+ NSDictionary *json = (NSDictionary *)jsonObject;
617
621
 
618
622
  std::vector<std::string> entryNames;
619
623
  if ([[NSFileManager defaultManager] fileExistsAtPath:sourcePatch isDirectory:NULL]) {
@@ -661,30 +665,93 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
661
665
  callback(nil);
662
666
  }
663
667
 
664
- - (void)patch:(NSString *)hash
665
- type:(PushyType)type
666
- fromBundle:(NSString *)bundleOrigin
667
- source:(NSString *)sourceOrigin
668
- callback:(void (^)(NSError *error))callback
668
+ - (BOOL)switchVersion:(NSString *)hash error:(NSError **)error
669
669
  {
670
- [self _dopatch:hash type:type fromBundle:bundleOrigin source:sourceOrigin callback:callback];
670
+ if (PushyStringIsBlank(hash)) {
671
+ if (error != NULL) {
672
+ *error = PushyErrorWithMessage(ERROR_OPTIONS);
673
+ }
674
+ return NO;
675
+ }
676
+
677
+ NSUserDefaults *defaults = PushyDefaults();
678
+ pushy::state::State next = pushy::state::SwitchVersion(
679
+ PushyStateFromDefaults(defaults),
680
+ PushyToStdString(hash)
681
+ );
682
+ PushyApplyStateToDefaults(defaults, next);
683
+ return YES;
684
+ }
685
+
686
+ - (BOOL)ensureDirectoryExistsAtPath:(NSString *)path
687
+ {
688
+ __block BOOL success = NO;
689
+
690
+ dispatch_sync(_fileQueue, ^{
691
+ NSFileManager *fileManager = [NSFileManager defaultManager];
692
+ BOOL isDirectory = NO;
693
+ if ([fileManager fileExistsAtPath:path isDirectory:&isDirectory]) {
694
+ success = isDirectory;
695
+ return;
696
+ }
697
+
698
+ NSError *error = nil;
699
+ success = [fileManager createDirectoryAtPath:path
700
+ withIntermediateDirectories:YES
701
+ attributes:nil
702
+ error:&error];
703
+ if (!success && error != nil) {
704
+ RCTLogWarn(@"Pushy create directory error: %@", error.localizedDescription);
705
+ }
706
+ });
707
+
708
+ return success;
709
+ }
710
+
711
+ - (void)unzipFileAtPath:(NSString *)path
712
+ toDestination:(NSString *)destination
713
+ completionHandler:(void (^)(NSError *error))completionHandler
714
+ {
715
+ dispatch_async(_fileQueue, ^{
716
+ NSFileManager *fileManager = [NSFileManager defaultManager];
717
+ if ([fileManager fileExistsAtPath:destination]) {
718
+ [fileManager removeItemAtPath:destination error:nil];
719
+ }
720
+
721
+ [SSZipArchive unzipFileAtPath:path
722
+ toDestination:destination
723
+ progressHandler:nil
724
+ completionHandler:^(NSString *archivePath, BOOL succeeded, NSError *error) {
725
+ [fileManager removeItemAtPath:archivePath error:nil];
726
+ if (completionHandler == nil) {
727
+ return;
728
+ }
729
+
730
+ NSError *unzipError = error;
731
+ if (!succeeded && unzipError == nil) {
732
+ unzipError = PushyErrorWithMessage(@"unzip failed");
733
+ }
734
+ completionHandler(unzipError);
735
+ }];
736
+ });
671
737
  }
672
738
 
673
739
  - (void)clearInvalidFiles
674
740
  {
675
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
676
- pushy::state::State state = PushyStateFromDefaults(defaults);
677
-
678
- NSString *downloadDir = [RCTPushy downloadDir];
679
- pushy::patch::Status status = pushy::patch::CleanupOldEntries(
680
- PushyToStdString(downloadDir),
681
- state.current_version,
682
- state.last_version,
683
- 7
684
- );
685
- if (!status.ok) {
686
- NSLog(@"Pushy cleanup error: %s", status.message.c_str());
687
- }
741
+ dispatch_async(_fileQueue, ^{
742
+ NSUserDefaults *defaults = PushyDefaults();
743
+ pushy::state::State state = PushyStateFromDefaults(defaults);
744
+ NSString *downloadDir = [RCTPushy downloadDir];
745
+ pushy::patch::Status status = pushy::patch::CleanupOldEntries(
746
+ PushyToStdString(downloadDir),
747
+ state.current_version,
748
+ state.last_version,
749
+ 7
750
+ );
751
+ if (!status.ok) {
752
+ RCTLogWarn(@"Pushy cleanup error: %s", status.message.c_str());
753
+ }
754
+ });
688
755
  }
689
756
 
690
757
  - (NSString *)zipExtension:(PushyType)type
@@ -697,29 +764,19 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
697
764
  case PushyTypePatchFromPpk:
698
765
  return @".ppk.patch";
699
766
  default:
700
- break;
767
+ return @"";
701
768
  }
702
769
  }
703
770
 
704
- - (NSError *)errorWithMessage:(NSString *)errorMessage
705
- {
706
- return [NSError errorWithDomain:@"cn.reactnative.pushy"
707
- code:-1
708
- userInfo:@{ NSLocalizedDescriptionKey: errorMessage}];
709
- }
710
-
711
771
  + (NSString *)downloadDir
712
772
  {
713
773
  NSString *directory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) firstObject];
714
- NSString *downloadDir = [directory stringByAppendingPathComponent:@"rctpushy"];
715
-
716
- return downloadDir;
774
+ return [directory stringByAppendingPathComponent:@"rctpushy"];
717
775
  }
718
776
 
719
777
  + (NSURL *)binaryBundleURL
720
778
  {
721
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
722
- return url;
779
+ return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
723
780
  }
724
781
 
725
782
  + (NSString *)packageVersion
@@ -750,7 +807,6 @@ RCT_EXPORT_METHOD(markSuccess:(RCTPromiseResolveBlock)resolve
750
807
  #endif
751
808
  }
752
809
 
753
- // Thanks to this guard, we won't compile this code when we build for the old architecture.
754
810
  #ifdef RCT_NEW_ARCH_ENABLED
755
811
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
756
812
  (const facebook::react::ObjCTurboModule::InitParams &)params