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.
- package/.github/workflows/e2e_android.yml +49 -0
- package/.github/workflows/e2e_ios.yml +182 -0
- package/.github/workflows/scripts/adb_all_emulators.sh +10 -0
- package/.github/workflows/scripts/database.rules +13 -0
- package/.github/workflows/scripts/firebase.json +39 -0
- package/.github/workflows/scripts/firestore.indexes.json +72 -0
- package/.github/workflows/scripts/firestore.rules +17 -0
- package/.github/workflows/scripts/functions/package.json +24 -0
- package/.github/workflows/scripts/functions/src/exports.ts +13 -0
- package/.github/workflows/scripts/functions/src/index.ts +12 -0
- package/.github/workflows/scripts/functions/src/sample-data.ts +80 -0
- package/.github/workflows/scripts/functions/src/testFunctionCustomRegion.ts +14 -0
- package/.github/workflows/scripts/functions/src/testFunctionDefaultRegion.ts +70 -0
- package/.github/workflows/scripts/functions/tsconfig.json +16 -0
- package/.github/workflows/scripts/start-firebase-emulator.bat +6 -0
- package/.github/workflows/scripts/start-firebase-emulator.sh +44 -0
- package/.github/workflows/scripts/storage.rules +21 -0
- package/README.md +8 -6
- package/android/build.gradle +22 -0
- package/android/jni/hpatch.c +4 -4
- package/android/jni/hpatch.h +3 -3
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +0 -2
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +265 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +31 -20
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +147 -0
- package/android/src/{main/java → oldarch}/cn/reactnative/modules/update/UpdateModule.java +6 -2
- package/e2e/jest.config.js +12 -0
- package/e2e/starter.test.js +23 -0
- package/ios/RCTPushy/{RCTPushy.m → RCTPushy.mm} +116 -44
- package/ios/pushy_build_time.txt +1 -1
- package/lib/NativeUpdate.js +51 -0
- package/lib/{endpoint.js → endpoint.ts} +22 -12
- package/lib/index.web.js +1 -0
- package/lib/{main.js → main.ts} +122 -71
- package/lib/{simpleUpdate.js → simpleUpdate.tsx} +13 -4
- package/lib/type.ts +70 -0
- package/package.json +37 -3
- package/react-native-update.podspec +20 -2
- package/lib/index.d.ts +0 -94
- /package/ios/RCTPushy/HDiffPatch/{HDiffPatch.m → HDiffPatch.mm} +0 -0
- /package/ios/RCTPushy/{RCTPushyDownloader.m → RCTPushyDownloader.mm} +0 -0
- /package/ios/RCTPushy/{RCTPushyManager.m → RCTPushyManager.mm} +0 -0
- /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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
[
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
|
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
|
package/ios/pushy_build_time.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
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