@bravemobile/react-native-code-push 12.4.1 → 13.1.0-beta.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/CodePush.podspec +47 -2
- package/README.md +118 -3
- package/THIRD-PARTY-NOTICES +96 -0
- package/android/app/build.gradle +26 -0
- package/android/app/proguard-rules.pro +5 -0
- package/android/app/src/main/cpp/CMakeLists.txt +38 -0
- package/android/app/src/main/cpp/binarypatch_jni.c +181 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/BinaryPatchAttempt.java +92 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/BinaryPatchResult.java +64 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +46 -11
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushBinaryPatch.java +293 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java +25 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +79 -88
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +159 -4
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +13 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/HDiffPatchNative.java +52 -0
- package/android/app/src/test/java/com/microsoft/codepush/react/CodePushBinaryPatchTest.java +393 -0
- package/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerBinaryPatchTest.java +207 -0
- package/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerDownloadTest.java +449 -0
- package/android/codepush-export.gradle +115 -0
- package/cli/commands/bundleCommand/bundleCodePush.ts +39 -7
- package/cli/commands/bundleCommand/index.ts +9 -1
- package/cli/commands/releaseCommand/addToReleaseHistory.ts +7 -0
- package/cli/commands/releaseCommand/index.test.ts +118 -0
- package/cli/commands/releaseCommand/index.ts +20 -2
- package/cli/commands/releaseCommand/release.test.ts +582 -0
- package/cli/commands/releaseCommand/release.ts +232 -15
- package/cli/dist/commands/bundleCommand/bundleCodePush.js +26 -7
- package/cli/dist/commands/bundleCommand/index.js +5 -1
- package/cli/dist/commands/releaseCommand/addToReleaseHistory.js +6 -1
- package/cli/dist/commands/releaseCommand/index.js +8 -1
- package/cli/dist/commands/releaseCommand/index.test.js +96 -0
- package/cli/dist/commands/releaseCommand/release.js +165 -17
- package/cli/dist/commands/releaseCommand/release.test.js +367 -0
- package/cli/dist/functions/makeBinaryPatchBundle.js +248 -0
- package/cli/dist/functions/makeBinaryPatchBundle.test.js +321 -0
- package/cli/dist/functions/makeCodePushBundle.js +4 -2
- package/cli/dist/functions/runHermesEmitBinaryCommand.js +98 -27
- package/cli/dist/functions/runHermesEmitBinaryCommand.test.js +100 -0
- package/cli/dist/jest.globalSetup.js +38 -0
- package/cli/dist/utils/binaryPatch.js +86 -0
- package/cli/dist/utils/binaryPatch.test.js +190 -0
- package/cli/functions/makeBinaryPatchBundle.test.ts +410 -0
- package/cli/functions/makeBinaryPatchBundle.ts +367 -0
- package/cli/functions/makeCodePushBundle.ts +4 -2
- package/cli/functions/runHermesEmitBinaryCommand.test.ts +124 -0
- package/cli/functions/runHermesEmitBinaryCommand.ts +112 -26
- package/cli/jest.globalSetup.ts +43 -0
- package/cli/utils/binaryPatch.test.ts +234 -0
- package/cli/utils/binaryPatch.ts +103 -0
- package/cpp/binarypatch/binarypatch_zstd_decompressor.c +187 -0
- package/cpp/binarypatch/binarypatch_zstd_decompressor.h +47 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/checksum_plugin.h +52 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/hpatch_mt/hpatch_mt.h +147 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/patch.c +3315 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/patch.h +268 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/patch_private.h +297 -0
- package/cpp/binarypatch/vendor/HDiffPatch/libHDiffPatch/HPatch/patch_types.h +434 -0
- package/cpp/binarypatch/vendor/zstd/common/allocations.h +55 -0
- package/cpp/binarypatch/vendor/zstd/common/bits.h +205 -0
- package/cpp/binarypatch/vendor/zstd/common/bitstream.h +454 -0
- package/cpp/binarypatch/vendor/zstd/common/compiler.h +464 -0
- package/cpp/binarypatch/vendor/zstd/common/cpu.h +249 -0
- package/cpp/binarypatch/vendor/zstd/common/debug.c +30 -0
- package/cpp/binarypatch/vendor/zstd/common/debug.h +107 -0
- package/cpp/binarypatch/vendor/zstd/common/entropy_common.c +340 -0
- package/cpp/binarypatch/vendor/zstd/common/error_private.c +64 -0
- package/cpp/binarypatch/vendor/zstd/common/error_private.h +158 -0
- package/cpp/binarypatch/vendor/zstd/common/fse.h +625 -0
- package/cpp/binarypatch/vendor/zstd/common/fse_decompress.c +315 -0
- package/cpp/binarypatch/vendor/zstd/common/huf.h +277 -0
- package/cpp/binarypatch/vendor/zstd/common/mem.h +422 -0
- package/cpp/binarypatch/vendor/zstd/common/pool.c +371 -0
- package/cpp/binarypatch/vendor/zstd/common/pool.h +81 -0
- package/cpp/binarypatch/vendor/zstd/common/portability_macros.h +171 -0
- package/cpp/binarypatch/vendor/zstd/common/threading.c +182 -0
- package/cpp/binarypatch/vendor/zstd/common/threading.h +142 -0
- package/cpp/binarypatch/vendor/zstd/common/xxhash.c +18 -0
- package/cpp/binarypatch/vendor/zstd/common/xxhash.h +7094 -0
- package/cpp/binarypatch/vendor/zstd/common/zstd_common.c +48 -0
- package/cpp/binarypatch/vendor/zstd/common/zstd_deps.h +123 -0
- package/cpp/binarypatch/vendor/zstd/common/zstd_internal.h +324 -0
- package/cpp/binarypatch/vendor/zstd/common/zstd_trace.h +156 -0
- package/cpp/binarypatch/vendor/zstd/decompress/huf_decompress.c +1944 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_ddict.c +244 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_ddict.h +44 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_decompress.c +2410 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_decompress_block.c +2209 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_decompress_block.h +73 -0
- package/cpp/binarypatch/vendor/zstd/decompress/zstd_decompress_internal.h +240 -0
- package/cpp/binarypatch/vendor/zstd/zstd.h +3206 -0
- package/cpp/binarypatch/vendor/zstd/zstd_errors.h +107 -0
- package/ios/CodePush/CodePush.h +58 -9
- package/ios/CodePush/{CodePush.m → CodePush.mm} +77 -63
- package/ios/CodePush/CodePushBinaryPatch.h +80 -0
- package/ios/CodePush/CodePushBinaryPatch.m +473 -0
- package/ios/CodePush/CodePushPackage.m +183 -2
- package/ios/CodePush/CodePushUpdateUtils.m +49 -1
- package/ios/CodePush.xcodeproj/project.pbxproj +6 -6
- package/package.json +28 -4
- package/react-native.config.js +3 -1
- package/scripts/binary-patch/build-hdiffpatch.sh +86 -0
- package/scripts/export-embedded-bundle.sh +76 -0
- package/src/CodePush.js +190 -96
- package/src/CodePush.test.js +382 -0
- package/src/native/NativeCodePush.ts +162 -0
- package/src/package-mixins.js +24 -11
- package/src/specs/NativeCodePush.ts +43 -0
- package/typings/react-native-code-push.d.ts +77 -0
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java +0 -102
- package/src/AlertAdapter.js +0 -24
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#import "CodePush.h"
|
|
2
|
+
#import "CodePushBinaryPatch.h"
|
|
2
3
|
#if __has_include(<SSZipArchive/SSZipArchive.h>)
|
|
3
4
|
#import <SSZipArchive/SSZipArchive.h>
|
|
4
5
|
#else
|
|
@@ -9,8 +10,18 @@
|
|
|
9
10
|
|
|
10
11
|
#pragma mark - Private constants
|
|
11
12
|
|
|
13
|
+
static NSString *const BinaryPatchDownloadUrlKey = @"binaryPatchDownloadUrl";
|
|
14
|
+
static NSString *const BinaryPatchFolderName = @"binary-patch";
|
|
15
|
+
// The fields of what a download that tried a patch reports back with. They are read by the
|
|
16
|
+
// app that asked for the download and by nothing else, so they never reach a file.
|
|
17
|
+
static NSString *const BinaryPatchResultApplyDurationMsKey = @"applyDurationMs";
|
|
18
|
+
static NSString *const BinaryPatchResultFallbackReasonKey = @"fallbackReason";
|
|
19
|
+
static NSString *const BinaryPatchResultStatusKey = @"status";
|
|
20
|
+
static NSString *const BinaryPatchResultStatusApplied = @"applied";
|
|
21
|
+
static NSString *const BinaryPatchResultStatusFallback = @"fallback";
|
|
12
22
|
static NSString *const DiffManifestFileName = @"hotcodepush.json";
|
|
13
23
|
static NSString *const DownloadFileName = @"download.zip";
|
|
24
|
+
static NSString *const DownloadUrlKey = @"downloadUrl";
|
|
14
25
|
static NSString *const RelativeBundlePathKey = @"bundlePath";
|
|
15
26
|
static NSString *const StatusFile = @"codepush.json";
|
|
16
27
|
static NSString *const UpdateBundleFileName = @"app.jsbundle";
|
|
@@ -47,8 +58,136 @@ static NSString *const UnzippedFolderName = @"unzipped";
|
|
|
47
58
|
expectedBundleFileName:(NSString *)expectedBundleFileName
|
|
48
59
|
operationQueue:(dispatch_queue_t)operationQueue
|
|
49
60
|
progressCallback:(void (^)(long long, long long))progressCallback
|
|
50
|
-
doneCallback:(void (^)())doneCallback
|
|
61
|
+
doneCallback:(void (^)(NSDictionary *binaryPatchResult))doneCallback
|
|
51
62
|
failCallback:(void (^)(NSError *err))failCallback
|
|
63
|
+
{
|
|
64
|
+
void (^downloadFullPackage)(NSDictionary *) = ^(NSDictionary *binaryPatchResult) {
|
|
65
|
+
[self downloadAndInstallPackage:updatePackage
|
|
66
|
+
expectedBundleFileName:expectedBundleFileName
|
|
67
|
+
operationQueue:operationQueue
|
|
68
|
+
downloadUrl:updatePackage[DownloadUrlKey]
|
|
69
|
+
isBinaryPatchUpdate:NO
|
|
70
|
+
progressCallback:progressCallback
|
|
71
|
+
doneCallback:^{
|
|
72
|
+
doneCallback(binaryPatchResult);
|
|
73
|
+
}
|
|
74
|
+
failCallback:failCallback
|
|
75
|
+
patchAppliedCallback:nil
|
|
76
|
+
patchFallbackCallback:nil];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// A release that was published with a binary patch offers two archives of the same
|
|
80
|
+
// update. The patch is worth trying because it is a fraction of the size, and the
|
|
81
|
+
// full archive is always there when it does not work out.
|
|
82
|
+
NSString *binaryPatchDownloadUrl = updatePackage[BinaryPatchDownloadUrlKey];
|
|
83
|
+
if (![binaryPatchDownloadUrl isKindOfClass:[NSString class]] || [binaryPatchDownloadUrl length] == 0) {
|
|
84
|
+
// A download that never had a patch to try has nothing to report about one.
|
|
85
|
+
return downloadFullPackage(nil);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Every way the patch can fail ends the same way, with the update being downloaded in
|
|
89
|
+
// full instead, so none of them reaches the caller as an error. The fallback happens
|
|
90
|
+
// exactly once without anything having to count it: the full archive is downloaded by
|
|
91
|
+
// a call that is not allowed to take the patch path, so it has no failure of its own
|
|
92
|
+
// to fall back from.
|
|
93
|
+
NSDate *patchAttemptStartTime = [NSDate date];
|
|
94
|
+
// Set once the applier has restored the bundle, which is also what tells a failure
|
|
95
|
+
// that follows apart from one that came before.
|
|
96
|
+
__block NSNumber *applyDurationMs = nil;
|
|
97
|
+
[self downloadAndInstallPackage:updatePackage
|
|
98
|
+
expectedBundleFileName:expectedBundleFileName
|
|
99
|
+
operationQueue:operationQueue
|
|
100
|
+
downloadUrl:binaryPatchDownloadUrl
|
|
101
|
+
isBinaryPatchUpdate:YES
|
|
102
|
+
progressCallback:progressCallback
|
|
103
|
+
doneCallback:^{
|
|
104
|
+
[self deleteBinaryPatchFolder];
|
|
105
|
+
doneCallback([self appliedBinaryPatchResult:applyDurationMs]);
|
|
106
|
+
}
|
|
107
|
+
failCallback:^(NSError *err) {
|
|
108
|
+
[self deleteBinaryPatchFolder];
|
|
109
|
+
CPLog(@"The binary patch update could not be completed (%@). Downloading the full update instead.", err.localizedDescription);
|
|
110
|
+
// An error raised after the bundle was restored is the restored
|
|
111
|
+
// update failing the checks every update passes before it is
|
|
112
|
+
// installed. Before that point the appliers have no word for what
|
|
113
|
+
// happened - the patch archive not being downloadable, say - and
|
|
114
|
+
// inventing one here would put a value on the wire that no
|
|
115
|
+
// platform reports, so the fallback is reported without a reason.
|
|
116
|
+
NSString *failureReason = applyDurationMs == nil
|
|
117
|
+
? nil
|
|
118
|
+
: CodePushBinaryPatchReasonPackageVerificationFailed;
|
|
119
|
+
downloadFullPackage([self binaryPatchFallbackResult:failureReason
|
|
120
|
+
attemptStartTime:patchAttemptStartTime]);
|
|
121
|
+
}
|
|
122
|
+
patchAppliedCallback:^(double durationMs) {
|
|
123
|
+
applyDurationMs = @(durationMs);
|
|
124
|
+
}
|
|
125
|
+
patchFallbackCallback:^(NSString *failureReason) {
|
|
126
|
+
[self deleteBinaryPatchFolder];
|
|
127
|
+
CPLog(@"Binary patch update failed (%@). Downloading the full update instead.", failureReason);
|
|
128
|
+
downloadFullPackage([self binaryPatchFallbackResult:failureReason
|
|
129
|
+
attemptStartTime:patchAttemptStartTime]);
|
|
130
|
+
}];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* The result of a patch attempt the update was installed from, timed over the apply itself.
|
|
135
|
+
*/
|
|
136
|
+
+ (NSDictionary *)appliedBinaryPatchResult:(NSNumber *)applyDurationMs
|
|
137
|
+
{
|
|
138
|
+
return @{
|
|
139
|
+
BinaryPatchResultStatusKey: BinaryPatchResultStatusApplied,
|
|
140
|
+
BinaryPatchResultApplyDurationMsKey: applyDurationMs ?: @0,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
* The result of a patch attempt the update had to be downloaded in full after.
|
|
146
|
+
*
|
|
147
|
+
* There is no completed apply to time here, so the attempt itself is what is timed: from the
|
|
148
|
+
* patch archive being asked for to the moment the attempt was given up on. The reason is left
|
|
149
|
+
* out when the attempt ended in an error none of the appliers has a word for.
|
|
150
|
+
*/
|
|
151
|
+
+ (NSDictionary *)binaryPatchFallbackResult:(NSString *)failureReason
|
|
152
|
+
attemptStartTime:(NSDate *)attemptStartTime
|
|
153
|
+
{
|
|
154
|
+
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:@{
|
|
155
|
+
BinaryPatchResultStatusKey: BinaryPatchResultStatusFallback,
|
|
156
|
+
BinaryPatchResultApplyDurationMsKey: @(round([[NSDate date] timeIntervalSinceDate:attemptStartTime] * 1000)),
|
|
157
|
+
}];
|
|
158
|
+
if (failureReason) {
|
|
159
|
+
result[BinaryPatchResultFallbackReasonKey] = failureReason;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* Downloads an update from one of its archives and installs it.
|
|
167
|
+
*
|
|
168
|
+
* isBinaryPatchUpdate says whether the archive holds a binary patch of the JS bundle,
|
|
169
|
+
* which has to be applied before the contents are the update. Only an archive downloaded
|
|
170
|
+
* from the binary patch URL is treated that way, so an update being downloaded in full
|
|
171
|
+
* can never end up on the patch path.
|
|
172
|
+
*
|
|
173
|
+
* patchAppliedCallback is called with how long the apply took the moment the bundle has
|
|
174
|
+
* been restored, which is before the update is known to install. It is nil for a full
|
|
175
|
+
* download, which has no patch to apply.
|
|
176
|
+
*
|
|
177
|
+
* patchFallbackCallback is called instead of doneCallback when the patch cannot be
|
|
178
|
+
* applied: the update was not installed, and the caller has to download the full archive.
|
|
179
|
+
* It is nil for a full download, which has nothing to fall back to.
|
|
180
|
+
*/
|
|
181
|
+
+ (void)downloadAndInstallPackage:(NSDictionary *)updatePackage
|
|
182
|
+
expectedBundleFileName:(NSString *)expectedBundleFileName
|
|
183
|
+
operationQueue:(dispatch_queue_t)operationQueue
|
|
184
|
+
downloadUrl:(NSString *)downloadUrl
|
|
185
|
+
isBinaryPatchUpdate:(BOOL)isBinaryPatchUpdate
|
|
186
|
+
progressCallback:(void (^)(long long, long long))progressCallback
|
|
187
|
+
doneCallback:(void (^)(void))doneCallback
|
|
188
|
+
failCallback:(void (^)(NSError *err))failCallback
|
|
189
|
+
patchAppliedCallback:(void (^)(double applyDurationMs))patchAppliedCallback
|
|
190
|
+
patchFallbackCallback:(void (^)(NSString *failureReason))patchFallbackCallback
|
|
52
191
|
{
|
|
53
192
|
NSString *newUpdateHash = updatePackage[@"packageHash"];
|
|
54
193
|
NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash];
|
|
@@ -109,6 +248,24 @@ static NSString *const UnzippedFolderName = @"unzipped";
|
|
|
109
248
|
nonFailingError = nil;
|
|
110
249
|
}
|
|
111
250
|
|
|
251
|
+
// Rebuild the JS bundle the archive only carries a patch of, which leaves the
|
|
252
|
+
// contents identical to the ones the full archive would have delivered.
|
|
253
|
+
if (isBinaryPatchUpdate) {
|
|
254
|
+
NSDate *patchStartTime = [NSDate date];
|
|
255
|
+
NSString *patchFailureReason = nil;
|
|
256
|
+
if (![CodePushBinaryPatch restoreBundleInUnzippedFolder:unzippedFolderPath
|
|
257
|
+
workingFolder:[self getBinaryPatchFolderPath]
|
|
258
|
+
baseBundleURL:[CodePush binaryBundleURL]
|
|
259
|
+
failureReason:&patchFailureReason]) {
|
|
260
|
+
patchFallbackCallback(patchFailureReason);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
double applyDurationMs = round([[NSDate date] timeIntervalSinceDate:patchStartTime] * 1000);
|
|
265
|
+
CPLog(@"Restored the update from its binary patch in %.0f ms.", applyDurationMs);
|
|
266
|
+
patchAppliedCallback(applyDurationMs);
|
|
267
|
+
}
|
|
268
|
+
|
|
112
269
|
NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName];
|
|
113
270
|
BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath];
|
|
114
271
|
|
|
@@ -252,6 +409,15 @@ static NSString *const UnzippedFolderName = @"unzipped";
|
|
|
252
409
|
}
|
|
253
410
|
|
|
254
411
|
} else {
|
|
412
|
+
if (isBinaryPatchUpdate) {
|
|
413
|
+
// Whatever the patch URL served, it is not a patch archive - an error page
|
|
414
|
+
// answered with a 200 looks like this too. Moving it into place would
|
|
415
|
+
// install bytes no hash has ever been checked against, so the full archive
|
|
416
|
+
// is downloaded instead.
|
|
417
|
+
patchFallbackCallback(CodePushBinaryPatchReasonInvalidManifest);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
255
421
|
[[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath
|
|
256
422
|
withIntermediateDirectories:YES
|
|
257
423
|
attributes:nil
|
|
@@ -284,7 +450,22 @@ static NSString *const UnzippedFolderName = @"unzipped";
|
|
|
284
450
|
|
|
285
451
|
failCallback:failCallback];
|
|
286
452
|
|
|
287
|
-
[downloadHandler download:
|
|
453
|
+
[downloadHandler download:downloadUrl];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/*
|
|
457
|
+
* Removes what a patch attempt works in, whichever way the attempt ended - and whatever
|
|
458
|
+
* an attempt that was killed halfway through left there.
|
|
459
|
+
*/
|
|
460
|
+
+ (void)deleteBinaryPatchFolder
|
|
461
|
+
{
|
|
462
|
+
[[NSFileManager defaultManager] removeItemAtPath:[self getBinaryPatchFolderPath]
|
|
463
|
+
error:nil];
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
+ (NSString *)getBinaryPatchFolderPath
|
|
467
|
+
{
|
|
468
|
+
return [[self getCodePushPath] stringByAppendingPathComponent:BinaryPatchFolderName];
|
|
288
469
|
}
|
|
289
470
|
|
|
290
471
|
+ (NSString *)getCodePushPath
|
|
@@ -7,6 +7,9 @@ NSString * const AssetsFolderName = @"assets";
|
|
|
7
7
|
NSString * const BinaryHashKey = @"CodePushBinaryHash";
|
|
8
8
|
NSString * const ManifestFolderPrefix = @"CodePush";
|
|
9
9
|
|
|
10
|
+
/* How much of a file is read at a time while hashing it. */
|
|
11
|
+
static const NSUInteger HashChunkSize = 1024 * 8;
|
|
12
|
+
|
|
10
13
|
/*
|
|
11
14
|
Ignore list for hashing
|
|
12
15
|
*/
|
|
@@ -95,11 +98,56 @@ NSString * const IgnoreDSStore = @".DS_Store";
|
|
|
95
98
|
{
|
|
96
99
|
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
|
|
97
100
|
CC_SHA256(inputData.bytes, (CC_LONG)inputData.length, digest);
|
|
101
|
+
return [self hashStringForDigest:digest];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
A file is hashed a chunk at a time, so that hashing one costs no more memory than the
|
|
106
|
+
chunk however large the file is.
|
|
107
|
+
*/
|
|
108
|
+
+ (NSString *)computeHashForFileAtPath:(NSString *)filePath
|
|
109
|
+
{
|
|
110
|
+
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
|
|
111
|
+
if (!fileHandle) {
|
|
112
|
+
CPLog(@"Unable to open %@ to hash it.", filePath);
|
|
113
|
+
return nil;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
CC_SHA256_CTX context;
|
|
117
|
+
CC_SHA256_Init(&context);
|
|
118
|
+
|
|
119
|
+
while (YES) {
|
|
120
|
+
@autoreleasepool {
|
|
121
|
+
NSError *error = nil;
|
|
122
|
+
NSData *chunk = [fileHandle readDataUpToLength:HashChunkSize error:&error];
|
|
123
|
+
if (!chunk) {
|
|
124
|
+
CPLog(@"Unable to read %@ to hash it: %@", filePath, error);
|
|
125
|
+
[fileHandle closeAndReturnError:nil];
|
|
126
|
+
return nil;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (chunk.length == 0) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
CC_SHA256_Update(&context, chunk.bytes, (CC_LONG)chunk.length);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
[fileHandle closeAndReturnError:nil];
|
|
138
|
+
|
|
139
|
+
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
|
|
140
|
+
CC_SHA256_Final(digest, &context);
|
|
141
|
+
return [self hashStringForDigest:digest];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
+ (NSString *)hashStringForDigest:(const uint8_t *)digest
|
|
145
|
+
{
|
|
98
146
|
NSMutableString* inputHash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
|
|
99
147
|
for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
|
|
100
148
|
[inputHash appendFormat:@"%02x", digest[i]];
|
|
101
149
|
}
|
|
102
|
-
|
|
150
|
+
|
|
103
151
|
return inputHash;
|
|
104
152
|
}
|
|
105
153
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
objects = {
|
|
8
8
|
|
|
9
9
|
/* Begin PBXBuildFile section */
|
|
10
|
-
13BE3DEE1AC21097009241FE /* CodePush.
|
|
10
|
+
13BE3DEE1AC21097009241FE /* CodePush.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.mm */; };
|
|
11
11
|
1B23B9141BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */; };
|
|
12
12
|
1B762E901C9A5E9A006EF800 /* CodePushErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */; };
|
|
13
13
|
1BCC09A71CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */; };
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
5498D8F61D21F14100B5EB43 /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5498D8F51D21F14100B5EB43 /* CodePushUtils.m */; };
|
|
83
83
|
54FFEDE01BF550630061DD23 /* CodePushDownloadHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */; };
|
|
84
84
|
6463C82D1EBA0CFB0095B8CD /* CodePushUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5498D8F51D21F14100B5EB43 /* CodePushUtils.m */; };
|
|
85
|
-
6463C82E1EBA0CFB0095B8CD /* CodePush.
|
|
85
|
+
6463C82E1EBA0CFB0095B8CD /* CodePush.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* CodePush.mm */; };
|
|
86
86
|
6463C82F1EBA0CFB0095B8CD /* CodePushConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 81D51F391B6181C2000DA084 /* CodePushConfig.m */; };
|
|
87
87
|
6463C8301EBA0CFB0095B8CD /* CodePushDownloadHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */; };
|
|
88
88
|
6463C8311EBA0CFB0095B8CD /* CodePushErrorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */; };
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
/* Begin PBXFileReference section */
|
|
126
126
|
134814201AA4EA6300B7C361 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCodePush.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
127
127
|
13BE3DEC1AC21097009241FE /* CodePush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodePush.h; path = CodePush/CodePush.h; sourceTree = "<group>"; };
|
|
128
|
-
13BE3DED1AC21097009241FE /* CodePush.
|
|
128
|
+
13BE3DED1AC21097009241FE /* CodePush.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CodePush.mm; path = CodePush/CodePush.mm; sourceTree = "<group>"; };
|
|
129
129
|
1B23B9131BF9267B000BB2F0 /* RCTConvert+CodePushInstallMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+CodePushInstallMode.m"; path = "CodePush/RCTConvert+CodePushInstallMode.m"; sourceTree = "<group>"; };
|
|
130
130
|
1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CodePushErrorUtils.m; path = CodePush/CodePushErrorUtils.m; sourceTree = "<group>"; };
|
|
131
131
|
1BCC09A61CC19EB700DDC0DD /* RCTConvert+CodePushUpdateState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+CodePushUpdateState.m"; path = "CodePush/RCTConvert+CodePushUpdateState.m"; sourceTree = "<group>"; };
|
|
@@ -277,7 +277,7 @@
|
|
|
277
277
|
FF90DEF92C5A808600CA8692 /* PrivacyInfo.xcprivacy */,
|
|
278
278
|
5498D8F51D21F14100B5EB43 /* CodePushUtils.m */,
|
|
279
279
|
13BE3DEC1AC21097009241FE /* CodePush.h */,
|
|
280
|
-
13BE3DED1AC21097009241FE /* CodePush.
|
|
280
|
+
13BE3DED1AC21097009241FE /* CodePush.mm */,
|
|
281
281
|
81D51F391B6181C2000DA084 /* CodePushConfig.m */,
|
|
282
282
|
54FFEDDF1BF550630061DD23 /* CodePushDownloadHandler.m */,
|
|
283
283
|
1B762E8F1C9A5E9A006EF800 /* CodePushErrorUtils.m */,
|
|
@@ -451,7 +451,7 @@
|
|
|
451
451
|
3221E4912C8ABE1400268379 /* SSZipArchive.m in Sources */,
|
|
452
452
|
5421FE311C58AD5A00986A55 /* CodePushTelemetryManager.m in Sources */,
|
|
453
453
|
3221E46F2C8ABE1300268379 /* mz_strm_wzaes.c in Sources */,
|
|
454
|
-
13BE3DEE1AC21097009241FE /* CodePush.
|
|
454
|
+
13BE3DEE1AC21097009241FE /* CodePush.mm in Sources */,
|
|
455
455
|
3221E45D2C8ABE1300268379 /* mz_zip.c in Sources */,
|
|
456
456
|
1B762E901C9A5E9A006EF800 /* CodePushErrorUtils.m in Sources */,
|
|
457
457
|
3221E4832C8ABE1400268379 /* mz_strm_split.c in Sources */,
|
|
@@ -473,7 +473,7 @@
|
|
|
473
473
|
3221E4822C8ABE1400268379 /* mz_strm_buf.c in Sources */,
|
|
474
474
|
3221E45E2C8ABE1300268379 /* mz_zip.c in Sources */,
|
|
475
475
|
6463C82D1EBA0CFB0095B8CD /* CodePushUtils.m in Sources */,
|
|
476
|
-
6463C82E1EBA0CFB0095B8CD /* CodePush.
|
|
476
|
+
6463C82E1EBA0CFB0095B8CD /* CodePush.mm in Sources */,
|
|
477
477
|
6463C82F1EBA0CFB0095B8CD /* CodePushConfig.m in Sources */,
|
|
478
478
|
6463C8301EBA0CFB0095B8CD /* CodePushDownloadHandler.m in Sources */,
|
|
479
479
|
6463C8311EBA0CFB0095B8CD /* CodePushErrorUtils.m in Sources */,
|
package/package.json
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bravemobile/react-native-code-push",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.1.0-beta.0",
|
|
4
4
|
"description": "React Native plugin for the CodePush service",
|
|
5
5
|
"main": "src/CodePush.js",
|
|
6
6
|
"react-native": "src/CodePush.js",
|
|
7
7
|
"source": "src/CodePush.js",
|
|
8
8
|
"types": "typings/react-native-code-push.d.ts",
|
|
9
|
+
"codegenConfig": {
|
|
10
|
+
"name": "RNCodePushSpec",
|
|
11
|
+
"type": "modules",
|
|
12
|
+
"jsSrcsDir": "src/specs",
|
|
13
|
+
"android": {
|
|
14
|
+
"javaPackageName": "com.microsoft.codepush.react"
|
|
15
|
+
},
|
|
16
|
+
"ios": {
|
|
17
|
+
"modulesProvider": {
|
|
18
|
+
"CodePush": "CodePush"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
9
22
|
"homepage": "https://microsoft.github.io/code-push",
|
|
10
23
|
"keywords": [
|
|
11
24
|
"react-native",
|
|
@@ -29,15 +42,19 @@
|
|
|
29
42
|
"bin/code-push.js",
|
|
30
43
|
"android",
|
|
31
44
|
"ios",
|
|
45
|
+
"cpp",
|
|
32
46
|
"cli/dist",
|
|
33
47
|
"cli/**/*.ts",
|
|
34
48
|
"!cli/node_modules",
|
|
49
|
+
"scripts/export-embedded-bundle.sh",
|
|
50
|
+
"scripts/binary-patch/build-hdiffpatch.sh",
|
|
35
51
|
"expo",
|
|
36
52
|
"typings",
|
|
37
53
|
"*.podspec",
|
|
38
54
|
"react-native.config.js",
|
|
39
55
|
"app.plugin.js",
|
|
40
56
|
"package.json",
|
|
57
|
+
"THIRD-PARTY-NOTICES",
|
|
41
58
|
"!ios/build",
|
|
42
59
|
"!android/build",
|
|
43
60
|
"!android/app/build",
|
|
@@ -45,6 +62,7 @@
|
|
|
45
62
|
"!android/gradlew",
|
|
46
63
|
"!android/gradlew.bat",
|
|
47
64
|
"!android/local.properties",
|
|
65
|
+
"!cpp/binarypatch/host",
|
|
48
66
|
"!**/__tests__",
|
|
49
67
|
"!**/__fixtures__",
|
|
50
68
|
"!**/__mocks__",
|
|
@@ -54,17 +72,20 @@
|
|
|
54
72
|
"setup": "npm install --quiet --no-progress",
|
|
55
73
|
"setup-example-app": "ts-node --project scripts/setupExampleApp/tsconfig.json scripts/setupExampleApp/runSetupExampleApp.ts",
|
|
56
74
|
"setup-expo-example-app": "ts-node --project scripts/setupExampleApp/tsconfig.json scripts/setupExpoExampleApp/runSetupExpoExampleApp.ts",
|
|
75
|
+
"type:src": "tsc --project tsconfig.json --noEmit",
|
|
57
76
|
"type:cli": "npm run --workspace cli typecheck",
|
|
58
77
|
"type:scripts": "tsc --project scripts/tsconfig.json --noEmit",
|
|
59
78
|
"type:e2e": "tsc --project e2e/tsconfig.json --noEmit",
|
|
60
|
-
"typecheck": "npm run type:cli && npm run type:scripts && npm run type:e2e",
|
|
79
|
+
"typecheck": "npm run type:src && npm run type:cli && npm run type:scripts && npm run type:e2e",
|
|
61
80
|
"build:cli": "npm run --workspace cli clean && npm run --workspace cli build",
|
|
62
81
|
"prepack": "npm run build:cli",
|
|
63
|
-
"publish": "npm publish --access=public",
|
|
64
82
|
"eslint": "eslint --quiet .",
|
|
65
|
-
"jest": "jest src/versioning/* expo/* && npm run --workspace cli test",
|
|
83
|
+
"jest": "jest src/CodePush.test.js src/versioning/* expo/* && npm run --workspace cli test",
|
|
66
84
|
"e2e": "ts-node --project e2e/tsconfig.json e2e/run.ts"
|
|
67
85
|
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
},
|
|
68
89
|
"repository": {
|
|
69
90
|
"type": "git",
|
|
70
91
|
"url": "git+https://github.com/Soomgo-Mobile/react-native-code-push.git"
|
|
@@ -94,6 +115,7 @@
|
|
|
94
115
|
"@eslint/js": "^9.13.0",
|
|
95
116
|
"@types/express": "^5.0.6",
|
|
96
117
|
"@types/node": "^18.19.129",
|
|
118
|
+
"@types/react": "19.2.14",
|
|
97
119
|
"@types/semver": "^7.5.8",
|
|
98
120
|
"@types/shelljs": "^0.8.15",
|
|
99
121
|
"@types/yauzl": "^2.10.3",
|
|
@@ -103,6 +125,8 @@
|
|
|
103
125
|
"express": "latest",
|
|
104
126
|
"globals": "^15.11.0",
|
|
105
127
|
"jest": "^29.7.0",
|
|
128
|
+
"react": "19.2.3",
|
|
129
|
+
"react-native": "0.84.1",
|
|
106
130
|
"ts-node": "^10.9.2",
|
|
107
131
|
"typescript": "5.0.4",
|
|
108
132
|
"typescript-eslint": "^8.11.0"
|
package/react-native.config.js
CHANGED
|
@@ -5,7 +5,9 @@ module.exports = {
|
|
|
5
5
|
packageImportPath: "import com.microsoft.codepush.react.CodePush;",
|
|
6
6
|
packageInstance:
|
|
7
7
|
"CodePush.getInstance(getApplicationContext(), BuildConfig.DEBUG)",
|
|
8
|
-
sourceDir: './android/app'
|
|
8
|
+
sourceDir: './android/app',
|
|
9
|
+
libraryName: 'RNCodePushSpec',
|
|
10
|
+
cmakeListsPath: 'build/generated/source/codegen/jni/CMakeLists.txt',
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Builds the `hdiffz` / `hpatchz` command line tools that the CodePush CLI uses to
|
|
4
|
+
# generate and verify binary patches, and installs them into `.hdiffpatch-tools/`
|
|
5
|
+
# (git-ignored) at the repository root.
|
|
6
|
+
#
|
|
7
|
+
# The tools are built from source instead of being vendored as prebuilt binaries so
|
|
8
|
+
# that the exact upstream revision is reproducible on every platform and no opaque
|
|
9
|
+
# executable is committed to the repository.
|
|
10
|
+
#
|
|
11
|
+
# The `make` flags below disable every codec except zstd. That keeps the build to a
|
|
12
|
+
# single extra dependency (sisong/zstd, which must sit next to the HDiffPatch clone)
|
|
13
|
+
# and matches the patch format the appliers support: `hdiffz -f -m-6 -c-zstd-21-24`.
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# scripts/binary-patch/build-hdiffpatch.sh [--force]
|
|
17
|
+
#
|
|
18
|
+
# Environment:
|
|
19
|
+
# HDIFFPATCH_TOOLS_DIR install directory (default: <repo>/.hdiffpatch-tools)
|
|
20
|
+
#
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
HDIFFPATCH_REPO="https://github.com/sisong/HDiffPatch.git"
|
|
24
|
+
HDIFFPATCH_TAG="v5.1.3"
|
|
25
|
+
# sisong/zstd is a fork of facebook/zstd that HDiffPatch's makefile expects as a
|
|
26
|
+
# sibling directory. It publishes no release tags, so it is pinned by commit: an
|
|
27
|
+
# unpinned default branch would silently change the generator on any upstream push,
|
|
28
|
+
# and this SHA is the snapshot the vendored decompressor sources came from.
|
|
29
|
+
ZSTD_REPO="https://github.com/sisong/zstd.git"
|
|
30
|
+
ZSTD_COMMIT="68c88c7c7ad22b5e6882a5296ef96d27dc8750c4"
|
|
31
|
+
|
|
32
|
+
force=0
|
|
33
|
+
for arg in "$@"; do
|
|
34
|
+
case "$arg" in
|
|
35
|
+
--force) force=1 ;;
|
|
36
|
+
*)
|
|
37
|
+
echo "error: unknown argument: $arg" >&2
|
|
38
|
+
echo "usage: $0 [--force]" >&2
|
|
39
|
+
exit 2
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
script_dir=$(cd "$(dirname "$0")" && pwd)
|
|
45
|
+
repo_root=$(cd "$script_dir/../.." && pwd)
|
|
46
|
+
tools_dir="${HDIFFPATCH_TOOLS_DIR:-$repo_root/.hdiffpatch-tools}"
|
|
47
|
+
|
|
48
|
+
if [ "$force" -eq 0 ] && [ -x "$tools_dir/hdiffz" ] && [ -x "$tools_dir/hpatchz" ]; then
|
|
49
|
+
echo "hdiffz/hpatchz already present in $tools_dir (pass --force to rebuild)"
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
for tool in git make cc c++; do
|
|
54
|
+
if ! command -v "$tool" >/dev/null 2>&1; then
|
|
55
|
+
echo "error: '$tool' is required to build hdiffz/hpatchz" >&2
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
|
|
60
|
+
work_dir=$(mktemp -d)
|
|
61
|
+
cleanup() { rm -rf "$work_dir"; }
|
|
62
|
+
trap cleanup EXIT
|
|
63
|
+
|
|
64
|
+
echo "cloning $HDIFFPATCH_REPO @ $HDIFFPATCH_TAG"
|
|
65
|
+
git clone --quiet --depth 1 --branch "$HDIFFPATCH_TAG" "$HDIFFPATCH_REPO" "$work_dir/HDiffPatch"
|
|
66
|
+
echo "cloning $ZSTD_REPO @ $ZSTD_COMMIT"
|
|
67
|
+
# `git clone --branch` does not take a commit, so the pinned commit is fetched into an
|
|
68
|
+
# empty repository instead - still a single-commit download.
|
|
69
|
+
git init --quiet "$work_dir/zstd"
|
|
70
|
+
git -C "$work_dir/zstd" remote add origin "$ZSTD_REPO"
|
|
71
|
+
git -C "$work_dir/zstd" fetch --quiet --depth 1 origin "$ZSTD_COMMIT"
|
|
72
|
+
git -C "$work_dir/zstd" checkout --quiet FETCH_HEAD
|
|
73
|
+
|
|
74
|
+
jobs=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)
|
|
75
|
+
echo "building hdiffz/hpatchz (zstd only, $jobs jobs)"
|
|
76
|
+
make -C "$work_dir/HDiffPatch" \
|
|
77
|
+
BSD=0 LDEF=0 LZMA=0 MD5=0 VCD=0 BZIP2=0 ZLIB=0 ZSTD=1 DIR_DIFF=0 XXH=0 \
|
|
78
|
+
-j"$jobs"
|
|
79
|
+
|
|
80
|
+
mkdir -p "$tools_dir"
|
|
81
|
+
cp "$work_dir/HDiffPatch/hdiffz" "$work_dir/HDiffPatch/hpatchz" "$tools_dir/"
|
|
82
|
+
chmod +x "$tools_dir/hdiffz" "$tools_dir/hpatchz"
|
|
83
|
+
|
|
84
|
+
echo "installed:"
|
|
85
|
+
echo " $tools_dir/hdiffz"
|
|
86
|
+
echo " $tools_dir/hpatchz"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Exports the JS bundle an Xcode build embeds in the app, so a later CodePush release can
|
|
4
|
+
# compute a binary patch against exactly the bytes the store binary ships.
|
|
5
|
+
#
|
|
6
|
+
# Call it at the end of the "Bundle React Native code and images" build phase:
|
|
7
|
+
#
|
|
8
|
+
# "$SRCROOT/../node_modules/@bravemobile/react-native-code-push/scripts/export-embedded-bundle.sh"
|
|
9
|
+
#
|
|
10
|
+
# The bundle and a `binary-patch-base.json` record describing it land in
|
|
11
|
+
# `$BUILD_DIR/codepush/embedded-bundle/$CONFIGURATION-$PLATFORM_NAME/`. Set
|
|
12
|
+
# CODEPUSH_EXPORT_DIR to export somewhere else; the `$CONFIGURATION-$PLATFORM_NAME`
|
|
13
|
+
# directory is appended to it either way, so builds of different configurations never
|
|
14
|
+
# overwrite each other.
|
|
15
|
+
#
|
|
16
|
+
# Builds that embed no bundle - Debug for the simulator, or any build run with
|
|
17
|
+
# SKIP_BUNDLING - have nothing to export, and the script exits without doing anything.
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
if [[ -z "${CONFIGURATION_BUILD_DIR:-}" || -z "${UNLOCALIZED_RESOURCES_FOLDER_PATH:-}" || -z "${BUILD_DIR:-}" || -z "${CONFIGURATION:-}" || -z "${PLATFORM_NAME:-}" ]]; then
|
|
22
|
+
echo "error: export-embedded-bundle.sh must run as an Xcode build phase; the build settings it needs are not set." >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# The name React Native gives the bundle it writes into the app, which BUNDLE_NAME renames.
|
|
27
|
+
embedded_bundle="$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/${BUNDLE_NAME:-main}.jsbundle"
|
|
28
|
+
|
|
29
|
+
if [[ ! -f "$embedded_bundle" ]]; then
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
export_dir="${CODEPUSH_EXPORT_DIR:-$BUILD_DIR/codepush/embedded-bundle}/$CONFIGURATION-$PLATFORM_NAME"
|
|
34
|
+
mkdir -p "$export_dir"
|
|
35
|
+
cp "$embedded_bundle" "$export_dir/"
|
|
36
|
+
|
|
37
|
+
exported_bundle="$export_dir/$(basename "$embedded_bundle")"
|
|
38
|
+
bundle_hash="$(shasum -a 256 "$exported_bundle" | awk '{ print $1 }')"
|
|
39
|
+
|
|
40
|
+
# Read from the built product rather than the source Info.plist, where the versions are
|
|
41
|
+
# still unexpanded build settings.
|
|
42
|
+
binary_version=""
|
|
43
|
+
build_number=""
|
|
44
|
+
info_plist="$CONFIGURATION_BUILD_DIR/${INFOPLIST_PATH:-}"
|
|
45
|
+
if [[ -n "${INFOPLIST_PATH:-}" && -f "$info_plist" ]]; then
|
|
46
|
+
binary_version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$info_plist" 2>/dev/null || true)"
|
|
47
|
+
build_number="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$info_plist" 2>/dev/null || true)"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# A build outside a git checkout still exports a usable record, just without the commit.
|
|
51
|
+
git_sha="$(git -C "${PROJECT_DIR:-$PWD}" rev-parse HEAD 2>/dev/null || true)"
|
|
52
|
+
|
|
53
|
+
# Record name and field names are a contract shared with the CodePush CLI
|
|
54
|
+
# (cli/functions/makeBinaryPatchBundle.ts) and the Android export script
|
|
55
|
+
# (android/codepush-export.gradle). Keep the three in step.
|
|
56
|
+
record_json=""
|
|
57
|
+
|
|
58
|
+
append_field() {
|
|
59
|
+
local name="$1" value="$2"
|
|
60
|
+
if [[ -z "$value" ]]; then
|
|
61
|
+
return 0
|
|
62
|
+
fi
|
|
63
|
+
if [[ -n "$record_json" ]]; then
|
|
64
|
+
record_json+=","$'\n'
|
|
65
|
+
fi
|
|
66
|
+
record_json+=" \"$name\": \"$value\""
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
append_field baseBundleHash "$bundle_hash"
|
|
70
|
+
append_field binaryVersion "$binary_version"
|
|
71
|
+
append_field buildNumber "$build_number"
|
|
72
|
+
append_field gitSha "$git_sha"
|
|
73
|
+
|
|
74
|
+
printf '{\n%s\n}\n' "$record_json" > "$export_dir/binary-patch-base.json"
|
|
75
|
+
|
|
76
|
+
echo "CodePush: exported the embedded bundle to $exported_bundle"
|