react-native-update 10.55.1 → 10.56.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.
- package/README-CN.md +35 -0
- package/README.md +37 -0
- package/android/build.gradle +53 -27
- package/android/jni/Application.mk +6 -1
- package/android/jni/hpatch.c +59 -4
- package/android/lib/arm64-v8a/librnupdate.so +0 -0
- package/android/lib/armeabi-v7a/librnupdate.so +0 -0
- package/android/lib/x86/librnupdate.so +0 -0
- package/android/lib/x86_64/librnupdate.so +0 -0
- package/android/proguard.pro +70 -14
- package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +15 -8
- package/android/src/main/java/cn/reactnative/modules/update/ArchiveLimits.java +1 -0
- package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +1 -2
- package/android/src/main/java/cn/reactnative/modules/update/CleanupKeepNames.java +25 -0
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +98 -34
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +29 -0
- package/android/src/main/java/cn/reactnative/modules/update/FileOperationException.java +15 -0
- package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +59 -0
- package/android/src/main/java/cn/reactnative/modules/update/InstallRecord.java +27 -1
- package/android/src/main/java/cn/reactnative/modules/update/NativeCheckOrchestrator.java +57 -16
- package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +38 -46
- package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +279 -183
- package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +14 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +222 -215
- package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +5 -0
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +23 -25
- package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +29 -29
- package/cpp/patch_core/archive_limits.h +6 -0
- package/cpp/patch_core/jni_util.h +6 -2
- package/cpp/patch_core/patch_core.cpp +237 -84
- package/cpp/patch_core/patch_core.h +11 -0
- package/cpp/patch_core/patch_core_android.cpp +49 -33
- package/cpp/patch_core/update_core_android.cpp +134 -103
- package/cpp/update_flow_core/flow_json.cpp +150 -17
- package/cpp/update_flow_core/flow_json.h +13 -1
- package/cpp/update_flow_core/update_flow_core.cpp +78 -8
- package/cpp/update_flow_core/update_flow_core.h +9 -0
- package/cpp/update_flow_core/update_flow_jni.cpp +44 -25
- package/harmony/hvigor-plugin.ts +168 -21
- package/harmony/pushy/src/README.md +74 -0
- package/harmony/pushy/src/main/cpp/CMakeLists.txt +13 -3
- package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +11 -5
- package/harmony/pushy/src/main/cpp/pushy.cpp +103 -18
- package/harmony/pushy/src/main/ets/ArchiveLimits.ts +61 -5
- package/harmony/pushy/src/main/ets/DownloadTask.ts +255 -166
- package/harmony/pushy/src/main/ets/ErrorCodes.ts +75 -0
- package/harmony/pushy/src/main/ets/EventHub.ts +22 -20
- package/harmony/pushy/src/main/ets/InstallRecord.ts +79 -21
- package/harmony/pushy/src/main/ets/Logger.ts +42 -16
- package/harmony/pushy/src/main/ets/NativeCheckOrchestrator.ts +98 -17
- package/harmony/pushy/src/main/ets/NativePatchCore.ts +10 -3
- package/harmony/pushy/src/main/ets/PathUtils.ts +9 -3
- package/harmony/pushy/src/main/ets/PushyTurboModule.ts +139 -53
- package/harmony/pushy/src/main/ets/UpdateContext.ts +269 -159
- package/harmony/pushy/src/main/module.json5 +5 -1
- package/harmony/pushy.har +0 -0
- package/ios/PrivacyInfo.xcprivacy +79 -0
- package/ios/RCTPushy/RCTPushy.mm +399 -170
- package/ios/RCTPushy/RCTPushyDownloader.h +14 -0
- package/ios/RCTPushy/RCTPushyDownloader.mm +136 -11
- package/package.json +14 -24
- package/react-native-update.podspec +36 -3
- package/src/client.ts +236 -82
- package/src/context.ts +40 -27
- package/src/core.ts +41 -16
- package/src/endpoint.ts +2 -1
- package/src/error.ts +49 -11
- package/src/index.ts +14 -0
- package/src/locales/en.ts +1 -23
- package/src/locales/zh.ts +1 -22
- package/src/provider.tsx +159 -111
- package/src/type.ts +0 -2
- package/src/updateFlowCore.ts +10 -2
- package/src/utils.ts +61 -4
- package/android/src/main/java/cn/reactnative/modules/update/ReactNativeHostHandler.java +0 -13
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleSupport.java +0 -45
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
#import <Foundation/Foundation.h>
|
|
2
2
|
|
|
3
|
+
// Path of the resume sidecar that records what a partial download at
|
|
4
|
+
// `savePath` belongs to (url + validators + total). Shared with the unzip
|
|
5
|
+
// step, which must drop it together with the archive it vouches for.
|
|
6
|
+
FOUNDATION_EXPORT NSString *RCTPushyResumeSidecarPath(NSString *savePath);
|
|
7
|
+
|
|
8
|
+
// Size of the file at `path` in bytes; -1 when it cannot be read.
|
|
9
|
+
FOUNDATION_EXPORT long long RCTPushyFileSize(NSString *path);
|
|
10
|
+
|
|
11
|
+
// nil when the volume holding `path` can take `bytesToWrite` plus the
|
|
12
|
+
// cpp/patch_core/archive_limits.h safety margin (or the free space is
|
|
13
|
+
// unknown); the reason otherwise. `path` need not exist yet — the check walks
|
|
14
|
+
// up to an existing ancestor.
|
|
15
|
+
FOUNDATION_EXPORT NSString *RCTPushyFreeSpaceShortfall(NSString *path, long long bytesToWrite);
|
|
16
|
+
|
|
3
17
|
@interface RCTPushyDownloader : NSObject
|
|
4
18
|
|
|
5
19
|
+ (void)download:(NSString *)downloadPath savePath:(NSString *)savePath
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#import "RCTPushyDownloader.h"
|
|
2
|
+
#include "../../cpp/patch_core/archive_limits.h"
|
|
2
3
|
|
|
3
4
|
static NSString *const RCTPushyDownloaderErrorDomain = @"cn.reactnative.pushy";
|
|
4
5
|
|
|
5
|
-
// Cross-launch resumable download (NATIVE_CHECKUPDATE_DESIGN §11.4):
|
|
6
|
-
//
|
|
6
|
+
// Cross-launch resumable download (NATIVE_CHECKUPDATE_DESIGN §11.4): a data
|
|
7
|
+
// task streams the archive straight into savePath (a download task's
|
|
7
8
|
// temporary file is discarded on failure, which made every partial byte
|
|
8
9
|
// worthless), and a sidecar next to it records what the partial belongs to
|
|
9
10
|
// (url + validators + total). A brick gets a few hundred milliseconds per
|
|
10
11
|
// launch plus a bounded crash-rescue window, so progress must be monotonic
|
|
11
12
|
// across process deaths.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
NSString *RCTPushyResumeSidecarPath(NSString *savePath) {
|
|
14
15
|
return [savePath stringByAppendingString:@".resume"];
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -35,15 +36,44 @@ static void RCTPushyDeleteResumeSidecar(NSString *savePath) {
|
|
|
35
36
|
error:nil];
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
long long RCTPushyFileSize(NSString *path) {
|
|
39
40
|
NSDictionary *attributes =
|
|
40
41
|
[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
|
|
41
42
|
NSNumber *size = attributes[NSFileSize];
|
|
42
43
|
return size == nil ? -1 : size.longLongValue;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
// Free space on the volume holding `path` (walks up to an existing ancestor);
|
|
47
|
+
// -1 when unknown.
|
|
48
|
+
static long long RCTPushyFreeDiskSpaceForPath(NSString *path) {
|
|
49
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
50
|
+
NSString *probe = path;
|
|
51
|
+
while (probe.length > 1 && ![fileManager fileExistsAtPath:probe]) {
|
|
52
|
+
probe = [probe stringByDeletingLastPathComponent];
|
|
53
|
+
}
|
|
54
|
+
NSDictionary *attributes = [fileManager attributesOfFileSystemForPath:probe error:nil];
|
|
55
|
+
NSNumber *free = attributes[NSFileSystemFreeSize];
|
|
56
|
+
return free == nil ? -1 : free.longLongValue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
NSString *RCTPushyFreeSpaceShortfall(NSString *path, long long bytesToWrite) {
|
|
60
|
+
long long free = RCTPushyFreeDiskSpaceForPath(path);
|
|
61
|
+
if (free < 0) {
|
|
62
|
+
return nil;
|
|
63
|
+
}
|
|
64
|
+
long long needed = MAX(0LL, bytesToWrite) + pushy::archive_limits::kFreeDiskMarginBytes;
|
|
65
|
+
if (free < needed) {
|
|
66
|
+
return [NSString stringWithFormat:@"insufficient disk space: need %lld bytes, have %lld",
|
|
67
|
+
needed, free];
|
|
68
|
+
}
|
|
69
|
+
return nil;
|
|
70
|
+
}
|
|
71
|
+
|
|
45
72
|
// "bytes <start>-<end>/<total>". Returns the total (0 when "*"), or -1 when
|
|
46
|
-
// missing/malformed
|
|
73
|
+
// missing/malformed, the start does not match the local partial, or the
|
|
74
|
+
// range and total contradict each other (end before start, or a numeric
|
|
75
|
+
// total not beyond the end — RFC 9110 §14.4). A total of 0 would otherwise
|
|
76
|
+
// pass as "unknown" and skip the final size check.
|
|
47
77
|
static long long RCTPushyParseContentRange(NSString *header, long long expectedStart) {
|
|
48
78
|
if (![header hasPrefix:@"bytes "]) {
|
|
49
79
|
return -1;
|
|
@@ -56,16 +86,35 @@ static long long RCTPushyParseContentRange(NSString *header, long long expectedS
|
|
|
56
86
|
|| dash.location > slash.location) {
|
|
57
87
|
return -1;
|
|
58
88
|
}
|
|
59
|
-
|
|
60
|
-
|
|
89
|
+
NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
|
|
90
|
+
NSString *startPart = [[range substringToIndex:dash.location]
|
|
91
|
+
stringByTrimmingCharactersInSet:whitespace];
|
|
92
|
+
NSString *endPart = [[range substringWithRange:
|
|
93
|
+
NSMakeRange(dash.location + 1, slash.location - dash.location - 1)]
|
|
94
|
+
stringByTrimmingCharactersInSet:whitespace];
|
|
95
|
+
NSString *totalPart = [[range substringFromIndex:slash.location + 1]
|
|
96
|
+
stringByTrimmingCharactersInSet:whitespace];
|
|
97
|
+
// longLongValue reads 0 for non-numeric text; require real digits.
|
|
98
|
+
NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];
|
|
99
|
+
if (startPart.length == 0 || endPart.length == 0
|
|
100
|
+
|| [startPart rangeOfCharacterFromSet:digits.invertedSet].location != NSNotFound
|
|
101
|
+
|| [endPart rangeOfCharacterFromSet:digits.invertedSet].location != NSNotFound) {
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
long long start = startPart.longLongValue;
|
|
105
|
+
long long end = endPart.longLongValue;
|
|
106
|
+
if (start != expectedStart || end < start) {
|
|
61
107
|
return -1;
|
|
62
108
|
}
|
|
63
|
-
NSString *totalPart = [range substringFromIndex:slash.location + 1];
|
|
64
109
|
if ([totalPart isEqualToString:@"*"]) {
|
|
65
110
|
return 0;
|
|
66
111
|
}
|
|
112
|
+
if (totalPart.length == 0
|
|
113
|
+
|| [totalPart rangeOfCharacterFromSet:digits.invertedSet].location != NSNotFound) {
|
|
114
|
+
return -1;
|
|
115
|
+
}
|
|
67
116
|
long long total = totalPart.longLongValue;
|
|
68
|
-
return total >
|
|
117
|
+
return total > end ? total : -1;
|
|
69
118
|
}
|
|
70
119
|
|
|
71
120
|
@interface RCTPushyDownloader()<NSURLSessionDataDelegate>
|
|
@@ -90,8 +139,15 @@ static long long RCTPushyParseContentRange(NSString *header, long long expectedS
|
|
|
90
139
|
// NSURLSession delivers decoded bytes, so length accounting against the
|
|
91
140
|
// encoded Content-Length is meaningless and resume offsets cannot be trusted.
|
|
92
141
|
@property (nonatomic, assign) BOOL encodedBody;
|
|
142
|
+
// The archive was rejected outright (over archive_limits::kMaxArchiveBytes):
|
|
143
|
+
// nothing on disk is worth resuming, so completion drops the partial and its
|
|
144
|
+
// sidecar instead of leaving them as resume state.
|
|
145
|
+
@property (nonatomic, assign) BOOL discardPartial;
|
|
93
146
|
@property (nonatomic, assign) int lastReportedPercentage;
|
|
94
147
|
@property (nonatomic, assign) long long lastReportedBytes;
|
|
148
|
+
// receivedBytes up to which free disk has been probed for (unknown-length
|
|
149
|
+
// bodies; 0 = probe before the first write)
|
|
150
|
+
@property (nonatomic, assign) long long freeSpaceReservedUntil;
|
|
95
151
|
@end
|
|
96
152
|
|
|
97
153
|
@implementation RCTPushyDownloader
|
|
@@ -221,6 +277,10 @@ completionHandler:(void (^)(NSString *path, NSError *error))completionHandler
|
|
|
221
277
|
}
|
|
222
278
|
self.fileHandle = nil;
|
|
223
279
|
}
|
|
280
|
+
if (self.discardPartial) {
|
|
281
|
+
[[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
|
|
282
|
+
RCTPushyDeleteResumeSidecar(self.savePath);
|
|
283
|
+
}
|
|
224
284
|
|
|
225
285
|
void (^completionHandler)(NSString *, NSError *) = self.completionHandler;
|
|
226
286
|
self.progressHandler = nil;
|
|
@@ -375,12 +435,44 @@ didReceiveResponse:(NSURLResponse *)response
|
|
|
375
435
|
self.expectedTotal = self.contentLength > 0 ? self.contentLength : 0;
|
|
376
436
|
}
|
|
377
437
|
|
|
438
|
+
// Caps from archive_limits.h, applied before the first body byte lands
|
|
439
|
+
// (Android does the same): the announced size up front here, streamed
|
|
440
|
+
// bytes in didReceiveData as the backstop for unknown/chunked lengths.
|
|
441
|
+
long long announcedTotal = self.expectedTotal;
|
|
442
|
+
if (announcedTotal <= 0 && !self.encodedBody && self.contentLength > 0) {
|
|
443
|
+
// A 206 whose Content-Range total is "*" still announces this body.
|
|
444
|
+
announcedTotal = self.baseOffset + self.contentLength;
|
|
445
|
+
}
|
|
446
|
+
if (announcedTotal > pushy::archive_limits::kMaxArchiveBytes) {
|
|
447
|
+
[self failWithDescription:[NSString stringWithFormat:@"archive too large: %lld bytes",
|
|
448
|
+
announcedTotal]
|
|
449
|
+
code:-1];
|
|
450
|
+
self.discardPartial = YES;
|
|
451
|
+
completionHandler(NSURLSessionResponseCancel);
|
|
452
|
+
[self completeWithError:self.fileError];
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
378
455
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
379
456
|
if (!append) {
|
|
380
|
-
// The server ignored the range (or none was sent):
|
|
457
|
+
// The server ignored the range (or none was sent): the stale partial
|
|
458
|
+
// is dead weight either way, so free it before the space check
|
|
459
|
+
// counts it against this download (a full restart must not fail
|
|
460
|
+
// forever on space the partial itself is holding).
|
|
381
461
|
[fileManager removeItemAtPath:self.savePath error:nil];
|
|
462
|
+
}
|
|
463
|
+
NSString *shortfall = RCTPushyFreeSpaceShortfall(
|
|
464
|
+
self.savePath, announcedTotal > 0 ? announcedTotal - self.baseOffset : 0);
|
|
465
|
+
if (shortfall != nil) {
|
|
466
|
+
// A resumable partial stays: a later attempt may find the space.
|
|
467
|
+
[self failWithDescription:shortfall code:-1];
|
|
468
|
+
completionHandler(NSURLSessionResponseCancel);
|
|
469
|
+
[self completeWithError:self.fileError];
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (!append) {
|
|
382
473
|
[fileManager createFileAtPath:self.savePath contents:nil attributes:nil];
|
|
383
474
|
}
|
|
475
|
+
self.freeSpaceReservedUntil = 0;
|
|
384
476
|
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.savePath];
|
|
385
477
|
if (self.fileHandle == nil) {
|
|
386
478
|
[self failWithDescription:@"cannot open download file for writing" code:-1];
|
|
@@ -418,6 +510,38 @@ didReceiveResponse:(NSURLResponse *)response
|
|
|
418
510
|
if (self.fileHandle == nil || self.fileError != nil) {
|
|
419
511
|
return;
|
|
420
512
|
}
|
|
513
|
+
if (self.baseOffset + self.receivedBytes + (long long)data.length
|
|
514
|
+
> pushy::archive_limits::kMaxArchiveBytes) {
|
|
515
|
+
// Unknown/chunked length backstop; an announced size was already
|
|
516
|
+
// checked in didReceiveResponse. Checked before the write so the
|
|
517
|
+
// file on disk never exceeds the cap.
|
|
518
|
+
[self failWithDescription:[NSString stringWithFormat:
|
|
519
|
+
@"archive too large: exceeded %lld bytes",
|
|
520
|
+
pushy::archive_limits::kMaxArchiveBytes]
|
|
521
|
+
code:-1];
|
|
522
|
+
self.discardPartial = YES;
|
|
523
|
+
[dataTask cancel];
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
if (self.expectedTotal <= 0
|
|
527
|
+
&& self.receivedBytes + (long long)data.length > self.freeSpaceReservedUntil) {
|
|
528
|
+
// Unknown/encoded length: the response-time check could only
|
|
529
|
+
// reserve the margin, so probe before any write that would run past
|
|
530
|
+
// the bytes reserved so far, each probe reserving at least the next
|
|
531
|
+
// PROBE bytes (more when one callback carries a larger buffer) — no
|
|
532
|
+
// write can ever eat into the margin. The archive cap alone (512
|
|
533
|
+
// MiB) is far more than the margin protects. The partial stays: a
|
|
534
|
+
// later attempt may find the space.
|
|
535
|
+
long long reserve = MAX(pushy::archive_limits::kUnknownLengthFreeSpaceProbeBytes,
|
|
536
|
+
(long long)data.length);
|
|
537
|
+
self.freeSpaceReservedUntil = self.receivedBytes + reserve;
|
|
538
|
+
NSString *shortfall = RCTPushyFreeSpaceShortfall(self.savePath, reserve);
|
|
539
|
+
if (shortfall != nil) {
|
|
540
|
+
[self failWithDescription:shortfall code:-1];
|
|
541
|
+
[dataTask cancel];
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
421
545
|
@try {
|
|
422
546
|
[self.fileHandle writeData:data];
|
|
423
547
|
} @catch (NSException *exception) {
|
|
@@ -488,7 +612,8 @@ didCompleteWithError:(NSError *)error
|
|
|
488
612
|
}
|
|
489
613
|
}
|
|
490
614
|
// On failure the partial + sidecar stay on disk — that is the resume
|
|
491
|
-
// state a later launch (or crash-rescue window) picks up
|
|
615
|
+
// state a later launch (or crash-rescue window) picks up — unless the
|
|
616
|
+
// archive was rejected outright (discardPartial).
|
|
492
617
|
[self completeWithError:finalError];
|
|
493
618
|
}
|
|
494
619
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-update",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.56.0",
|
|
4
4
|
"description": "react-native hot update",
|
|
5
5
|
"main": "src/index",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"src",
|
|
9
9
|
"!src/__tests__",
|
|
10
10
|
"android/src",
|
|
11
|
+
"!android/src/test",
|
|
11
12
|
"android/lib",
|
|
12
13
|
"android/jni",
|
|
13
14
|
"!android/jni/HDiffPatch/test",
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
"prepublishOnly": "NODE_ENV=production bun scripts/prepublish.ts",
|
|
33
34
|
"publish:local": "SKIP_NATIVE_BUILD=1 npm publish",
|
|
34
35
|
"prepack": "bun submodule && bun lint",
|
|
35
|
-
"lint": "biome check src && tsc --noEmit && node scripts/check-harmony-types.js",
|
|
36
|
+
"lint": "biome check src && tsc --noEmit && node scripts/check-harmony-types.js && node scripts/check-native-spec-parity.js",
|
|
36
37
|
"lint:harmony": "node scripts/check-harmony-types.js",
|
|
37
38
|
"submodule": "git submodule update --init --recursive",
|
|
38
39
|
"test": "bun test src/__tests__",
|
|
@@ -42,21 +43,17 @@
|
|
|
42
43
|
"build:harmony-har": "node scripts/build-harmony-har.js",
|
|
43
44
|
"build:harmony-e2e": "bash Example/e2etest/scripts/build-harmony-e2e.sh",
|
|
44
45
|
"build:so": "bun submodule && bash scripts/build-android-so.sh",
|
|
45
|
-
"build:ios-debug": "cd Example/e2etest && bun && detox build --configuration ios.sim.debug",
|
|
46
|
-
"build:ios-release": "cd Example/e2etest && bun && detox build --configuration ios.sim.release",
|
|
47
|
-
"test:ios-debug": "cd Example/e2etest && E2E_PLATFORM=ios detox test --configuration ios.sim.debug",
|
|
48
|
-
"test:ios-release": "cd Example/e2etest && E2E_PLATFORM=ios
|
|
49
|
-
"build:android-debug": "cd Example/e2etest && bun && detox build --configuration android.emu.debug",
|
|
50
|
-
"build:android-release": "cd Example/e2etest && bun && detox build --configuration android.emu.release",
|
|
51
|
-
"test:android-release": "cd Example/e2etest && E2E_PLATFORM=android
|
|
52
|
-
"test:android-debug": "cd Example/e2etest && E2E_PLATFORM=android detox test --configuration android.emu.debug --headless --record-logs all",
|
|
53
|
-
"smoke:android-debug": "cd Example/e2etest && detox test --configuration android.emu.debug --config e2e/smoke/jest.config.js",
|
|
46
|
+
"build:ios-debug": "cd Example/e2etest && bun && bunx detox build --configuration ios.sim.debug",
|
|
47
|
+
"build:ios-release": "cd Example/e2etest && bun && bunx detox build --configuration ios.sim.release",
|
|
48
|
+
"test:ios-debug": "cd Example/e2etest && E2E_PLATFORM=ios bunx detox test --configuration ios.sim.debug",
|
|
49
|
+
"test:ios-release": "cd Example/e2etest && E2E_PLATFORM=ios bunx detox test --configuration ios.sim.release",
|
|
50
|
+
"build:android-debug": "cd Example/e2etest && bun && bunx detox build --configuration android.emu.debug",
|
|
51
|
+
"build:android-release": "cd Example/e2etest && bun && bunx detox build --configuration android.emu.release",
|
|
52
|
+
"test:android-release": "cd Example/e2etest && E2E_PLATFORM=android bunx detox test --configuration android.emu.release --headless --record-logs all",
|
|
53
|
+
"test:android-debug": "cd Example/e2etest && E2E_PLATFORM=android bunx detox test --configuration android.emu.debug --headless --record-logs all",
|
|
54
|
+
"smoke:android-debug": "cd Example/e2etest && bunx detox test --configuration android.emu.debug --config e2e/smoke/jest.config.js",
|
|
54
55
|
"e2e:ios": "bun build:ios-release && bun test:ios-release",
|
|
55
|
-
"e2e:android": "bun build:android-release && bun test:android-release"
|
|
56
|
-
"tests:emulator:prepare": "cd .github/workflows/scripts/functions && bun && bun build",
|
|
57
|
-
"tests:emulator:start-ci": "bun tests:emulator:prepare && cd ./.github/workflows/scripts && ./start-firebase-emulator.sh",
|
|
58
|
-
"tests:packager:jet-ci": "cd Example/e2etest && cross-env TMPDIR=$HOME/.metro REACT_DEBUGGER=\"echo nope\" node_modules/.bin/react-native start --no-interactive",
|
|
59
|
-
"tests:ios:pod:install": "cd Example/e2etest && bun && bun pod-install"
|
|
56
|
+
"e2e:android": "bun build:android-release && bun test:android-release"
|
|
60
57
|
},
|
|
61
58
|
"repository": {
|
|
62
59
|
"type": "git",
|
|
@@ -79,8 +76,7 @@
|
|
|
79
76
|
},
|
|
80
77
|
"homepage": "https://github.com/reactnativecn/react-native-update#readme",
|
|
81
78
|
"dependencies": {
|
|
82
|
-
"nanoid": "^3.3.3"
|
|
83
|
-
"react-native-url-polyfill": "^3.0.0"
|
|
79
|
+
"nanoid": "^3.3.3"
|
|
84
80
|
},
|
|
85
81
|
"codegenConfig": {
|
|
86
82
|
"name": "RCTPushySpec",
|
|
@@ -93,18 +89,12 @@
|
|
|
93
89
|
"@react-native/babel-preset": "^0.73.21",
|
|
94
90
|
"@react-native/typescript-config": "0.84.1",
|
|
95
91
|
"@types/bun": "^1.3.11",
|
|
96
|
-
"@types/jest": "^30.0.0",
|
|
97
92
|
"@types/node": "^25.5.0",
|
|
98
93
|
"@types/react": "^19.2.14",
|
|
99
94
|
"@types/react-test-renderer": "18.0.7",
|
|
100
|
-
"detox": "^20.50.1",
|
|
101
|
-
"firebase-tools": "^15.11.0",
|
|
102
|
-
"jest": "^30.3.0",
|
|
103
|
-
"pod-install": "^1.0.14",
|
|
104
95
|
"react": "18.2.0",
|
|
105
96
|
"react-native": "0.73",
|
|
106
97
|
"react-test-renderer": "18.2.0",
|
|
107
|
-
"ts-jest": "^29.4.6",
|
|
108
98
|
"typescript": "^7.0.2"
|
|
109
99
|
}
|
|
110
100
|
}
|
|
@@ -91,16 +91,49 @@ Pod::Spec.new do |s|
|
|
|
91
91
|
s.source = { :git => 'https://github.com/reactnativecn/react-native-update.git', :tag => "#{s.version}" }
|
|
92
92
|
|
|
93
93
|
s.libraries = 'bz2', 'z'
|
|
94
|
+
# No search path into the pod source: every include under ios/ resolves
|
|
95
|
+
# relative to the including file (the cpp/ core via ../../cpp/...), and the
|
|
96
|
+
# former absolute "#{podspec_dir}/ios" entry made the generated xcconfig
|
|
97
|
+
# machine-specific.
|
|
94
98
|
s.pod_target_xcconfig = {
|
|
95
|
-
'USER_HEADER_SEARCH_PATHS' => "
|
|
99
|
+
'USER_HEADER_SEARCH_PATHS' => "\"$(PODS_ROOT)/Headers/Public/SSZipArchive\" \"$(PODS_ROOT)/Headers/Public/React-Codegen/RCTPushySpec\"",
|
|
96
100
|
"DEFINES_MODULE" => "YES"
|
|
97
101
|
}
|
|
102
|
+
# buildTime for binary-rebuild detection (SyncBinaryVersion) and the check
|
|
103
|
+
# request. The stamp is refreshed on every build and ships as a resource.
|
|
104
|
+
# When the pod source is not writable (read-only checkout or cache) the
|
|
105
|
+
# committed value is kept; +buildTime falls back to the main bundle's
|
|
106
|
+
# Info.plist mtime when the file is missing or empty, so it is never blank.
|
|
98
107
|
s.resource = 'ios/pushy_build_time.txt'
|
|
99
|
-
|
|
108
|
+
build_time_phase = {
|
|
109
|
+
:name => 'Generate build time',
|
|
110
|
+
:script => "set -x; f=\"${PODS_TARGET_SRCROOT:-#{podspec_dir}}/ios/pushy_build_time.txt\"; if [ -w \"$f\" ] || { [ ! -e \"$f\" ] && [ -w \"$(dirname \"$f\")\" ]; }; then date +%s > \"$f\"; else echo \"warning: $f is not writable, keeping the shipped build time\"; fi",
|
|
111
|
+
:execution_position => :before_compile
|
|
112
|
+
}
|
|
113
|
+
# Declaring the output lets Xcode order the resource copy (into the app, or
|
|
114
|
+
# into this pod's framework under use_frameworks!) after the stamp is
|
|
115
|
+
# written and stops the output-less-phase warning. A phase with outputs and
|
|
116
|
+
# no inputs is otherwise skipped once the file exists — and it is committed
|
|
117
|
+
# — so the phase must also be marked always out of date to keep refreshing
|
|
118
|
+
# the stamp every build. CocoaPods < 1.11 has no such key; there the phase
|
|
119
|
+
# stays output-less (runs every build, as before).
|
|
120
|
+
if defined?(Pod::Specification::DSL::SCRIPT_PHASE_OPTIONAL_KEYS) &&
|
|
121
|
+
Pod::Specification::DSL::SCRIPT_PHASE_OPTIONAL_KEYS.include?(:always_out_of_date)
|
|
122
|
+
build_time_phase[:output_files] = ['$(PODS_TARGET_SRCROOT)/ios/pushy_build_time.txt']
|
|
123
|
+
build_time_phase[:always_out_of_date] = '1'
|
|
124
|
+
end
|
|
125
|
+
s.script_phase = build_time_phase
|
|
126
|
+
# Privacy manifest (required-reason APIs: disk space, file timestamps,
|
|
127
|
+
# system boot time, user defaults) delivered as its own resource bundle so
|
|
128
|
+
# static and dynamic integrations both carry it.
|
|
129
|
+
s.resource_bundles = { 'react-native-update_privacy' => ['ios/PrivacyInfo.xcprivacy'] }
|
|
100
130
|
|
|
101
131
|
s.dependency 'React'
|
|
102
132
|
s.dependency "React-Core"
|
|
103
|
-
|
|
133
|
+
# The unzip guard relies on the 2.x delegate contract
|
|
134
|
+
# (zipArchiveShouldUnzipFileAtIndex:... cancels, _sanitizedPath); a future
|
|
135
|
+
# major could change it silently.
|
|
136
|
+
s.dependency 'SSZipArchive', '~> 2.4'
|
|
104
137
|
|
|
105
138
|
# Conditionally add Expo dependency
|
|
106
139
|
if valid_expo_project
|