react-native-update 8.1.0 → 9.0.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 (43) hide show
  1. package/.github/workflows/e2e_android.yml +49 -0
  2. package/.github/workflows/e2e_ios.yml +182 -0
  3. package/.github/workflows/scripts/adb_all_emulators.sh +10 -0
  4. package/.github/workflows/scripts/database.rules +13 -0
  5. package/.github/workflows/scripts/firebase.json +39 -0
  6. package/.github/workflows/scripts/firestore.indexes.json +72 -0
  7. package/.github/workflows/scripts/firestore.rules +17 -0
  8. package/.github/workflows/scripts/functions/package.json +24 -0
  9. package/.github/workflows/scripts/functions/src/exports.ts +13 -0
  10. package/.github/workflows/scripts/functions/src/index.ts +12 -0
  11. package/.github/workflows/scripts/functions/src/sample-data.ts +80 -0
  12. package/.github/workflows/scripts/functions/src/testFunctionCustomRegion.ts +14 -0
  13. package/.github/workflows/scripts/functions/src/testFunctionDefaultRegion.ts +70 -0
  14. package/.github/workflows/scripts/functions/tsconfig.json +16 -0
  15. package/.github/workflows/scripts/start-firebase-emulator.bat +6 -0
  16. package/.github/workflows/scripts/start-firebase-emulator.sh +44 -0
  17. package/.github/workflows/scripts/storage.rules +21 -0
  18. package/README.md +8 -6
  19. package/android/build.gradle +22 -0
  20. package/android/jni/hpatch.c +4 -4
  21. package/android/jni/hpatch.h +3 -3
  22. package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +0 -2
  23. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +265 -0
  24. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +31 -20
  25. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +147 -0
  26. package/android/src/{main/java → oldarch}/cn/reactnative/modules/update/UpdateModule.java +6 -2
  27. package/e2e/jest.config.js +12 -0
  28. package/e2e/starter.test.js +23 -0
  29. package/ios/RCTPushy/{RCTPushy.m → RCTPushy.mm} +116 -44
  30. package/ios/pushy_build_time.txt +1 -1
  31. package/lib/NativeUpdate.js +51 -0
  32. package/lib/{endpoint.js → endpoint.ts} +22 -12
  33. package/lib/index.web.js +1 -0
  34. package/lib/{main.js → main.ts} +122 -71
  35. package/lib/{simpleUpdate.js → simpleUpdate.tsx} +13 -4
  36. package/lib/type.ts +70 -0
  37. package/package.json +37 -3
  38. package/react-native-update.podspec +20 -2
  39. package/lib/index.d.ts +0 -94
  40. /package/ios/RCTPushy/HDiffPatch/{HDiffPatch.m → HDiffPatch.mm} +0 -0
  41. /package/ios/RCTPushy/{RCTPushyDownloader.m → RCTPushyDownloader.mm} +0 -0
  42. /package/ios/RCTPushy/{RCTPushyManager.m → RCTPushyManager.mm} +0 -0
  43. /package/lib/{index.js → index.ts} +0 -0
@@ -0,0 +1,23 @@
1
+ describe('Example', () => {
2
+ beforeAll(async () => {
3
+ await device.launchApp();
4
+ });
5
+
6
+ beforeEach(async () => {
7
+ await device.reloadReactNative();
8
+ });
9
+
10
+ it('should have welcome screen', async () => {
11
+ await expect(element(by.id('welcome'))).toBeVisible();
12
+ });
13
+
14
+ it('should show hello screen after tap', async () => {
15
+ await element(by.id('hello_button')).tap();
16
+ await expect(element(by.text('Hello!!!'))).toBeVisible();
17
+ });
18
+
19
+ it('should show world screen after tap', async () => {
20
+ await element(by.id('world_button')).tap();
21
+ await expect(element(by.text('World!!!'))).toBeVisible();
22
+ });
23
+ });
@@ -1,7 +1,10 @@
1
1
  #import "RCTPushy.h"
2
2
  #import "RCTPushyDownloader.h"
3
3
  #import "RCTPushyManager.h"
4
-
4
+ // Thanks to this guard, we won't import this header when we build for the old architecture.
5
+ #ifdef RCT_NEW_ARCH_ENABLED
6
+ #import "RCTPushySpec.h"
7
+ #endif
5
8
 
6
9
  #import <React/RCTConvert.h>
7
10
  #import <React/RCTLog.h>
@@ -189,29 +192,53 @@ RCT_EXPORT_MODULE(RCTPushy);
189
192
  return self;
190
193
  }
191
194
 
