@hot-updater/react-native 0.16.7-0 → 0.18.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 +7 -11
- package/android/{generated/java/com/hotupdater → app/build/generated/source/codegen/java/com/facebook/fbreact/specs}/NativeHotUpdaterSpec.java +3 -2
- package/android/app/build/generated/source/codegen/jni/HotUpdater-generated.cpp +68 -0
- package/android/app/build/generated/source/codegen/jni/HotUpdater.h +31 -0
- package/android/{generated → app/build/generated/source/codegen}/jni/HotUpdaterSpec-generated.cpp +2 -2
- package/android/{generated/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI-generated.cpp → app/build/generated/source/codegen/jni/react/renderer/components/HotUpdater/HotUpdaterJSI-generated.cpp} +3 -4
- package/{ios/generated/HotUpdaterSpecJSI.h → android/app/build/generated/source/codegen/jni/react/renderer/components/HotUpdater/HotUpdaterJSI.h} +53 -6
- package/{ios/generated → android/app/build/generated/source/codegen/jni/react/renderer/components/HotUpdaterSpec}/HotUpdaterSpecJSI-generated.cpp +2 -3
- package/android/{generated → app/build/generated/source/codegen}/jni/react/renderer/components/HotUpdaterSpec/HotUpdaterSpecJSI.h +59 -8
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +200 -0
- package/android/src/main/java/com/hotupdater/FileManagerService.kt +104 -0
- package/android/src/main/java/com/hotupdater/HotUpdater.kt +62 -305
- package/android/src/main/java/com/hotupdater/HotUpdaterFactory.kt +49 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +176 -0
- package/android/src/main/java/com/hotupdater/HttpDownloadService.kt +98 -0
- package/android/src/main/java/com/hotupdater/VersionedPreferencesService.kt +69 -0
- package/android/src/main/java/com/hotupdater/ZipFileUnzipService.kt +52 -0
- package/android/src/newarch/HotUpdaterModule.kt +31 -34
- package/android/src/newarch/ReactIntegrationManager.kt +17 -3
- package/android/src/oldarch/HotUpdaterModule.kt +32 -34
- package/android/src/oldarch/HotUpdaterSpec.kt +2 -9
- package/android/src/oldarch/ReactIntegrationManager.kt +0 -2
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +593 -0
- package/ios/HotUpdater/Internal/FileManagerService.swift +97 -0
- package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +8 -0
- package/ios/HotUpdater/Internal/HotUpdater.mm +241 -0
- package/ios/HotUpdater/Internal/HotUpdaterFactory.swift +24 -0
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +143 -0
- package/ios/HotUpdater/Internal/NotificationExtension.swift +6 -0
- package/ios/HotUpdater/Internal/SSZipArchiveUnzipService.swift +25 -0
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +101 -0
- package/ios/HotUpdater/Internal/VersionedPreferencesService.swift +82 -0
- package/ios/HotUpdater/Package.resolved +15 -0
- package/ios/HotUpdater/Public/HotUpdater.h +29 -0
- package/lib/commonjs/checkForUpdate.js +70 -0
- package/lib/commonjs/checkForUpdate.js.map +1 -0
- package/lib/commonjs/error.js +14 -0
- package/lib/commonjs/error.js.map +1 -0
- package/lib/commonjs/fetchUpdateInfo.js +74 -0
- package/lib/commonjs/fetchUpdateInfo.js.map +1 -0
- package/lib/commonjs/hooks/useEventCallback.js +17 -0
- package/lib/commonjs/hooks/useEventCallback.js.map +1 -0
- package/lib/commonjs/index.js +234 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native.js +132 -0
- package/lib/commonjs/native.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/runUpdateProcess.js +69 -0
- package/lib/commonjs/runUpdateProcess.js.map +1 -0
- package/lib/commonjs/specs/NativeHotUpdater.js +9 -0
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -0
- package/lib/commonjs/store.js +48 -0
- package/lib/commonjs/store.js.map +1 -0
- package/lib/commonjs/wrap.js +98 -0
- package/lib/commonjs/wrap.js.map +1 -0
- package/lib/module/checkForUpdate.js +64 -0
- package/lib/module/checkForUpdate.js.map +1 -0
- package/lib/module/error.js +9 -0
- package/lib/module/error.js.map +1 -0
- package/lib/module/fetchUpdateInfo.js +69 -0
- package/lib/module/fetchUpdateInfo.js.map +1 -0
- package/lib/module/hooks/useEventCallback.js +13 -0
- package/lib/module/hooks/useEventCallback.js.map +1 -0
- package/lib/module/index.js +211 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native.js +119 -0
- package/lib/module/native.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/runUpdateProcess.js +64 -0
- package/lib/module/runUpdateProcess.js.map +1 -0
- package/lib/module/specs/NativeHotUpdater.js +5 -0
- package/lib/module/specs/NativeHotUpdater.js.map +1 -0
- package/lib/module/store.js +42 -0
- package/lib/module/store.js.map +1 -0
- package/lib/module/wrap.js +94 -0
- package/lib/module/wrap.js.map +1 -0
- package/lib/typescript/commonjs/checkForUpdate.d.ts +22 -0
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/error.d.ts +1 -0
- package/lib/typescript/commonjs/error.d.ts.map +1 -0
- package/lib/typescript/commonjs/fetchUpdateInfo.d.ts +4 -0
- package/lib/typescript/commonjs/fetchUpdateInfo.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/hooks/useEventCallback.d.ts +1 -0
- package/lib/typescript/commonjs/hooks/useEventCallback.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/index.d.ts +38 -12
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/native.d.ts +64 -0
- package/lib/typescript/commonjs/native.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/{dist → lib/typescript/commonjs}/runUpdateProcess.d.ts +1 -0
- package/lib/typescript/commonjs/runUpdateProcess.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/specs/NativeHotUpdater.d.ts +8 -9
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/store.d.ts +1 -0
- package/lib/typescript/commonjs/store.d.ts.map +1 -0
- package/{dist → lib/typescript/commonjs}/wrap.d.ts +3 -2
- package/lib/typescript/commonjs/wrap.d.ts.map +1 -0
- package/lib/typescript/module/checkForUpdate.d.ts +22 -0
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -0
- package/lib/typescript/module/error.d.ts +4 -0
- package/lib/typescript/module/error.d.ts.map +1 -0
- package/lib/typescript/module/fetchUpdateInfo.d.ts +4 -0
- package/lib/typescript/module/fetchUpdateInfo.d.ts.map +1 -0
- package/lib/typescript/module/hooks/useEventCallback.d.ts +5 -0
- package/lib/typescript/module/hooks/useEventCallback.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +202 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/native.d.ts +64 -0
- package/lib/typescript/module/native.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/runUpdateProcess.d.ts +49 -0
- package/lib/typescript/module/runUpdateProcess.d.ts.map +1 -0
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +19 -0
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -0
- package/lib/typescript/module/store.d.ts +11 -0
- package/lib/typescript/module/store.d.ts.map +1 -0
- package/lib/typescript/module/wrap.d.ts +51 -0
- package/lib/typescript/module/wrap.d.ts.map +1 -0
- package/package.json +59 -30
- package/src/checkForUpdate.ts +59 -9
- package/src/fetchUpdateInfo.ts +40 -12
- package/src/index.ts +37 -11
- package/src/native.ts +87 -41
- package/src/runUpdateProcess.ts +2 -2
- package/src/specs/NativeHotUpdater.ts +8 -10
- package/src/wrap.tsx +9 -13
- package/android/src/main/java/com/hotupdater/HotUpdaterPrefs.kt +0 -42
- package/dist/checkForUpdate.d.ts +0 -12
- package/dist/fetchUpdateInfo.d.ts +0 -3
- package/dist/index.js +0 -341
- package/dist/index.mjs +0 -301
- package/dist/native.d.ts +0 -41
- package/ios/HotUpdater/HotUpdater.h +0 -15
- package/ios/HotUpdater/HotUpdater.mm +0 -468
- package/ios/HotUpdater/HotUpdater.modulemap +0 -6
- package/ios/HotUpdater/HotUpdaterPrefs.h +0 -9
- package/ios/HotUpdater/HotUpdaterPrefs.mm +0 -45
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec-generated.mm +0 -81
- package/ios/generated/HotUpdaterSpec/HotUpdaterSpec.h +0 -112
- package/react-native.config.js +0 -12
- package/src/global.d.ts +0 -3
- /package/android/{generated → app/build/generated/source/codegen}/jni/CMakeLists.txt +0 -0
- /package/android/{generated → app/build/generated/source/codegen}/jni/HotUpdaterSpec.h +0 -0
package/src/checkForUpdate.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import type { AppUpdateInfo, GetBundlesArgs } from "@hot-updater/core";
|
|
1
2
|
import { Platform } from "react-native";
|
|
2
3
|
import { HotUpdaterError } from "./error";
|
|
3
4
|
import { type UpdateSource, fetchUpdateInfo } from "./fetchUpdateInfo";
|
|
4
5
|
import {
|
|
6
|
+
HotUpdaterConstants,
|
|
5
7
|
getAppVersion,
|
|
6
8
|
getBundleId,
|
|
7
9
|
getChannel,
|
|
8
10
|
getMinBundleId,
|
|
11
|
+
updateBundle,
|
|
9
12
|
} from "./native";
|
|
10
13
|
|
|
11
14
|
export interface CheckForUpdateOptions {
|
|
@@ -19,7 +22,17 @@ export interface CheckForUpdateOptions {
|
|
|
19
22
|
requestTimeout?: number;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
export
|
|
25
|
+
export type CheckForUpdateResult = AppUpdateInfo & {
|
|
26
|
+
/**
|
|
27
|
+
* Updates the bundle.
|
|
28
|
+
* This method is equivalent to `HotUpdater.updateBundle()` but with all required arguments pre-filled.
|
|
29
|
+
*/
|
|
30
|
+
updateBundle: () => Promise<boolean>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export async function checkForUpdate(
|
|
34
|
+
options: CheckForUpdateOptions,
|
|
35
|
+
): Promise<CheckForUpdateResult | null> {
|
|
23
36
|
if (__DEV__) {
|
|
24
37
|
return null;
|
|
25
38
|
}
|
|
@@ -42,17 +55,54 @@ export async function checkForUpdate(options: CheckForUpdateOptions) {
|
|
|
42
55
|
return null;
|
|
43
56
|
}
|
|
44
57
|
|
|
58
|
+
const baseArgs = {
|
|
59
|
+
bundleId: currentBundleId,
|
|
60
|
+
platform,
|
|
61
|
+
minBundleId,
|
|
62
|
+
channel: channel ?? undefined,
|
|
63
|
+
};
|
|
64
|
+
|
|
45
65
|
return fetchUpdateInfo(
|
|
46
66
|
options.source,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
HotUpdaterConstants.UPDATE_STRATEGY === "appVersion"
|
|
68
|
+
? {
|
|
69
|
+
_updateStrategy: HotUpdaterConstants.UPDATE_STRATEGY,
|
|
70
|
+
appVersion: currentAppVersion,
|
|
71
|
+
...baseArgs,
|
|
72
|
+
}
|
|
73
|
+
: {
|
|
74
|
+
_updateStrategy: HotUpdaterConstants.UPDATE_STRATEGY,
|
|
75
|
+
fingerprintHash: HotUpdaterConstants.FINGERPRINT_HASH!,
|
|
76
|
+
...baseArgs,
|
|
77
|
+
},
|
|
54
78
|
options.requestHeaders,
|
|
55
79
|
options.onError,
|
|
56
80
|
options.requestTimeout,
|
|
57
|
-
)
|
|
81
|
+
).then((updateInfo) => {
|
|
82
|
+
if (!updateInfo) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
...updateInfo,
|
|
88
|
+
updateBundle: async () => {
|
|
89
|
+
return updateBundle({
|
|
90
|
+
bundleId: updateInfo.id,
|
|
91
|
+
fileUrl: updateInfo.fileUrl,
|
|
92
|
+
status: updateInfo.status,
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
});
|
|
58
97
|
}
|
|
98
|
+
|
|
99
|
+
export const getUpdateSource = (baseUrl: string) => (args: GetBundlesArgs) => {
|
|
100
|
+
switch (args._updateStrategy) {
|
|
101
|
+
case "appVersion":
|
|
102
|
+
return `${baseUrl}/app-version/${args.platform}/${args.appVersion}/${args.channel}/${args.minBundleId}/${args.bundleId}`;
|
|
103
|
+
case "fingerprint":
|
|
104
|
+
return `${baseUrl}/fingerprint/${args.platform}/${args.fingerprintHash}/${args.channel}/${args.minBundleId}/${args.bundleId}`;
|
|
105
|
+
default:
|
|
106
|
+
return baseUrl;
|
|
107
|
+
}
|
|
108
|
+
};
|
package/src/fetchUpdateInfo.ts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import type { AppUpdateInfo, GetBundlesArgs } from "@hot-updater/core";
|
|
2
2
|
|
|
3
|
-
export type UpdateSource =
|
|
3
|
+
export type UpdateSource =
|
|
4
|
+
| string
|
|
5
|
+
| ((args: GetBundlesArgs) => Promise<AppUpdateInfo | null>)
|
|
6
|
+
| ((args: GetBundlesArgs) => string);
|
|
4
7
|
|
|
5
8
|
export const fetchUpdateInfo = async (
|
|
6
9
|
source: UpdateSource,
|
|
7
|
-
|
|
10
|
+
args: GetBundlesArgs,
|
|
8
11
|
requestHeaders?: Record<string, string>,
|
|
9
12
|
onError?: (error: Error) => void,
|
|
10
13
|
requestTimeout = 5000,
|
|
11
14
|
): Promise<AppUpdateInfo | null> => {
|
|
12
15
|
if (typeof source === "function") {
|
|
13
|
-
|
|
16
|
+
const url = source(args);
|
|
17
|
+
if (typeof url !== "string") {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
source = url;
|
|
14
21
|
}
|
|
15
22
|
|
|
16
23
|
const controller = new AbortController();
|
|
@@ -19,17 +26,38 @@ export const fetchUpdateInfo = async (
|
|
|
19
26
|
}, requestTimeout);
|
|
20
27
|
|
|
21
28
|
try {
|
|
29
|
+
let headers: Record<string, string> = {};
|
|
30
|
+
|
|
31
|
+
switch (args._updateStrategy) {
|
|
32
|
+
case "fingerprint":
|
|
33
|
+
headers = {
|
|
34
|
+
"Content-Type": "application/json",
|
|
35
|
+
"x-app-platform": args.platform,
|
|
36
|
+
"x-bundle-id": args.bundleId,
|
|
37
|
+
"x-fingerprint-hash": args.fingerprintHash,
|
|
38
|
+
...(args.minBundleId ? { "x-min-bundle-id": args.minBundleId } : {}),
|
|
39
|
+
...(args.channel ? { "x-channel": args.channel } : {}),
|
|
40
|
+
...requestHeaders,
|
|
41
|
+
};
|
|
42
|
+
break;
|
|
43
|
+
case "appVersion":
|
|
44
|
+
headers = {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
"x-app-platform": args.platform,
|
|
47
|
+
"x-bundle-id": args.bundleId,
|
|
48
|
+
"x-app-version": args.appVersion,
|
|
49
|
+
...(args.minBundleId ? { "x-min-bundle-id": args.minBundleId } : {}),
|
|
50
|
+
...(args.channel ? { "x-channel": args.channel } : {}),
|
|
51
|
+
...requestHeaders,
|
|
52
|
+
};
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
throw new Error("Invalid update strategy");
|
|
56
|
+
}
|
|
57
|
+
|
|
22
58
|
const response = await fetch(source, {
|
|
23
59
|
signal: controller.signal,
|
|
24
|
-
headers
|
|
25
|
-
"Content-Type": "application/json",
|
|
26
|
-
"x-app-platform": platform,
|
|
27
|
-
"x-app-version": appVersion,
|
|
28
|
-
"x-bundle-id": bundleId,
|
|
29
|
-
...(minBundleId ? { "x-min-bundle-id": minBundleId } : {}),
|
|
30
|
-
...(channel ? { "x-channel": channel } : {}),
|
|
31
|
-
...requestHeaders,
|
|
32
|
-
},
|
|
60
|
+
headers,
|
|
33
61
|
});
|
|
34
62
|
|
|
35
63
|
clearTimeout(timeoutId);
|
package/src/index.ts
CHANGED
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
getAppVersion,
|
|
5
5
|
getBundleId,
|
|
6
6
|
getChannel,
|
|
7
|
+
getFingerprintHash,
|
|
7
8
|
getMinBundleId,
|
|
9
|
+
getReleaseChannel,
|
|
8
10
|
reload,
|
|
9
|
-
setChannel,
|
|
10
11
|
updateBundle,
|
|
11
12
|
} from "./native";
|
|
12
13
|
import { runUpdateProcess } from "./runUpdateProcess";
|
|
@@ -65,13 +66,12 @@ export const HotUpdater = {
|
|
|
65
66
|
*/
|
|
66
67
|
getMinBundleId,
|
|
67
68
|
/**
|
|
68
|
-
* Fetches the current
|
|
69
|
+
* Fetches the current channel of the app.
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
* If the app is running in development mode, the channel will be `null`.
|
|
72
|
-
*
|
|
73
|
-
* @returns {string | null} The current release channel of the app
|
|
71
|
+
* If no channel is specified, the app is assigned to the 'production' channel.
|
|
74
72
|
*
|
|
73
|
+
* @returns {string} The current release channel of the app
|
|
74
|
+
* @default "production"
|
|
75
75
|
* @example
|
|
76
76
|
* ```ts
|
|
77
77
|
* const channel = HotUpdater.getChannel();
|
|
@@ -80,9 +80,17 @@ export const HotUpdater = {
|
|
|
80
80
|
*/
|
|
81
81
|
getChannel,
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
83
|
+
* The initial channel of the native app.
|
|
84
|
+
*
|
|
85
|
+
* @returns {string} The current release channel of the app
|
|
86
|
+
* @default "production"
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const channel = HotUpdater.getReleaseChannel();
|
|
90
|
+
* console.log(`Current release channel: ${channel}`);
|
|
91
|
+
* ```
|
|
84
92
|
*/
|
|
85
|
-
|
|
93
|
+
getReleaseChannel,
|
|
86
94
|
/**
|
|
87
95
|
* Adds a listener to HotUpdater events.
|
|
88
96
|
*
|
|
@@ -167,8 +175,9 @@ export const HotUpdater = {
|
|
|
167
175
|
/**
|
|
168
176
|
* Updates the bundle of the app.
|
|
169
177
|
*
|
|
170
|
-
* @param {
|
|
171
|
-
* @param {string}
|
|
178
|
+
* @param {UpdateBundleParams} params - Parameters object required for bundle update
|
|
179
|
+
* @param {string} params.bundleId - The bundle ID of the app
|
|
180
|
+
* @param {string|null} params.fileUrl - The URL of the zip file
|
|
172
181
|
*
|
|
173
182
|
* @returns {Promise<boolean>} Whether the update was successful
|
|
174
183
|
*
|
|
@@ -187,11 +196,28 @@ export const HotUpdater = {
|
|
|
187
196
|
* };
|
|
188
197
|
* }
|
|
189
198
|
*
|
|
190
|
-
* await HotUpdater.updateBundle(
|
|
199
|
+
* await HotUpdater.updateBundle({
|
|
200
|
+
* bundleId: updateInfo.id,
|
|
201
|
+
* fileUrl: updateInfo.fileUrl
|
|
202
|
+
* });
|
|
191
203
|
* if (updateInfo.shouldForceUpdate) {
|
|
192
204
|
* HotUpdater.reload();
|
|
193
205
|
* }
|
|
194
206
|
* ```
|
|
195
207
|
*/
|
|
196
208
|
updateBundle,
|
|
209
|
+
/**
|
|
210
|
+
* Fetches the fingerprint of the app.
|
|
211
|
+
*
|
|
212
|
+
* @returns {string} The fingerprint of the app
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* const fingerprint = HotUpdater.getFingerprintHash();
|
|
217
|
+
* console.log(`Fingerprint: ${fingerprint}`);
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
getFingerprintHash,
|
|
197
221
|
};
|
|
222
|
+
|
|
223
|
+
export { getUpdateSource } from "./checkForUpdate";
|
package/src/native.ts
CHANGED
|
@@ -1,37 +1,28 @@
|
|
|
1
|
+
import type { UpdateStatus, UpdateStrategy } from "@hot-updater/core";
|
|
1
2
|
import { NativeEventEmitter, Platform } from "react-native";
|
|
2
|
-
import
|
|
3
|
+
import HotUpdaterNative, {
|
|
4
|
+
type UpdateBundleParams,
|
|
5
|
+
} from "./specs/NativeHotUpdater";
|
|
6
|
+
|
|
3
7
|
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
|
|
4
8
|
|
|
5
9
|
declare const __HOT_UPDATER_BUNDLE_ID: string | undefined;
|
|
6
|
-
declare const
|
|
10
|
+
declare const __HOT_UPDATER_FINGERPRINT_HASH_IOS: string | null;
|
|
11
|
+
declare const __HOT_UPDATER_FINGERPRINT_HASH_ANDROID: string | null;
|
|
12
|
+
declare const __HOT_UPDATER_UPDATE_STRATEGY: UpdateStrategy;
|
|
13
|
+
declare const __HOT_UPDATER_CHANNEL: string | null;
|
|
7
14
|
|
|
8
|
-
const
|
|
15
|
+
export const HotUpdaterConstants = {
|
|
16
|
+
OVER_THE_AIR_CHANNEL: __HOT_UPDATER_CHANNEL,
|
|
9
17
|
HOT_UPDATER_BUNDLE_ID: __HOT_UPDATER_BUNDLE_ID || NIL_UUID,
|
|
10
|
-
|
|
18
|
+
FINGERPRINT_HASH: Platform.select({
|
|
19
|
+
ios: __HOT_UPDATER_FINGERPRINT_HASH_IOS,
|
|
20
|
+
android: __HOT_UPDATER_FINGERPRINT_HASH_ANDROID,
|
|
21
|
+
default: null,
|
|
22
|
+
}),
|
|
23
|
+
UPDATE_STRATEGY: __HOT_UPDATER_UPDATE_STRATEGY,
|
|
11
24
|
};
|
|
12
25
|
|
|
13
|
-
const RCTNativeHotUpdater = require("./specs/NativeHotUpdater").default;
|
|
14
|
-
|
|
15
|
-
const LINKING_ERROR =
|
|
16
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
17
|
-
`The package '@hot-updater/react-native' doesn't seem to be linked. Make sure: \n\n` +
|
|
18
|
-
Platform.select({ ios: "- You have run 'pod install'\n", default: "" }) +
|
|
19
|
-
"- You rebuilt the app after installing the package\n" +
|
|
20
|
-
"- You are not using Expo Go\n";
|
|
21
|
-
|
|
22
|
-
const HotUpdaterNative = (
|
|
23
|
-
RCTNativeHotUpdater
|
|
24
|
-
? RCTNativeHotUpdater
|
|
25
|
-
: new Proxy(
|
|
26
|
-
{},
|
|
27
|
-
{
|
|
28
|
-
get() {
|
|
29
|
-
throw new Error(LINKING_ERROR);
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
)
|
|
33
|
-
) as Spec;
|
|
34
|
-
|
|
35
26
|
export type HotUpdaterEvent = {
|
|
36
27
|
onProgress: {
|
|
37
28
|
progress: number;
|
|
@@ -50,19 +41,59 @@ export const addListener = <T extends keyof HotUpdaterEvent>(
|
|
|
50
41
|
};
|
|
51
42
|
};
|
|
52
43
|
|
|
44
|
+
export type UpdateParams = UpdateBundleParams & {
|
|
45
|
+
status: UpdateStatus;
|
|
46
|
+
};
|
|
47
|
+
|
|
53
48
|
/**
|
|
54
|
-
* Downloads files
|
|
49
|
+
* Downloads files and applies them to the app.
|
|
55
50
|
*
|
|
56
|
-
* @param {
|
|
57
|
-
* @param {string | null} zipUrl - zip file URL. If null, it means rolling back to the built-in bundle
|
|
51
|
+
* @param {UpdateParams} params - Parameters object required for bundle update
|
|
58
52
|
* @returns {Promise<boolean>} Resolves with true if download was successful, otherwise rejects with an error.
|
|
59
53
|
*/
|
|
60
|
-
export
|
|
54
|
+
export async function updateBundle(params: UpdateParams): Promise<boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Use updateBundle(params: UpdateBundleParamsWithStatus) instead
|
|
57
|
+
*/
|
|
58
|
+
export async function updateBundle(
|
|
61
59
|
bundleId: string,
|
|
62
|
-
|
|
63
|
-
): Promise<boolean
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
fileUrl: string | null,
|
|
61
|
+
): Promise<boolean>;
|
|
62
|
+
export async function updateBundle(
|
|
63
|
+
paramsOrBundleId: UpdateParams | string,
|
|
64
|
+
fileUrl?: string | null,
|
|
65
|
+
): Promise<boolean> {
|
|
66
|
+
const updateBundleId =
|
|
67
|
+
typeof paramsOrBundleId === "string"
|
|
68
|
+
? paramsOrBundleId
|
|
69
|
+
: paramsOrBundleId.bundleId;
|
|
70
|
+
|
|
71
|
+
const status =
|
|
72
|
+
typeof paramsOrBundleId === "string" ? "UPDATE" : paramsOrBundleId.status;
|
|
73
|
+
|
|
74
|
+
const currentBundleId = getBundleId();
|
|
75
|
+
|
|
76
|
+
// updateBundleId <= currentBundleId
|
|
77
|
+
if (
|
|
78
|
+
status === "UPDATE" &&
|
|
79
|
+
updateBundleId.localeCompare(currentBundleId) <= 0
|
|
80
|
+
) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"Update bundle id is the same as the current bundle id. Preventing infinite update loop.",
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (typeof paramsOrBundleId === "string") {
|
|
87
|
+
return HotUpdaterNative.updateBundle({
|
|
88
|
+
bundleId: updateBundleId,
|
|
89
|
+
fileUrl: fileUrl || null,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return HotUpdaterNative.updateBundle({
|
|
93
|
+
bundleId: updateBundleId,
|
|
94
|
+
fileUrl: paramsOrBundleId.fileUrl,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
66
97
|
|
|
67
98
|
/**
|
|
68
99
|
* Fetches the current app version.
|
|
@@ -99,19 +130,34 @@ export const getMinBundleId = (): string => {
|
|
|
99
130
|
* @returns {Promise<string>} Resolves with the current version id or null if not available.
|
|
100
131
|
*/
|
|
101
132
|
export const getBundleId = (): string => {
|
|
102
|
-
return
|
|
133
|
+
return HotUpdaterConstants.HOT_UPDATER_BUNDLE_ID === NIL_UUID
|
|
103
134
|
? getMinBundleId()
|
|
104
|
-
:
|
|
135
|
+
: HotUpdaterConstants.HOT_UPDATER_BUNDLE_ID;
|
|
105
136
|
};
|
|
106
137
|
|
|
107
138
|
/**
|
|
108
|
-
*
|
|
139
|
+
* Fetches the channel for the app.
|
|
140
|
+
*
|
|
141
|
+
* @returns {string} Resolves with the channel or null if not available.
|
|
109
142
|
*/
|
|
110
|
-
export const
|
|
111
|
-
|
|
143
|
+
export const getChannel = (): string => {
|
|
144
|
+
if (HotUpdaterConstants.OVER_THE_AIR_CHANNEL) {
|
|
145
|
+
return HotUpdaterConstants.OVER_THE_AIR_CHANNEL;
|
|
146
|
+
}
|
|
147
|
+
const constants = HotUpdaterNative.getConstants();
|
|
148
|
+
return constants.CHANNEL;
|
|
112
149
|
};
|
|
113
150
|
|
|
114
|
-
export const
|
|
151
|
+
export const getReleaseChannel = (): string => {
|
|
115
152
|
const constants = HotUpdaterNative.getConstants();
|
|
116
|
-
return constants
|
|
153
|
+
return constants.CHANNEL;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Fetches the fingerprint for the app.
|
|
158
|
+
*
|
|
159
|
+
* @returns {string | null} Resolves with the fingerprint hash
|
|
160
|
+
*/
|
|
161
|
+
export const getFingerprintHash = (): string | null => {
|
|
162
|
+
return HotUpdaterConstants.FINGERPRINT_HASH;
|
|
117
163
|
};
|
package/src/runUpdateProcess.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CheckForUpdateOptions, checkForUpdate } from "./checkForUpdate";
|
|
2
|
-
import { getBundleId, reload
|
|
2
|
+
import { getBundleId, reload } from "./native";
|
|
3
3
|
|
|
4
4
|
export interface RunUpdateProcessResponse {
|
|
5
5
|
status: "ROLLBACK" | "UPDATE" | "UP_TO_DATE";
|
|
@@ -63,7 +63,7 @@ export const runUpdateProcess = async ({
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const isUpdated = await updateBundle(
|
|
66
|
+
const isUpdated = await updateInfo.updateBundle();
|
|
67
67
|
if (isUpdated && updateInfo.shouldForceUpdate && reloadOnForceUpdate) {
|
|
68
68
|
reload();
|
|
69
69
|
}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import type { TurboModule } from "react-native";
|
|
2
2
|
import { TurboModuleRegistry } from "react-native";
|
|
3
3
|
|
|
4
|
+
export interface UpdateBundleParams {
|
|
5
|
+
bundleId: string;
|
|
6
|
+
fileUrl: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
export interface Spec extends TurboModule {
|
|
5
10
|
// Methods
|
|
6
11
|
reload(): void;
|
|
7
|
-
updateBundle(
|
|
8
|
-
/**
|
|
9
|
-
* @deprecated
|
|
10
|
-
* use getConstants().APP_VERSION instead
|
|
11
|
-
*/
|
|
12
|
-
getAppVersion(): Promise<string | null>;
|
|
13
|
-
|
|
14
|
-
setChannel(channel: string): Promise<void>;
|
|
12
|
+
updateBundle(params: UpdateBundleParams): Promise<boolean>;
|
|
15
13
|
|
|
16
14
|
// EventEmitter
|
|
17
15
|
addListener(eventName: string): void;
|
|
@@ -19,8 +17,8 @@ export interface Spec extends TurboModule {
|
|
|
19
17
|
readonly getConstants: () => {
|
|
20
18
|
MIN_BUNDLE_ID: string;
|
|
21
19
|
APP_VERSION: string | null;
|
|
22
|
-
CHANNEL: string
|
|
20
|
+
CHANNEL: string;
|
|
23
21
|
};
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
export default TurboModuleRegistry.
|
|
24
|
+
export default TurboModuleRegistry.getEnforcing<Spec>("HotUpdater");
|
package/src/wrap.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useEffect, useLayoutEffect, useState } from "react";
|
|
3
3
|
import { type CheckForUpdateOptions, checkForUpdate } from "./checkForUpdate";
|
|
4
|
-
import { HotUpdaterError } from "./error";
|
|
4
|
+
import type { HotUpdaterError } from "./error";
|
|
5
5
|
import { useEventCallback } from "./hooks/useEventCallback";
|
|
6
|
-
import { getBundleId, reload
|
|
6
|
+
import { getBundleId, reload } from "./native";
|
|
7
7
|
import type { RunUpdateProcessResponse } from "./runUpdateProcess";
|
|
8
8
|
import { useHotUpdaterStore } from "./store";
|
|
9
9
|
|
|
@@ -39,7 +39,7 @@ export interface HotUpdaterOptions extends CheckForUpdateOptions {
|
|
|
39
39
|
progress: number;
|
|
40
40
|
message: string | null;
|
|
41
41
|
}>;
|
|
42
|
-
onError?: (error: HotUpdaterError) => void;
|
|
42
|
+
onError?: (error: HotUpdaterError | Error | unknown) => void;
|
|
43
43
|
onProgress?: (progress: number) => void;
|
|
44
44
|
/**
|
|
45
45
|
* When a force update exists, the app will automatically reload.
|
|
@@ -93,7 +93,10 @@ export function wrap<P extends React.JSX.IntrinsicAttributes = object>(
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
if (updateInfo.shouldForceUpdate === false) {
|
|
96
|
-
void updateBundle(
|
|
96
|
+
void updateInfo.updateBundle().catch((error) => {
|
|
97
|
+
restOptions.onError?.(error);
|
|
98
|
+
});
|
|
99
|
+
|
|
97
100
|
restOptions.onUpdateProcessCompleted?.({
|
|
98
101
|
id: updateInfo.id,
|
|
99
102
|
status: updateInfo.status,
|
|
@@ -103,13 +106,9 @@ export function wrap<P extends React.JSX.IntrinsicAttributes = object>(
|
|
|
103
106
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
|
-
|
|
107
109
|
// Force Update Scenario
|
|
108
110
|
setUpdateStatus("UPDATING");
|
|
109
|
-
const isSuccess = await updateBundle(
|
|
110
|
-
updateInfo.id,
|
|
111
|
-
updateInfo.fileUrl,
|
|
112
|
-
);
|
|
111
|
+
const isSuccess = await updateInfo.updateBundle();
|
|
113
112
|
|
|
114
113
|
if (!isSuccess) {
|
|
115
114
|
throw new Error(
|
|
@@ -130,11 +129,8 @@ export function wrap<P extends React.JSX.IntrinsicAttributes = object>(
|
|
|
130
129
|
|
|
131
130
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
132
131
|
} catch (error) {
|
|
133
|
-
|
|
134
|
-
restOptions.onError?.(error);
|
|
135
|
-
}
|
|
132
|
+
restOptions.onError?.(error);
|
|
136
133
|
setUpdateStatus("UPDATE_PROCESS_COMPLETED");
|
|
137
|
-
throw error;
|
|
138
134
|
}
|
|
139
135
|
});
|
|
140
136
|
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
package com.hotupdater
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.content.SharedPreferences
|
|
5
|
-
import java.io.File
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A class that manages SharedPreferences based on the app version.
|
|
9
|
-
* Externally, only getItem(key) and setItem(key, value) can be used.
|
|
10
|
-
* It constructs the prefs filename based on the app version passed in the constructor,
|
|
11
|
-
* and deletes previous files that don't match the current version during initialization.
|
|
12
|
-
*/
|
|
13
|
-
class HotUpdaterPrefs(
|
|
14
|
-
private val context: Context,
|
|
15
|
-
private val appVersion: String,
|
|
16
|
-
) {
|
|
17
|
-
private val prefs: SharedPreferences
|
|
18
|
-
|
|
19
|
-
init {
|
|
20
|
-
val prefsName = "HotUpdaterPrefs_$appVersion"
|
|
21
|
-
|
|
22
|
-
val sharedPrefsDir = File(context.applicationInfo.dataDir, "shared_prefs")
|
|
23
|
-
if (sharedPrefsDir.exists() && sharedPrefsDir.isDirectory) {
|
|
24
|
-
sharedPrefsDir.listFiles()?.forEach { file ->
|
|
25
|
-
if (file.name.startsWith("HotUpdaterPrefs_") && file.name != "$prefsName.xml") {
|
|
26
|
-
file.delete()
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
prefs = context.getSharedPreferences(prefsName, Context.MODE_PRIVATE)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
fun getItem(key: String): String? = prefs.getString(key, null)
|
|
35
|
-
|
|
36
|
-
fun setItem(
|
|
37
|
-
key: String,
|
|
38
|
-
value: String?,
|
|
39
|
-
) {
|
|
40
|
-
prefs.edit().putString(key, value).apply()
|
|
41
|
-
}
|
|
42
|
-
}
|
package/dist/checkForUpdate.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type UpdateSource } from "./fetchUpdateInfo";
|
|
2
|
-
export interface CheckForUpdateOptions {
|
|
3
|
-
source: UpdateSource;
|
|
4
|
-
requestHeaders?: Record<string, string>;
|
|
5
|
-
onError?: (error: Error) => void;
|
|
6
|
-
/**
|
|
7
|
-
* The timeout duration for the request.
|
|
8
|
-
* @default 5000
|
|
9
|
-
*/
|
|
10
|
-
requestTimeout?: number;
|
|
11
|
-
}
|
|
12
|
-
export declare function checkForUpdate(options: CheckForUpdateOptions): Promise<import("@hot-updater/core").AppUpdateInfo | null>;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { AppUpdateInfo, GetBundlesArgs } from "@hot-updater/core";
|
|
2
|
-
export type UpdateSource = string | (() => Promise<AppUpdateInfo | null>);
|
|
3
|
-
export declare const fetchUpdateInfo: (source: UpdateSource, { appVersion, bundleId, platform, minBundleId, channel }: GetBundlesArgs, requestHeaders?: Record<string, string>, onError?: (error: Error) => void, requestTimeout?: number) => Promise<AppUpdateInfo | null>;
|