@hot-updater/react-native 1.0.7 → 1.1.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/HotUpdater.podspec +14 -2
- package/Package.swift +24 -3
- package/android/build.gradle +2 -6
- package/android/hot-updater-fingerprint.gradle +135 -0
- package/android/src/main/cpp/HotUpdaterRecovery.cpp +291 -21
- package/android/src/main/java/com/hotupdater/ActivityStartGate.kt +176 -15
- package/android/src/main/java/com/hotupdater/ArtifactFileResolver.kt +20 -8
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +145 -31
- package/android/src/main/java/com/hotupdater/CohortService.kt +10 -2
- package/android/src/main/java/com/hotupdater/FileManagerService.kt +3 -1
- package/android/src/main/java/com/hotupdater/HotUpdaterConfig.kt +249 -21
- package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +8 -4
- package/android/src/main/java/com/hotupdater/HotUpdaterHeldContent.kt +92 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +319 -113
- package/android/src/main/java/com/hotupdater/HotUpdaterInstance.kt +87 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterInstanceEnvironment.kt +323 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterMainThread.kt +46 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterProcess.kt +30 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryAttribution.kt +492 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +1541 -159
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoverySlots.kt +137 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +4 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterRuntimeInstance.kt +53 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterUpdateCheck.kt +149 -0
- package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +12 -2
- package/android/src/main/java/com/hotupdater/NativeConfigUtils.kt +5 -6
- package/android/src/main/java/com/hotupdater/NativeUpdateCheck.kt +172 -0
- package/android/src/main/java/com/hotupdater/NativeUpdateChecker.kt +1007 -0
- package/android/src/main/java/com/hotupdater/NativeUpdateEventQueue.kt +111 -0
- package/android/src/main/java/com/hotupdater/OkHttpUpdateCheckTransport.kt +88 -0
- package/android/src/main/java/com/hotupdater/ReleaseCatalog.kt +491 -0
- package/android/src/main/java/com/hotupdater/ReleaseCatalogClient.kt +405 -0
- package/android/src/main/java/com/hotupdater/ReleaseSelection.kt +474 -0
- package/android/src/main/java/com/hotupdater/SignatureVerifier.kt +32 -10
- package/android/src/main/java/com/hotupdater/StrictJson.kt +392 -0
- package/android/src/main/java/com/hotupdater/VersionedPreferencesService.kt +24 -9
- package/android/src/main/java/com/hotupdater/WeakIdentitySet.kt +76 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/BitReader.java +314 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/BrotliError.java +47 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/BrotliInputStream.java +174 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/BrotliRuntimeException.java +21 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Context.java +58 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Decode.java +1574 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Decoder.java +72 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Dictionary.java +103 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/DictionaryData.java +82 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Huffman.java +143 -0
- package/{LICENSE → android/src/main/java/com/hotupdater/vendor/brotli/dec/LICENSE} +6 -20
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/README.md +39 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/State.java +100 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Transform.java +240 -0
- package/android/src/main/java/com/hotupdater/vendor/brotli/dec/Utils.java +163 -0
- package/android/src/main/resources/META-INF/LICENSE-brotli +19 -0
- package/android/src/newarch/HotUpdater.kt +53 -15
- package/android/src/newarch/HotUpdaterModule.kt +42 -17
- package/android/src/newarch/JavaScriptExceptionHooks.kt +45 -8
- package/android/src/oldarch/HotUpdater.kt +51 -12
- package/android/src/oldarch/HotUpdaterModule.kt +43 -17
- package/android/src/oldarch/HotUpdaterSpec.kt +2 -0
- package/android/src/oldarch/JavaScriptExceptionHooks.kt +25 -16
- package/ios/HotUpdater/Interface/HotUpdaterInterface.h +13 -0
- package/ios/HotUpdater/Internal/ArtifactFileResolver.swift +38 -7
- package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +10 -4
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +186 -48
- package/ios/HotUpdater/Internal/CohortService.swift +8 -0
- package/ios/HotUpdater/Internal/HotUpdater.mm +821 -71
- package/ios/HotUpdater/Internal/HotUpdaterAsync.swift +7 -0
- package/ios/HotUpdater/Internal/HotUpdaterConfig.swift +208 -25
- package/ios/HotUpdater/Internal/HotUpdaterFingerprintHash.m +10 -0
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +940 -261
- package/ios/HotUpdater/Internal/HotUpdaterInstanceEnvironment.swift +492 -0
- package/ios/HotUpdater/Internal/HotUpdaterInstanceRouter.swift +83 -0
- package/ios/HotUpdater/Internal/HotUpdaterInterface.swift +28 -1
- package/ios/HotUpdater/Internal/HotUpdaterLaunchRecovery.swift +1553 -0
- package/ios/HotUpdater/Internal/HotUpdaterNativeUpdates.swift +353 -0
- package/ios/HotUpdater/Internal/LaunchPreparationLock.swift +54 -0
- package/ios/HotUpdater/Internal/NativeUpdateCheck.swift +2051 -0
- package/ios/HotUpdater/Internal/ReleaseCatalog.swift +634 -0
- package/ios/HotUpdater/Internal/ReleaseCatalogCacheService.swift +1 -1
- package/ios/HotUpdater/Internal/ReleaseSelection.swift +482 -0
- package/ios/HotUpdater/Internal/SignatureVerifier.swift +27 -10
- package/ios/HotUpdater/Internal/StrictJson.swift +363 -0
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +4 -2
- package/ios/HotUpdater/Internal/UpdateFailure.swift +2 -0
- package/ios/HotUpdater/Package.swift +11 -0
- package/ios/HotUpdater/Public/HotUpdater/HotUpdater.h +4 -0
- package/ios/HotUpdater/Public/HotUpdater.h +21 -2
- package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +66 -0
- package/ios/Plugins/HotUpdaterFingerprintPlugin/HotUpdaterFingerprintPlugin.swift +45 -0
- package/ios/scripts/generate-fingerprint-hash.zsh +85 -0
- package/lib/commonjs/checkForUpdate.js +3 -1
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/index.js +9 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/native.js +24 -79
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/nativeUpdateEvents.js +66 -0
- package/lib/commonjs/nativeUpdateEvents.js.map +1 -0
- package/lib/commonjs/sdkVersion.js +1 -1
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
- package/lib/module/checkForUpdate.js +3 -1
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/index.js +10 -13
- package/lib/module/index.js.map +1 -1
- package/lib/module/native.js +19 -73
- package/lib/module/native.js.map +1 -1
- package/lib/module/nativeUpdateEvents.js +61 -0
- package/lib/module/nativeUpdateEvents.js.map +1 -0
- package/lib/module/sdkVersion.js +1 -1
- package/lib/module/specs/NativeHotUpdater.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -14
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +9 -46
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/nativeUpdateEvents.d.ts +12 -0
- package/lib/typescript/commonjs/nativeUpdateEvents.d.ts.map +1 -0
- package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +19 -3
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -14
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +9 -46
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/nativeUpdateEvents.d.ts +12 -0
- package/lib/typescript/module/nativeUpdateEvents.d.ts.map +1 -0
- package/lib/typescript/module/sdkVersion.d.ts +1 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +19 -3
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/checkForUpdate.ts +7 -1
- package/src/index.ts +9 -17
- package/src/native.ts +19 -91
- package/src/nativeUpdateEvents.ts +77 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +20 -3
- package/android/libs/README.md +0 -50
- package/android/libs/hot-updater-brotli-dec-1.2.0.jar +0 -0
- package/android/src/bridge/BridgeReactInstance.kt +0 -38
- package/android/src/bridgeless/BridgeReactInstance.kt +0 -24
- package/android/src/main/java/com/hotupdater/ReactIntegrationManagerBase.kt +0 -34
- package/android/src/newarch/ReactIntegrationManager.kt +0 -185
- package/android/src/oldarch/ReactIntegrationManager.kt +0 -120
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
Distributed under MIT license.
|
|
4
|
+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
package com.hotupdater.vendor.brotli.dec;
|
|
8
|
+
|
|
9
|
+
import static com.hotupdater.vendor.brotli.dec.BrotliError.BROTLI_ERROR_READ_FAILED;
|
|
10
|
+
import static com.hotupdater.vendor.brotli.dec.BrotliError.BROTLI_OK;
|
|
11
|
+
import static com.hotupdater.vendor.brotli.dec.BrotliError.BROTLI_PANIC;
|
|
12
|
+
|
|
13
|
+
import java.io.ByteArrayInputStream;
|
|
14
|
+
import java.io.IOException;
|
|
15
|
+
import java.io.InputStream;
|
|
16
|
+
import java.io.UnsupportedEncodingException;
|
|
17
|
+
import java.nio.Buffer;
|
|
18
|
+
import java.nio.ByteBuffer;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A set of utility methods.
|
|
22
|
+
*/
|
|
23
|
+
final class Utils {
|
|
24
|
+
|
|
25
|
+
private static final byte[] BYTE_ZEROES = new byte[1024];
|
|
26
|
+
|
|
27
|
+
private static final int[] INT_ZEROES = new int[1024];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Fills byte array with zeroes.
|
|
31
|
+
*
|
|
32
|
+
* <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
|
|
33
|
+
* less than 16.
|
|
34
|
+
*
|
|
35
|
+
* @param dest array to fill with zeroes
|
|
36
|
+
* @param start the first item to fill
|
|
37
|
+
* @param end the last item to fill (exclusive)
|
|
38
|
+
*/
|
|
39
|
+
static void fillBytesWithZeroes(byte[] dest, int start, int end) {
|
|
40
|
+
int cursor = start;
|
|
41
|
+
while (cursor < end) {
|
|
42
|
+
int step = Math.min(cursor + 1024, end) - cursor;
|
|
43
|
+
System.arraycopy(BYTE_ZEROES, 0, dest, cursor, step);
|
|
44
|
+
cursor += step;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Fills int array with zeroes.
|
|
50
|
+
*
|
|
51
|
+
* <p> Current implementation uses {@link System#arraycopy}, so it should be used for length not
|
|
52
|
+
* less than 16.
|
|
53
|
+
*
|
|
54
|
+
* @param dest array to fill with zeroes
|
|
55
|
+
* @param start the first item to fill
|
|
56
|
+
* @param end the last item to fill (exclusive)
|
|
57
|
+
*/
|
|
58
|
+
static void fillIntsWithZeroes(int[] dest, int start, int end) {
|
|
59
|
+
int cursor = start;
|
|
60
|
+
while (cursor < end) {
|
|
61
|
+
int step = Math.min(cursor + 1024, end) - cursor;
|
|
62
|
+
System.arraycopy(INT_ZEROES, 0, dest, cursor, step);
|
|
63
|
+
cursor += step;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static void copyBytes(byte[] dst, int target, byte[] src, int start, int end) {
|
|
68
|
+
System.arraycopy(src, start, dst, target, end - start);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void copyBytesWithin(byte[] bytes, int target, int start, int end) {
|
|
72
|
+
System.arraycopy(bytes, start, bytes, target, end - start);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static int readInput(State s, byte[] dst, int offset, int length) {
|
|
76
|
+
try {
|
|
77
|
+
return s.input.read(dst, offset, length);
|
|
78
|
+
} catch (IOException e) {
|
|
79
|
+
return makeError(s, BROTLI_ERROR_READ_FAILED);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static InputStream makeEmptyInput() {
|
|
84
|
+
return new ByteArrayInputStream(new byte[0]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static void closeInput(State s) throws IOException {
|
|
88
|
+
s.input.close();
|
|
89
|
+
s.input = makeEmptyInput();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static byte[] toUsAsciiBytes(String src) {
|
|
93
|
+
try {
|
|
94
|
+
// NB: String#getBytes(String) is present in JDK 1.1, while other variants require JDK 1.6 and
|
|
95
|
+
// above.
|
|
96
|
+
return src.getBytes("US-ASCII");
|
|
97
|
+
} catch (UnsupportedEncodingException e) {
|
|
98
|
+
throw new RuntimeException(e); // cannot happen
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static int[] toUtf8Runes(String src) {
|
|
103
|
+
int[] result = new int[src.length()];
|
|
104
|
+
for (int i = 0; i < src.length(); i++) {
|
|
105
|
+
result[i] = (int) src.charAt(i);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static ByteBuffer asReadOnlyBuffer(ByteBuffer src) {
|
|
111
|
+
return src.asReadOnlyBuffer();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static int isReadOnly(ByteBuffer src) {
|
|
115
|
+
return src.isReadOnly() ? 1 : 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static int isDirect(ByteBuffer src) {
|
|
119
|
+
return src.isDirect() ? 1 : 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Crazy pills factory: code compiled for JDK8 does not work on JRE9.
|
|
123
|
+
static void flipBuffer(Buffer buffer) {
|
|
124
|
+
buffer.flip();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static int isDebugMode() {
|
|
128
|
+
boolean assertsEnabled = Boolean.parseBoolean(System.getProperty("BROTLI_ENABLE_ASSERTS"));
|
|
129
|
+
return assertsEnabled ? 1 : 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// See BitReader.LOG_BITNESS
|
|
133
|
+
static int getLogBintness() {
|
|
134
|
+
boolean isLongExpensive = Boolean.parseBoolean(System.getProperty("BROTLI_32_BIT_CPU"));
|
|
135
|
+
return isLongExpensive ? 5 : 6;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static int shr32(int x, int y) {
|
|
139
|
+
return x >>> y;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static long shr64(long x, int y) {
|
|
143
|
+
return x >>> y;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static int min(int a, int b) {
|
|
147
|
+
return Math.min(a, b);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static int makeError(State s, int code) {
|
|
151
|
+
if (code >= BROTLI_OK) {
|
|
152
|
+
return code;
|
|
153
|
+
}
|
|
154
|
+
if (s.runningState >= 0) {
|
|
155
|
+
s.runningState = code; // Only the first error is remembered.
|
|
156
|
+
}
|
|
157
|
+
// TODO(eustas): expand codes to messages, if ever necessary.
|
|
158
|
+
if (code <= BROTLI_PANIC) {
|
|
159
|
+
throw new IllegalStateException("Brotli error code: " + code);
|
|
160
|
+
}
|
|
161
|
+
throw new BrotliRuntimeException("Error code: " + code);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.hotupdater
|
|
2
2
|
|
|
3
|
+
import android.app.Activity
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import com.facebook.react.ReactHost
|
|
5
6
|
|
|
@@ -20,7 +21,9 @@ class HotUpdater {
|
|
|
20
21
|
*/
|
|
21
22
|
fun getInstance(context: Context): HotUpdaterImpl =
|
|
22
23
|
instance ?: synchronized(this) {
|
|
23
|
-
|
|
24
|
+
// Built from one snapshot of main's values, which options and
|
|
25
|
+
// HotUpdater.configure can no longer change.
|
|
26
|
+
instance ?: MainInstanceConfiguration.shared.createImpl(context.applicationContext).also {
|
|
24
27
|
instance = it
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -62,14 +65,6 @@ class HotUpdater {
|
|
|
62
65
|
)
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
/**
|
|
66
|
-
* Reloads the React Native application using the default singleton instance
|
|
67
|
-
* @param context Context (preferably ReactApplicationContext)
|
|
68
|
-
*/
|
|
69
|
-
suspend fun reload(context: Context) {
|
|
70
|
-
getInstance(context).reload(context)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
/**
|
|
74
69
|
* Gets the app version - delegates to HotUpdaterImpl static method
|
|
75
70
|
* @param context Application context
|
|
@@ -98,9 +93,22 @@ class HotUpdater {
|
|
|
98
93
|
fun getChannel(context: Context): String = HotUpdaterImpl.getChannel(context)
|
|
99
94
|
|
|
100
95
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
96
|
+
* Main's configuration, which [HotUpdaterOptions] of [init] now set.
|
|
97
|
+
* Each call replaces all four values; a null argument means no
|
|
98
|
+
* override. [isolationKey] replaces main's storage key verbatim.
|
|
99
|
+
* Main's native state reads the values once, when it is created, so a
|
|
100
|
+
* later call no longer changes it. Named instances never read them.
|
|
103
101
|
*/
|
|
102
|
+
@Deprecated(
|
|
103
|
+
"Pass channel, fingerprintHash, and publicKey to HotUpdaterOptions. " +
|
|
104
|
+
"Fingerprint downloads now survive native releases that ship the same artifact.",
|
|
105
|
+
ReplaceWith(
|
|
106
|
+
"HotUpdater.init(context, HotUpdaterOptions(baseURL, channel = channel, " +
|
|
107
|
+
"fingerprintHash = fingerprintHash, publicKey = publicKey))",
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
@JvmStatic
|
|
111
|
+
@Suppress("DEPRECATION")
|
|
104
112
|
fun configure(
|
|
105
113
|
fingerprintHash: String? = null,
|
|
106
114
|
publicKey: String? = null,
|
|
@@ -116,9 +124,8 @@ class HotUpdater {
|
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* When set, reload() will use this ReactHost instead of accessing Application.
|
|
127
|
+
* Registers the ReactHost a brownfield app runs without a ReactApplication
|
|
128
|
+
* (New Architecture).
|
|
122
129
|
* @param reactHost The ReactHost instance
|
|
123
130
|
*/
|
|
124
131
|
fun setReactHost(reactHost: ReactHost) {
|
|
@@ -132,6 +139,37 @@ class HotUpdater {
|
|
|
132
139
|
ReactHostHolder.clear()
|
|
133
140
|
}
|
|
134
141
|
|
|
135
|
-
|
|
142
|
+
/**
|
|
143
|
+
* The native counterpart of JavaScript's `HotUpdater.init`: an
|
|
144
|
+
* instance with this server and these request defaults, for checking
|
|
145
|
+
* for and staging updates before React Native starts.
|
|
146
|
+
* @throws IllegalArgumentException when [HotUpdaterOptions.baseURL] is
|
|
147
|
+
* not an absolute HTTP(S) URL, as `HotUpdater.init` throws, when
|
|
148
|
+
* [HotUpdaterOptions.name] is not 1 to 32 lowercase letters, digits, or
|
|
149
|
+
* hyphens, or when the name was already created with another channel,
|
|
150
|
+
* fingerprint hash, public key, or bundle asset name. `main` refuses
|
|
151
|
+
* a bundle asset name other than `index.android.bundle`, and a
|
|
152
|
+
* channel, fingerprint hash, or public key other than the one an
|
|
153
|
+
* earlier `init` or `HotUpdater.configure` set or, once its native
|
|
154
|
+
* state was first read, the one it uses
|
|
155
|
+
*/
|
|
156
|
+
@JvmStatic
|
|
157
|
+
fun init(
|
|
158
|
+
context: Context,
|
|
159
|
+
options: HotUpdaterOptions,
|
|
160
|
+
): HotUpdaterInstance {
|
|
161
|
+
requireValidBaseURL(options.baseURL)
|
|
162
|
+
// An activity started before this process followed activities is
|
|
163
|
+
// known only from the context the app hands over.
|
|
164
|
+
(context as? Activity)?.let(HotUpdaterRecoveryAttribution.shared::noteActivity)
|
|
165
|
+
return HotUpdaterInstance.create(context.applicationContext, options)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Clears the runtime channel switch once other native update work
|
|
170
|
+
* finishes, as [HotUpdaterInstance.resetChannel] does.
|
|
171
|
+
*/
|
|
172
|
+
suspend fun resetChannel(context: Context): Boolean =
|
|
173
|
+
NativeUpdateCheck.resetChannel(context.applicationContext) { getInstance(context) }
|
|
136
174
|
}
|
|
137
175
|
}
|
|
@@ -36,16 +36,39 @@ class HotUpdaterModule internal constructor(
|
|
|
36
36
|
return value.toLong().takeIf { it in 0..9_007_199_254_740_991L }
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
override fun initialize() {
|
|
40
|
+
super.initialize()
|
|
41
|
+
// Each runtime has its own module, so this reaches a named instance's
|
|
42
|
+
// runtime, whose host the app doesn't expose, and main's, whose root
|
|
43
|
+
// views are looked for too; main's errors are left alone.
|
|
44
|
+
registeredInstanceName = HotUpdaterRecoveryManager.registerRuntime(mReactApplicationContext)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The named instance whose runtime this module registered; the runtime,
|
|
48
|
+
// whichever instance's, is unregistered when it is torn down.
|
|
49
|
+
private var registeredInstanceName: String? = null
|
|
50
|
+
|
|
51
|
+
private fun unregisterRuntime() {
|
|
52
|
+
HotUpdaterRecoveryManager.unregisterRuntime(mReactApplicationContext, registeredInstanceName)
|
|
53
|
+
registeredInstanceName = null
|
|
54
|
+
}
|
|
55
|
+
|
|
39
56
|
override fun invalidate() {
|
|
40
57
|
super.invalidate()
|
|
58
|
+
unregisterRuntime()
|
|
41
59
|
// Cancel all ongoing coroutines when module is destroyed
|
|
42
60
|
moduleScope.cancel()
|
|
43
61
|
}
|
|
44
62
|
|
|
63
|
+
// The instance whose bundle this module's runtime runs, read from the
|
|
64
|
+
// URL React Native loaded it from.
|
|
65
|
+
private val runtimeInstance = HotUpdaterRuntimeInstance(mReactApplicationContext, { mReactApplicationContext.sourceURL })
|
|
66
|
+
|
|
45
67
|
/**
|
|
46
|
-
*
|
|
68
|
+
* The impl of this runtime's instance: main's, or a named instance's
|
|
69
|
+
* when the runtime runs its bundle
|
|
47
70
|
*/
|
|
48
|
-
private fun getInstance(): HotUpdaterImpl =
|
|
71
|
+
private fun getInstance(): HotUpdaterImpl = runtimeInstance.impl
|
|
49
72
|
|
|
50
73
|
/**
|
|
51
74
|
* Every changed file with its hash and URL or Hermes patch; with
|
|
@@ -210,7 +233,14 @@ class HotUpdaterModule internal constructor(
|
|
|
210
233
|
)
|
|
211
234
|
}
|
|
212
235
|
|
|
236
|
+
// Legacy: released JavaScript calls reload() on Android when the app chose
|
|
237
|
+
// setReloadBehavior("reload"). The in-place React Native reload is gone, so
|
|
238
|
+
// reload() restarts the process, and reloadProcess() runs the same code.
|
|
213
239
|
override fun reload(promise: Promise) {
|
|
240
|
+
runtimeInstance.reloadUnsupportedReason()?.let { reason ->
|
|
241
|
+
promise.reject(RELOAD_UNSUPPORTED_CODE, reason)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
214
244
|
moduleScope.launch {
|
|
215
245
|
try {
|
|
216
246
|
val impl = getInstance()
|
|
@@ -223,18 +253,9 @@ class HotUpdaterModule internal constructor(
|
|
|
223
253
|
}
|
|
224
254
|
}
|
|
225
255
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
val impl = getInstance()
|
|
230
|
-
impl.reloadProcess(mReactApplicationContext)
|
|
231
|
-
promise.resolve(null)
|
|
232
|
-
} catch (e: Exception) {
|
|
233
|
-
Log.d("HotUpdater", "Failed to restart process", e)
|
|
234
|
-
promise.reject("reloadProcess", e)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
256
|
+
// Deprecated: JavaScript calls reloadProcess() on Android, both released
|
|
257
|
+
// JavaScript and this SDK's, so it stays until the next major release.
|
|
258
|
+
override fun reloadProcess(promise: Promise) = reload(promise)
|
|
238
259
|
|
|
239
260
|
override fun updateBundle(
|
|
240
261
|
params: ReadableMap,
|
|
@@ -466,7 +487,7 @@ class HotUpdaterModule internal constructor(
|
|
|
466
487
|
constants["APP_VERSION"] = HotUpdater.getAppVersion(mReactApplicationContext)
|
|
467
488
|
constants["CHANNEL"] = getInstance().getChannel()
|
|
468
489
|
constants["DEFAULT_CHANNEL"] = getInstance().getDefaultChannel()
|
|
469
|
-
constants["FINGERPRINT_HASH"] =
|
|
490
|
+
constants["FINGERPRINT_HASH"] = getInstance().getFingerprintHash()
|
|
470
491
|
return constants
|
|
471
492
|
}
|
|
472
493
|
|
|
@@ -520,11 +541,15 @@ class HotUpdaterModule internal constructor(
|
|
|
520
541
|
getInstance().setStorageItem(key, value)
|
|
521
542
|
}
|
|
522
543
|
|
|
544
|
+
override fun takeNativeUpdateEvents(): String? = getInstance().takeNativeUpdateEvents()
|
|
545
|
+
|
|
523
546
|
override fun resetChannel(promise: Promise) {
|
|
524
547
|
moduleScope.launch {
|
|
525
548
|
try {
|
|
526
|
-
|
|
527
|
-
|
|
549
|
+
// Waits for a native check or download, which would save its
|
|
550
|
+
// channel again after the reset.
|
|
551
|
+
val name = runtimeInstance.name
|
|
552
|
+
val success = NativeUpdateCheck.resetChannel(mReactApplicationContext, name) { runtimeInstance.impl(name) }
|
|
528
553
|
promise.resolve(success)
|
|
529
554
|
} catch (e: HotUpdaterException) {
|
|
530
555
|
promise.reject(e.code, e.message)
|
|
@@ -1,16 +1,47 @@
|
|
|
1
1
|
package com.hotupdater
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
3
4
|
import com.facebook.react.ReactApplication
|
|
5
|
+
import com.facebook.react.ReactHost
|
|
6
|
+
import com.facebook.react.bridge.ReactContext
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* Routes JavaScript errors of the running React instance to crash recovery.
|
|
7
|
-
* The New Architecture reaches the instance through ReactHost
|
|
10
|
+
* The New Architecture reaches the instance through ReactHost: the one a
|
|
11
|
+
* brownfield app passes to `HotUpdater.setReactHost`, the application's, or
|
|
12
|
+
* the host of a runtime whose HotUpdater module was created. An error belongs
|
|
13
|
+
* to the instance whose bundle the host's runtime runs.
|
|
8
14
|
*/
|
|
9
15
|
internal object JavaScriptExceptionHooks {
|
|
10
|
-
private val
|
|
16
|
+
private val patchedReactHostDelegates = WeakIdentitySet<Any>()
|
|
11
17
|
|
|
12
|
-
fun install(
|
|
13
|
-
val reactHost =
|
|
18
|
+
fun install(appContext: Context) {
|
|
19
|
+
val reactHost =
|
|
20
|
+
ReactHostHolder.getReactHost()
|
|
21
|
+
?: (appContext as? ReactApplication)?.reactHost
|
|
22
|
+
?: return
|
|
23
|
+
patchReactHost(reactHost)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Hooks the host of [reactContext]'s runtime. Without a bridge, a fatal
|
|
28
|
+
* error reaches only the host's delegate, and the host of a named
|
|
29
|
+
* instance's runtime is reached only through its context.
|
|
30
|
+
*/
|
|
31
|
+
fun installForRuntime(reactContext: ReactContext) {
|
|
32
|
+
HotUpdaterRecoveryManager.patchReactContextExceptionHandler(reactContext)
|
|
33
|
+
// BridgelessReactContext's host: `mReactHost` before React Native 0.80's Kotlin rewrite.
|
|
34
|
+
val reactHost =
|
|
35
|
+
listOf("reactHost", "mReactHost")
|
|
36
|
+
.firstNotNullOfOrNull { name -> HotUpdaterRecoveryManager.findField(reactContext.javaClass, name) }
|
|
37
|
+
?.let { field ->
|
|
38
|
+
field.isAccessible = true
|
|
39
|
+
field.get(reactContext)
|
|
40
|
+
} as? ReactHost ?: return
|
|
41
|
+
patchReactHost(reactHost)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private fun patchReactHost(reactHost: ReactHost) {
|
|
14
45
|
val reactHostDelegate =
|
|
15
46
|
HotUpdaterRecoveryManager.findField(reactHost.javaClass, "mReactHostDelegate")?.let { field ->
|
|
16
47
|
field.isAccessible = true
|
|
@@ -22,12 +53,12 @@ internal object JavaScriptExceptionHooks {
|
|
|
22
53
|
}
|
|
23
54
|
?: return
|
|
24
55
|
|
|
25
|
-
val
|
|
26
|
-
if (
|
|
56
|
+
val patches = patchedReactHostDelegates.add(reactHostDelegate)
|
|
57
|
+
if (patches) {
|
|
27
58
|
val exceptionHandlerField =
|
|
28
59
|
HotUpdaterRecoveryManager.findField(reactHostDelegate.javaClass, "exceptionHandler")
|
|
29
60
|
if (exceptionHandlerField == null) {
|
|
30
|
-
|
|
61
|
+
patchedReactHostDelegates.remove(reactHostDelegate)
|
|
31
62
|
return
|
|
32
63
|
}
|
|
33
64
|
|
|
@@ -37,8 +68,14 @@ internal object JavaScriptExceptionHooks {
|
|
|
37
68
|
exceptionHandlerField.get(reactHostDelegate) as? (Exception) -> Unit
|
|
38
69
|
|
|
39
70
|
exceptionHandlerField.set(reactHostDelegate) { exception: Exception ->
|
|
40
|
-
|
|
71
|
+
// The host still holds the runtime that failed: it tears it down after the delegate.
|
|
72
|
+
val runtime = runCatching { reactHost.currentReactContext }.getOrNull()
|
|
73
|
+
val sourceURL = runCatching { runtime?.sourceURL }.getOrNull()
|
|
74
|
+
val outcome = HotUpdaterRecoveryManager.handleJavaScriptError(exception, sourceURL, runtime)
|
|
75
|
+
if (!outcome.recovered) {
|
|
41
76
|
previousHandler?.invoke(exception) ?: throw exception
|
|
77
|
+
// The handler returned: the error did not end the process.
|
|
78
|
+
HotUpdaterRecoveryManager.handlerReturned(outcome)
|
|
42
79
|
}
|
|
43
80
|
}
|
|
44
81
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.hotupdater
|
|
2
2
|
|
|
3
|
+
import android.app.Activity
|
|
3
4
|
import android.content.Context
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -19,7 +20,9 @@ class HotUpdater {
|
|
|
19
20
|
*/
|
|
20
21
|
fun getInstance(context: Context): HotUpdaterImpl =
|
|
21
22
|
instance ?: synchronized(this) {
|
|
22
|
-
|
|
23
|
+
// Built from one snapshot of main's values, which options and
|
|
24
|
+
// HotUpdater.configure can no longer change.
|
|
25
|
+
instance ?: MainInstanceConfiguration.shared.createImpl(context.applicationContext).also {
|
|
23
26
|
instance = it
|
|
24
27
|
}
|
|
25
28
|
}
|
|
@@ -61,14 +64,6 @@ class HotUpdater {
|
|
|
61
64
|
)
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
/**
|
|
65
|
-
* Reloads the React Native application using the default singleton instance
|
|
66
|
-
* @param context Context (preferably ReactApplicationContext)
|
|
67
|
-
*/
|
|
68
|
-
suspend fun reload(context: Context) {
|
|
69
|
-
getInstance(context).reload(context)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
67
|
/**
|
|
73
68
|
* Gets the app version - delegates to HotUpdaterImpl static method
|
|
74
69
|
* @param context Application context
|
|
@@ -97,9 +92,22 @@ class HotUpdater {
|
|
|
97
92
|
fun getChannel(context: Context): String = HotUpdaterImpl.getChannel(context)
|
|
98
93
|
|
|
99
94
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
95
|
+
* Main's configuration, which [HotUpdaterOptions] of [init] now set.
|
|
96
|
+
* Each call replaces all four values; a null argument means no
|
|
97
|
+
* override. [isolationKey] replaces main's storage key verbatim.
|
|
98
|
+
* Main's native state reads the values once, when it is created, so a
|
|
99
|
+
* later call no longer changes it. Named instances never read them.
|
|
102
100
|
*/
|
|
101
|
+
@Deprecated(
|
|
102
|
+
"Pass channel, fingerprintHash, and publicKey to HotUpdaterOptions. " +
|
|
103
|
+
"Fingerprint downloads now survive native releases that ship the same artifact.",
|
|
104
|
+
ReplaceWith(
|
|
105
|
+
"HotUpdater.init(context, HotUpdaterOptions(baseURL, channel = channel, " +
|
|
106
|
+
"fingerprintHash = fingerprintHash, publicKey = publicKey))",
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
@JvmStatic
|
|
110
|
+
@Suppress("DEPRECATION")
|
|
103
111
|
fun configure(
|
|
104
112
|
fingerprintHash: String? = null,
|
|
105
113
|
publicKey: String? = null,
|
|
@@ -130,6 +138,37 @@ class HotUpdater {
|
|
|
130
138
|
// No-op for old architecture
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
|
|
141
|
+
/**
|
|
142
|
+
* The native counterpart of JavaScript's `HotUpdater.init`: an
|
|
143
|
+
* instance with this server and these request defaults, for checking
|
|
144
|
+
* for and staging updates before React Native starts.
|
|
145
|
+
* @throws IllegalArgumentException when [HotUpdaterOptions.baseURL] is
|
|
146
|
+
* not an absolute HTTP(S) URL, as `HotUpdater.init` throws, when
|
|
147
|
+
* [HotUpdaterOptions.name] is not 1 to 32 lowercase letters, digits, or
|
|
148
|
+
* hyphens, or when the name was already created with another channel,
|
|
149
|
+
* fingerprint hash, public key, or bundle asset name. `main` refuses
|
|
150
|
+
* a bundle asset name other than `index.android.bundle`, and a
|
|
151
|
+
* channel, fingerprint hash, or public key other than the one an
|
|
152
|
+
* earlier `init` or `HotUpdater.configure` set or, once its native
|
|
153
|
+
* state was first read, the one it uses
|
|
154
|
+
*/
|
|
155
|
+
@JvmStatic
|
|
156
|
+
fun init(
|
|
157
|
+
context: Context,
|
|
158
|
+
options: HotUpdaterOptions,
|
|
159
|
+
): HotUpdaterInstance {
|
|
160
|
+
requireValidBaseURL(options.baseURL)
|
|
161
|
+
// An activity started before this process followed activities is
|
|
162
|
+
// known only from the context the app hands over.
|
|
163
|
+
(context as? Activity)?.let(HotUpdaterRecoveryAttribution.shared::noteActivity)
|
|
164
|
+
return HotUpdaterInstance.create(context.applicationContext, options)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Clears the runtime channel switch once other native update work
|
|
169
|
+
* finishes, as [HotUpdaterInstance.resetChannel] does.
|
|
170
|
+
*/
|
|
171
|
+
suspend fun resetChannel(context: Context): Boolean =
|
|
172
|
+
NativeUpdateCheck.resetChannel(context.applicationContext) { getInstance(context) }
|
|
134
173
|
}
|
|
135
174
|
}
|