192
- RCT_EXPORT_METHOD(setBlockUpdate:(NSDictionary *)options)
195
+ RCT_EXPORT_METHOD(setBlockUpdate:(NSDictionary *)options
196
+ resolver:(RCTPromiseResolveBlock)resolve
197
+ rejecter:(RCTPromiseRejectBlock)reject)
193
198
  {
194
199
  // NSMutableDictionary *blockUpdateInfo = [NSMutableDictionary new];
195
200
  // blockUpdateInfo[@"reason"] = options[@"reason"];
196
201
  // blockUpdateInfo[@"until"] = options[@"until"];
197
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
198
- [defaults setObject:options forKey:keyBlockUpdate];
199
- [defaults synchronize];
202
+ @try {
203
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
204
+ [defaults setObject:options forKey:keyBlockUpdate];
205
+ [defaults synchronize];
206
+ resolve(@true);
207
+ }
208
+ @catch (NSException *exception) {
209
+ reject(@"执行报错", nil, nil);
210
+ }
200
211
  }
201
212
 
202
- RCT_EXPORT_METHOD(setUuid:(NSString *)uuid)
213
+ RCT_EXPORT_METHOD(setUuid:(NSString *)uuid resolver:(RCTPromiseResolveBlock)resolve
214
+ rejecter:(RCTPromiseRejectBlock)reject)
203
215
  {
204
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
205
- [defaults setObject:uuid forKey:keyUuid];
206
- [defaults synchronize];
216
+ @try {
217
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
218
+ [defaults setObject:uuid forKey:keyUuid];
219
+ [defaults synchronize];
220
+ resolve(@true);
221
+ }
222
+ @catch (NSException *exception) {
223
+ reject(@"json格式校验报错", nil, nil);
224
+ }
207
225
  }
208
226
 
209
227
  RCT_EXPORT_METHOD(setLocalHashInfo:(NSString *)hash
210
- value:(NSString *)value)
228
+ value:(NSString *)value resolver:(RCTPromiseResolveBlock)resolve
229
+ rejecter:(RCTPromiseRejectBlock)reject)
211
230
  {
212
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
213
- [defaults setObject:value forKey:[keyHashInfo stringByAppendingString:hash]];
214
- [defaults synchronize];
231
+ NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];
232
+ NSError *error = nil;
233
+ id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
234
+ if (object && [object isKindOfClass:[NSDictionary class]]) {
235
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
236
+ [defaults setObject:value forKey:[keyHashInfo stringByAppendingString:hash]];
237
+ [defaults synchronize];
238
+ resolve(@true);
239
+ } else {
240
+ reject(@"json格式校验报错", nil, nil);
241
+ }
215
242
  }
216
243
 
217
244
 
@@ -266,7 +293,9 @@ RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
266
293
  }];
267
294
  }
268
295
 
269
- RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
296
+ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options
297
+ resolver:(RCTPromiseResolveBlock)resolve
298
+ rejecter:(RCTPromiseRejectBlock)reject)
270
299
  {
271
300
  NSString *hash = options[@"hash"];
272
301
 
@@ -287,45 +316,66 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
287
316
  [defaults setObject:newInfo forKey:keyPushyInfo];
288
317
 
289
318
  [defaults synchronize];
319
+ resolve(@true);
320
+ }else{
321
+ reject(@"执行报错", nil, nil);
290
322
  }
291
323
  }
292
324
 
293
- RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options)
325
+ RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options
326
+ resolver:(RCTPromiseResolveBlock)resolve
327
+ rejecter:(RCTPromiseRejectBlock)reject)
294
328
  {
295
- NSString *hash = options[@"hash"];
296
-
297
- if (hash.length) {
298
- [self setNeedUpdate:options];
299
-
300
- // reload 0.62+
301
- // RCTReloadCommandSetBundleURL([[self class] bundleURL]);
302
- // RCTTriggerReloadCommandListeners(@"pushy reload");
303
-
304
- dispatch_async(dispatch_get_main_queue(), ^{
305
- [self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
306
- [self.bridge reload];
307
- });
329
+ @try {
330
+ NSString *hash = options[@"hash"];
331
+ if (hash.length) {
332
+ [self setNeedUpdate:options resolver:resolve rejecter:reject];
333
+
334
+ // reload 0.62+
335
+ // RCTReloadCommandSetBundleURL([[self class] bundleURL]);
336
+ // RCTTriggerReloadCommandListeners(@"pushy reload");
337
+
338
+ dispatch_async(dispatch_get_main_queue(), ^{
339
+ [self.bridge setValue:[[self class] bundleURL] forKey:@"bundleURL"];
340
+ [self.bridge reload];
341
+ });
342
+ resolve(@true);
343
+ }else{
344
+ reject(@"执行报错", nil, nil);
345
+ }
346
+ }
347
+ @catch (NSException *exception) {
348
+ reject(@"执行报错", nil, nil);
308
349
  }
309
350
  }
310
351
 
311
- RCT_EXPORT_METHOD(markSuccess)
352
+ RCT_EXPORT_METHOD(markSuccess:
353
+ resolver:(RCTPromiseResolveBlock)resolve
354
+ rejecter:(RCTPromiseRejectBlock)reject)
312
355
  {
313
- // up package info
314
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
315
- NSMutableDictionary *pushyInfo = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:keyPushyInfo]];
316
- [pushyInfo setObject:@(NO) forKey:paramIsFirstTime];
317
- [pushyInfo setObject:@(YES) forKey:paramIsFirstLoadOk];
318
356
 
319
- NSString *lastVersion = pushyInfo[paramLastVersion];
320
- NSString *curVersion = pushyInfo[paramCurrentVersion];
321
- if (lastVersion != nil && ![lastVersion isEqualToString:curVersion]) {
322
- [pushyInfo removeObjectForKey:[keyHashInfo stringByAppendingString:lastVersion]];
357
+ @try {
358
+ // up package info
359
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
360
+ NSMutableDictionary *pushyInfo = [[NSMutableDictionary alloc] initWithDictionary:[defaults objectForKey:keyPushyInfo]];
361
+ [pushyInfo setObject:@(NO) forKey:paramIsFirstTime];
362
+ [pushyInfo setObject:@(YES) forKey:paramIsFirstLoadOk];
363
+
364
+ NSString *lastVersion = pushyInfo[paramLastVersion];
365
+ NSString *curVersion = pushyInfo[paramCurrentVersion];
366
+ if (lastVersion != nil && ![lastVersion isEqualToString:curVersion]) {
367
+ [pushyInfo removeObjectForKey:[keyHashInfo stringByAppendingString:lastVersion]];
368
+ }
369
+ [defaults setObject:pushyInfo forKey:keyPushyInfo];
370
+ [defaults synchronize];
371
+
372
+ // clear other package dir
373
+ [self clearInvalidFiles];
374
+ resolve(@true);
375
+ }
376
+ @catch (NSException *exception) {
377
+ reject(@"执行报错", nil, nil);
323
378
  }
324
- [defaults setObject:pushyInfo forKey:keyPushyInfo];
325
- [defaults synchronize];
326
-
327
- // clear other package dir
328
- [self clearInvalidFiles];
329
379
  }
330
380
 
331
381
 
@@ -351,6 +401,19 @@ RCT_EXPORT_METHOD(markSuccess)
351
401
  // Remove upstream listeners, stop unnecessary background tasks
352
402
  }
353
403
 
404
+ - (BOOL) isBlankString:(NSString *)string {
405
+ if (string == nil || string == NULL) {
406
+ return YES;
407
+ }
408
+ if ([string isKindOfClass:[NSNull class]]) {
409
+ return YES;
410
+ }
411
+ if ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0) {
412
+ return YES;
413
+ }
414
+ return NO;
415
+ }
416
+
354
417
 
355
418
  - (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
356
419
  {
@@ -362,7 +425,7 @@ RCT_EXPORT_METHOD(markSuccess)
362
425
  return;
363
426
  }
364
427
  NSString *originHash = [RCTConvert NSString:options[@"originHash"]];
365
- if (type == PushyTypePatchFromPpk && originHash <= 0) {
428
+ if (type == PushyTypePatchFromPpk && [self isBlankString:originHash]) {
366
429
  callback([self errorWithMessage:ERROR_OPTIONS]);
367
430
  return;
368
431
  }
@@ -562,4 +625,13 @@ RCT_EXPORT_METHOD(markSuccess)
562
625
  #endif
563
626
  }
564
627
 
628
+ // Thanks to this guard, we won't compile this code when we build for the old architecture.
629
+ #ifdef RCT_NEW_ARCH_ENABLED
630
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
631
+ (const facebook::react::ObjCTurboModule::InitParams &)params
632
+ {
633
+ return std::make_shared<facebook::react::NativeUpdateSpecJSI>(params);
634
+ }
635
+ #endif
636
+
565
637
  @end
@@ -1 +1 @@
1
- 1654072539
1
+ 1680488830
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @format
3
+ * @flow strict-local
4
+ */
5
+ 'use strict';
6
+
7
+ import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
8
+ import { TurboModuleRegistry } from 'react-native';
9
+
10
+ export interface Spec extends TurboModule {
11
+ getConstants: () => {
12
+ downloadRootDir: string,
13
+ packageVersion: string,
14
+ currentVersion: string,
15
+ isFirstTime: boolean,
16
+ rolledBackVersion: string,
17
+ buildTime: string,
18
+ blockUpdate: Object,
19
+ uuid: string,
20
+ isUsingBundleUrl: boolean,
21
+ };
22
+ setLocalHashInfo(hash: string, info: string): Promise<void>;
23
+ getLocalHashInfo(hash: string): Promise<string>;
24
+ setUuid(uuid: string): Promise<void>;
25
+ setBlockUpdate(options: { reason: string, until: number }): Promise<void>;
26
+ reloadUpdate(options: { hash: string }): Promise<void>;
27
+ setNeedUpdate(options: { hash: string }): Promise<void>;
28
+ markSuccess(): Promise<void>;
29
+ downloadPatchFromPpk(options: {
30
+ updateUrl: string,
31
+ hash: string,
32
+ originHash: string,
33
+ }): Promise<void>;
34
+ downloadPatchFromPackage(options: {
35
+ updateUrl: string,
36
+ hash: string,
37
+ }): Promise<void>;
38
+ downloadFullUpdate(options: {
39
+ updateUrl: string,
40
+ hash: string,
41
+ }): Promise<void>;
42
+ downloadAndInstallApk(options: {
43
+ url: string,
44
+ target: string,
45
+ hash: string,
46
+ }): Promise<void>;
47
+ addListener(eventName: string): void;
48
+ removeListeners(count: number): void;
49
+ }
50
+
51
+ export default (TurboModuleRegistry.get<Spec>('Pushy'): ?Spec);
@@ -1,6 +1,6 @@
1
1
  let currentEndpoint = 'https://update.react-native.cn/api';
2
2
 
3
- function ping(url, rejectImmediate) {
3
+ function ping(url: string, rejectImmediate?: boolean) {
4
4
  return new Promise((resolve, reject) => {
5
5
  const xhr = new XMLHttpRequest();
6
6
  xhr.onreadystatechange = (e) => {
@@ -20,12 +20,12 @@ function ping(url, rejectImmediate) {
20
20
  });
21
21
  }
22
22
 
23
- function logger(...args) {
24
- // console.warn('pushy', ...args);
23
+ function logger(...args: any[]) {
24
+ console.log('Pushy: ', ...args);
25
25
  }
26
26
 
27
- let backupEndpoints = [];
28
- let backupEndpointsQueryUrl =
27
+ let backupEndpoints: string[] = [];
28
+ let backupEndpointsQueryUrl: string | null =
29
29
  'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-pushy@master/endpoints.json';
30
30
 
31
31
  export async function tryBackupEndpoints() {
@@ -34,10 +34,10 @@ export async function tryBackupEndpoints() {
34
34
  }
35
35
  try {
36
36
  await ping(getStatusUrl(), true);
37
- logger('current endpoint ok');
37
+ logger('current endpoint ok', currentEndpoint);
38
38
  return;
39
39
  } catch (e) {
40
- logger('current endpoint failed');
40
+ logger('current endpoint failed', currentEndpoint);
41
41
  }
42
42
  if (!backupEndpoints.length && backupEndpointsQueryUrl) {
43
43
  try {
@@ -76,11 +76,21 @@ export function getCheckUrl(APPKEY, endpoint = currentEndpoint) {
76
76
  return `${endpoint}/checkUpdate/${APPKEY}`;
77
77
  }
78
78
 
79
- export function getReportUrl(endpoint = currentEndpoint) {
80
- return `${endpoint}/report`;
81
- }
82
-
83
- export function setCustomEndpoints({ main, backups, backupQueryUrl }) {
79
+ /**
80
+ * @param {string} main - The main api endpoint
81
+ * @param {string[]} [backups] - The back up endpoints.
82
+ * @param {string} [backupQueryUrl] - An url that return a json file containing an array of endpoint.
83
+ * like: ["https://backup.api/1", "https://backup.api/2"]
84
+ */
85
+ export function setCustomEndpoints({
86
+ main,
87
+ backups,
88
+ backupQueryUrl,
89
+ }: {
90
+ main: string;
91
+ backups?: string[];
92
+ backupQueryUrl?: string;
93
+ }) {
84
94
  currentEndpoint = main;
85
95
  backupEndpointsQueryUrl = null;
86
96
  if (Array.isArray(backups) && backups.length > 0) {
package/lib/index.web.js CHANGED
@@ -15,3 +15,4 @@ export const downloadAndInstallApk = noop;
15
15
  export const setCustomEndpoints = noop;
16
16
  export const getCurrentVersionInfo = noop;
17
17
  export const simpleUpdate = noop;
18
+ export const onEvents = noop;