@otaupdate/react-native 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +321 -0
- package/android/build.gradle +70 -0
- package/android/src/expo/java/com/otaupdate/OtaUpdateExpoPackage.kt +37 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/otaupdate/OtaUpdate.kt +98 -0
- package/android/src/main/java/com/otaupdate/OtaUpdateInstaller.kt +211 -0
- package/android/src/main/java/com/otaupdate/OtaUpdateModule.kt +278 -0
- package/android/src/main/java/com/otaupdate/OtaUpdatePackage.kt +15 -0
- package/android/src/main/java/com/otaupdate/OtaUpdateStore.kt +268 -0
- package/app.plugin.js +3 -0
- package/expo-module.config.json +6 -0
- package/ios/OtaUpdate.h +46 -0
- package/ios/OtaUpdate.m +302 -0
- package/ios/OtaUpdateInstaller.h +25 -0
- package/ios/OtaUpdateInstaller.m +278 -0
- package/ios/OtaUpdateStore.h +69 -0
- package/ios/OtaUpdateStore.m +283 -0
- package/lib/OtaUpdate.d.ts +28 -0
- package/lib/OtaUpdate.d.ts.map +1 -0
- package/lib/OtaUpdate.js +254 -0
- package/lib/OtaUpdate.js.map +1 -0
- package/lib/api.d.ts +36 -0
- package/lib/api.d.ts.map +1 -0
- package/lib/api.js +89 -0
- package/lib/api.js.map +1 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +37 -0
- package/lib/index.js.map +1 -0
- package/lib/native.d.ts +34 -0
- package/lib/native.d.ts.map +1 -0
- package/lib/native.js +34 -0
- package/lib/native.js.map +1 -0
- package/lib/types.d.ts +112 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +27 -0
- package/lib/types.js.map +1 -0
- package/lib/useOtaUpdate.d.ts +17 -0
- package/lib/useOtaUpdate.d.ts.map +1 -0
- package/lib/useOtaUpdate.js +81 -0
- package/lib/useOtaUpdate.js.map +1 -0
- package/lib/withOtaUpdate.d.ts +10 -0
- package/lib/withOtaUpdate.d.ts.map +1 -0
- package/lib/withOtaUpdate.js +21 -0
- package/lib/withOtaUpdate.js.map +1 -0
- package/package.json +54 -0
- package/plugin/build/index.d.ts +11 -0
- package/plugin/build/index.js +97 -0
- package/react-native-ota-update.podspec +43 -0
- package/react-native.config.js +21 -0
- package/src/OtaUpdate.ts +293 -0
- package/src/api.ts +122 -0
- package/src/index.ts +55 -0
- package/src/native.ts +64 -0
- package/src/types.ts +125 -0
- package/src/useOtaUpdate.ts +96 -0
- package/src/withOtaUpdate.tsx +22 -0
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** When a downloaded update actually replaces the running JS bundle. */
|
|
2
|
+
export declare enum InstallMode {
|
|
3
|
+
/** Swap in on the next natural app start. Safest; the default. */
|
|
4
|
+
ON_NEXT_RESTART = 0,
|
|
5
|
+
/** Swap in the next time the app returns from the background. */
|
|
6
|
+
ON_NEXT_RESUME = 1,
|
|
7
|
+
/** Reload the JS bundle right now. Interrupts the user — use for mandatory fixes. */
|
|
8
|
+
IMMEDIATE = 2
|
|
9
|
+
}
|
|
10
|
+
/** Progress of a `sync()` call, reported through `onSyncStatusChange`. */
|
|
11
|
+
export declare enum SyncStatus {
|
|
12
|
+
UP_TO_DATE = 0,
|
|
13
|
+
UPDATE_INSTALLED = 1,
|
|
14
|
+
UPDATE_IGNORED = 2,
|
|
15
|
+
UNKNOWN_ERROR = 3,
|
|
16
|
+
SYNC_IN_PROGRESS = 4,
|
|
17
|
+
CHECKING_FOR_UPDATE = 5,
|
|
18
|
+
AWAITING_USER_ACTION = 6,
|
|
19
|
+
DOWNLOADING_PACKAGE = 7,
|
|
20
|
+
INSTALLING_UPDATE = 8
|
|
21
|
+
}
|
|
22
|
+
export interface DownloadProgress {
|
|
23
|
+
totalBytes: number;
|
|
24
|
+
receivedBytes: number;
|
|
25
|
+
}
|
|
26
|
+
/** Metadata about an update that exists on the server but not yet on device. */
|
|
27
|
+
export interface RemotePackage {
|
|
28
|
+
label: string;
|
|
29
|
+
packageHash: string;
|
|
30
|
+
downloadUrl: string;
|
|
31
|
+
size: number;
|
|
32
|
+
isMandatory: boolean;
|
|
33
|
+
description: string | null;
|
|
34
|
+
targetBinaryVersion: string;
|
|
35
|
+
rollout: number;
|
|
36
|
+
isRollback: boolean;
|
|
37
|
+
deployment: string;
|
|
38
|
+
/** Fetches and verifies the bundle, returning the on-device package. */
|
|
39
|
+
download(onProgress?: (progress: DownloadProgress) => void): Promise<LocalPackage>;
|
|
40
|
+
}
|
|
41
|
+
/** An update that has been downloaded and verified onto the device. */
|
|
42
|
+
export interface LocalPackage {
|
|
43
|
+
label: string;
|
|
44
|
+
packageHash: string;
|
|
45
|
+
isMandatory: boolean;
|
|
46
|
+
description: string | null;
|
|
47
|
+
bundlePath: string;
|
|
48
|
+
size: number;
|
|
49
|
+
/** Applies the update according to `mode`. */
|
|
50
|
+
install(mode?: InstallMode, minimumBackgroundDuration?: number): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/** The bundle currently running, if it came from an OTA update. */
|
|
53
|
+
export interface CurrentPackage {
|
|
54
|
+
label: string | null;
|
|
55
|
+
packageHash: string | null;
|
|
56
|
+
description: string | null;
|
|
57
|
+
isMandatory: boolean;
|
|
58
|
+
bundlePath: string | null;
|
|
59
|
+
appVersion: string;
|
|
60
|
+
/** True until `notifyAppReady()` confirms this update booted successfully. */
|
|
61
|
+
isPending: boolean;
|
|
62
|
+
/** True on the first run after this update was applied. */
|
|
63
|
+
isFirstRun: boolean;
|
|
64
|
+
}
|
|
65
|
+
export type NoUpdateReason = 'up_to_date' | 'not_in_rollout' | 'no_matching_binary_version' | 'update_app_version';
|
|
66
|
+
export interface CheckResult {
|
|
67
|
+
update: RemotePackage | null;
|
|
68
|
+
reason?: NoUpdateReason;
|
|
69
|
+
/** Set when a newer *binary* is required — the fix is a store update, not OTA. */
|
|
70
|
+
updateAppVersion?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface OtaConfiguration {
|
|
73
|
+
deploymentKey: string;
|
|
74
|
+
serverUrl: string;
|
|
75
|
+
appVersion: string;
|
|
76
|
+
clientUniqueId: string;
|
|
77
|
+
/** Hash/label of the bundle currently running, if it is an OTA package. */
|
|
78
|
+
packageHash: string | null;
|
|
79
|
+
label: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* The app's real native bundle identifier (iOS `CFBundleIdentifier` /
|
|
82
|
+
* Android package name), read from the native runtime — not settable from
|
|
83
|
+
* JS. Sent on every update-check so the server can reject a deployment key
|
|
84
|
+
* used against an app it was not issued for.
|
|
85
|
+
*/
|
|
86
|
+
bundleIdentifier: string;
|
|
87
|
+
}
|
|
88
|
+
export interface SyncOptions {
|
|
89
|
+
installMode?: InstallMode;
|
|
90
|
+
/** Install mode used when the release is flagged mandatory. */
|
|
91
|
+
mandatoryInstallMode?: InstallMode;
|
|
92
|
+
/** Seconds the app must stay backgrounded before an ON_NEXT_RESUME install applies. */
|
|
93
|
+
minimumBackgroundDuration?: number;
|
|
94
|
+
deploymentKey?: string;
|
|
95
|
+
onSyncStatusChange?: (status: SyncStatus) => void;
|
|
96
|
+
onDownloadProgress?: (progress: DownloadProgress) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Return false to skip an update (e.g. after asking the user).
|
|
99
|
+
* Mandatory updates ignore the result.
|
|
100
|
+
*/
|
|
101
|
+
shouldInstall?: (update: RemotePackage) => boolean | Promise<boolean>;
|
|
102
|
+
}
|
|
103
|
+
export interface OtaOptions {
|
|
104
|
+
/** Run a sync when the app starts. Default: true. */
|
|
105
|
+
checkOnAppStart?: boolean;
|
|
106
|
+
/** Run a sync each time the app returns to the foreground. Default: true. */
|
|
107
|
+
checkOnResume?: boolean;
|
|
108
|
+
/** Minimum seconds between automatic syncs. Default: 60. */
|
|
109
|
+
minimumSyncInterval?: number;
|
|
110
|
+
sync?: SyncOptions;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SyncStatus = exports.InstallMode = void 0;
|
|
4
|
+
/** When a downloaded update actually replaces the running JS bundle. */
|
|
5
|
+
var InstallMode;
|
|
6
|
+
(function (InstallMode) {
|
|
7
|
+
/** Swap in on the next natural app start. Safest; the default. */
|
|
8
|
+
InstallMode[InstallMode["ON_NEXT_RESTART"] = 0] = "ON_NEXT_RESTART";
|
|
9
|
+
/** Swap in the next time the app returns from the background. */
|
|
10
|
+
InstallMode[InstallMode["ON_NEXT_RESUME"] = 1] = "ON_NEXT_RESUME";
|
|
11
|
+
/** Reload the JS bundle right now. Interrupts the user — use for mandatory fixes. */
|
|
12
|
+
InstallMode[InstallMode["IMMEDIATE"] = 2] = "IMMEDIATE";
|
|
13
|
+
})(InstallMode || (exports.InstallMode = InstallMode = {}));
|
|
14
|
+
/** Progress of a `sync()` call, reported through `onSyncStatusChange`. */
|
|
15
|
+
var SyncStatus;
|
|
16
|
+
(function (SyncStatus) {
|
|
17
|
+
SyncStatus[SyncStatus["UP_TO_DATE"] = 0] = "UP_TO_DATE";
|
|
18
|
+
SyncStatus[SyncStatus["UPDATE_INSTALLED"] = 1] = "UPDATE_INSTALLED";
|
|
19
|
+
SyncStatus[SyncStatus["UPDATE_IGNORED"] = 2] = "UPDATE_IGNORED";
|
|
20
|
+
SyncStatus[SyncStatus["UNKNOWN_ERROR"] = 3] = "UNKNOWN_ERROR";
|
|
21
|
+
SyncStatus[SyncStatus["SYNC_IN_PROGRESS"] = 4] = "SYNC_IN_PROGRESS";
|
|
22
|
+
SyncStatus[SyncStatus["CHECKING_FOR_UPDATE"] = 5] = "CHECKING_FOR_UPDATE";
|
|
23
|
+
SyncStatus[SyncStatus["AWAITING_USER_ACTION"] = 6] = "AWAITING_USER_ACTION";
|
|
24
|
+
SyncStatus[SyncStatus["DOWNLOADING_PACKAGE"] = 7] = "DOWNLOADING_PACKAGE";
|
|
25
|
+
SyncStatus[SyncStatus["INSTALLING_UPDATE"] = 8] = "INSTALLING_UPDATE";
|
|
26
|
+
})(SyncStatus || (exports.SyncStatus = SyncStatus = {}));
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
package/lib/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAAA,wEAAwE;AACxE,IAAY,WAOX;AAPD,WAAY,WAAW;IACrB,kEAAkE;IAClE,mEAAmB,CAAA;IACnB,iEAAiE;IACjE,iEAAkB,CAAA;IAClB,qFAAqF;IACrF,uDAAa,CAAA;AACf,CAAC,EAPW,WAAW,2BAAX,WAAW,QAOtB;AAED,0EAA0E;AAC1E,IAAY,UAUX;AAVD,WAAY,UAAU;IACpB,uDAAc,CAAA;IACd,mEAAoB,CAAA;IACpB,+DAAkB,CAAA;IAClB,6DAAiB,CAAA;IACjB,mEAAoB,CAAA;IACpB,yEAAuB,CAAA;IACvB,2EAAwB,CAAA;IACxB,yEAAuB,CAAA;IACvB,qEAAqB,CAAA;AACvB,CAAC,EAVW,UAAU,0BAAV,UAAU,QAUrB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SyncStatus, type DownloadProgress, type RemotePackage, type SyncOptions } from './types';
|
|
2
|
+
export interface UseOtaUpdateState {
|
|
3
|
+
status: SyncStatus;
|
|
4
|
+
progress: DownloadProgress | null;
|
|
5
|
+
/** Populated when a check found an update that has not been installed yet. */
|
|
6
|
+
available: RemotePackage | null;
|
|
7
|
+
error: Error | null;
|
|
8
|
+
isSyncing: boolean;
|
|
9
|
+
check(): Promise<void>;
|
|
10
|
+
update(options?: SyncOptions): Promise<SyncStatus>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Hook for update UI — a "New version available" banner, a download progress
|
|
14
|
+
* bar, or a settings screen with a manual "Check for updates" button.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useOtaUpdate(defaultOptions?: SyncOptions): UseOtaUpdateState;
|
|
17
|
+
//# sourceMappingURL=useOtaUpdate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOtaUpdate.d.ts","sourceRoot":"","sources":["../src/useOtaUpdate.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,8EAA8E;IAC9E,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,cAAc,GAAE,WAAgB,GAAG,iBAAiB,CAsEhF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useOtaUpdate = useOtaUpdate;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const OtaUpdate_1 = require("./OtaUpdate");
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
/**
|
|
8
|
+
* Hook for update UI — a "New version available" banner, a download progress
|
|
9
|
+
* bar, or a settings screen with a manual "Check for updates" button.
|
|
10
|
+
*/
|
|
11
|
+
function useOtaUpdate(defaultOptions = {}) {
|
|
12
|
+
const [status, setStatus] = (0, react_1.useState)(types_1.SyncStatus.UP_TO_DATE);
|
|
13
|
+
const [progress, setProgress] = (0, react_1.useState)(null);
|
|
14
|
+
const [available, setAvailable] = (0, react_1.useState)(null);
|
|
15
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
16
|
+
const mounted = (0, react_1.useRef)(true);
|
|
17
|
+
(0, react_1.useEffect)(() => {
|
|
18
|
+
mounted.current = true;
|
|
19
|
+
return () => {
|
|
20
|
+
mounted.current = false;
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
const check = (0, react_1.useCallback)(async () => {
|
|
24
|
+
try {
|
|
25
|
+
setError(null);
|
|
26
|
+
setStatus(types_1.SyncStatus.CHECKING_FOR_UPDATE);
|
|
27
|
+
const result = await (0, OtaUpdate_1.checkForUpdate)(defaultOptions.deploymentKey);
|
|
28
|
+
if (!mounted.current)
|
|
29
|
+
return;
|
|
30
|
+
setAvailable(result.update);
|
|
31
|
+
setStatus(result.update ? types_1.SyncStatus.AWAITING_USER_ACTION : types_1.SyncStatus.UP_TO_DATE);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (!mounted.current)
|
|
35
|
+
return;
|
|
36
|
+
setError(err);
|
|
37
|
+
setStatus(types_1.SyncStatus.UNKNOWN_ERROR);
|
|
38
|
+
}
|
|
39
|
+
// defaultOptions is intentionally read fresh on each call rather than
|
|
40
|
+
// captured as a dependency — callers routinely pass an inline object.
|
|
41
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
42
|
+
}, [defaultOptions.deploymentKey]);
|
|
43
|
+
const update = (0, react_1.useCallback)(async (options = {}) => {
|
|
44
|
+
setError(null);
|
|
45
|
+
const result = await (0, OtaUpdate_1.sync)({
|
|
46
|
+
installMode: types_1.InstallMode.ON_NEXT_RESTART,
|
|
47
|
+
...defaultOptions,
|
|
48
|
+
...options,
|
|
49
|
+
onSyncStatusChange: (s) => {
|
|
50
|
+
if (mounted.current)
|
|
51
|
+
setStatus(s);
|
|
52
|
+
defaultOptions.onSyncStatusChange?.(s);
|
|
53
|
+
options.onSyncStatusChange?.(s);
|
|
54
|
+
},
|
|
55
|
+
onDownloadProgress: (p) => {
|
|
56
|
+
if (mounted.current)
|
|
57
|
+
setProgress(p);
|
|
58
|
+
defaultOptions.onDownloadProgress?.(p);
|
|
59
|
+
options.onDownloadProgress?.(p);
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (mounted.current && result === types_1.SyncStatus.UPDATE_INSTALLED)
|
|
63
|
+
setAvailable(null);
|
|
64
|
+
return result;
|
|
65
|
+
},
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
|
+
[]);
|
|
68
|
+
return {
|
|
69
|
+
status,
|
|
70
|
+
progress,
|
|
71
|
+
available,
|
|
72
|
+
error,
|
|
73
|
+
isSyncing: status === types_1.SyncStatus.CHECKING_FOR_UPDATE ||
|
|
74
|
+
status === types_1.SyncStatus.DOWNLOADING_PACKAGE ||
|
|
75
|
+
status === types_1.SyncStatus.INSTALLING_UPDATE ||
|
|
76
|
+
status === types_1.SyncStatus.SYNC_IN_PROGRESS,
|
|
77
|
+
check,
|
|
78
|
+
update,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=useOtaUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOtaUpdate.js","sourceRoot":"","sources":["../src/useOtaUpdate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { OtaOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Wraps the root component so updates are checked on start and on resume, and
|
|
5
|
+
* the running bundle is confirmed (rollback-protection) as soon as it mounts.
|
|
6
|
+
*
|
|
7
|
+
* export default withOtaUpdate(App, { sync: { installMode: InstallMode.ON_NEXT_RESUME } })
|
|
8
|
+
*/
|
|
9
|
+
export declare function withOtaUpdate<P extends object>(Component: React.ComponentType<P>, options?: OtaOptions): React.ComponentType<P>;
|
|
10
|
+
//# sourceMappingURL=withOtaUpdate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withOtaUpdate.d.ts","sourceRoot":"","sources":["../src/withOtaUpdate.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAC5C,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EACjC,OAAO,GAAE,UAAe,GACvB,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAQxB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withOtaUpdate = withOtaUpdate;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const OtaUpdate_1 = require("./OtaUpdate");
|
|
7
|
+
/**
|
|
8
|
+
* Wraps the root component so updates are checked on start and on resume, and
|
|
9
|
+
* the running bundle is confirmed (rollback-protection) as soon as it mounts.
|
|
10
|
+
*
|
|
11
|
+
* export default withOtaUpdate(App, { sync: { installMode: InstallMode.ON_NEXT_RESUME } })
|
|
12
|
+
*/
|
|
13
|
+
function withOtaUpdate(Component, options = {}) {
|
|
14
|
+
const Wrapped = (props) => {
|
|
15
|
+
(0, react_1.useEffect)(() => (0, OtaUpdate_1.startAutoSync)(options), []);
|
|
16
|
+
return (0, jsx_runtime_1.jsx)(Component, { ...props });
|
|
17
|
+
};
|
|
18
|
+
Wrapped.displayName = `withOtaUpdate(${Component.displayName ?? Component.name ?? 'Component'})`;
|
|
19
|
+
return Wrapped;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=withOtaUpdate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withOtaUpdate.js","sourceRoot":"","sources":["../src/withOtaUpdate.tsx"],"names":[],"mappings":";;AAUA,sCAWC;;AArBD,iCAAyC;AACzC,2CAA4C;AAG5C;;;;;GAKG;AACH,SAAgB,aAAa,CAC3B,SAAiC,EACjC,UAAsB,EAAE;IAExB,MAAM,OAAO,GAAgB,CAAC,KAAK,EAAE,EAAE;QACrC,IAAA,iBAAS,EAAC,GAAG,EAAE,CAAC,IAAA,yBAAa,EAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,uBAAC,SAAS,OAAK,KAAK,GAAI,CAAC;IAClC,CAAC,CAAC;IAEF,OAAO,CAAC,WAAW,GAAG,iBAAiB,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,IAAI,IAAI,WAAW,GAAG,CAAC;IACjG,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@otaupdate/react-native",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Over-the-air JS bundle updates for React Native \u2014 bare and Expo",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"types": "lib/index.d.ts",
|
|
11
|
+
"react-native": "src/index.ts",
|
|
12
|
+
"source": "src/index.ts",
|
|
13
|
+
"app.plugin.js": "app.plugin.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"lib",
|
|
16
|
+
"src",
|
|
17
|
+
"android",
|
|
18
|
+
"ios",
|
|
19
|
+
"plugin/build",
|
|
20
|
+
"expo-module.config.json",
|
|
21
|
+
"react-native.config.js",
|
|
22
|
+
"app.plugin.js",
|
|
23
|
+
"react-native-ota-update.podspec",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.json && tsc -p plugin/tsconfig.json",
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p plugin/tsconfig.json --noEmit",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"react-native",
|
|
33
|
+
"ota",
|
|
34
|
+
"codepush",
|
|
35
|
+
"hot-update",
|
|
36
|
+
"expo"
|
|
37
|
+
],
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": ">=18.0.0",
|
|
40
|
+
"react-native": ">=0.71.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@expo/config-plugins": "^9.0.0",
|
|
44
|
+
"@types/react": "^18.3.18",
|
|
45
|
+
"react": "18.3.1",
|
|
46
|
+
"react-native": "0.76.6",
|
|
47
|
+
"typescript": "^5.7.3"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"expo": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
export interface OtaPluginOptions {
|
|
3
|
+
/** Server that serves updates, e.g. https://ota.example.com */
|
|
4
|
+
serverUrl: string;
|
|
5
|
+
/** Deployment key used on both platforms unless overridden below. */
|
|
6
|
+
deploymentKey?: string;
|
|
7
|
+
iosDeploymentKey?: string;
|
|
8
|
+
androidDeploymentKey?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: ConfigPlugin<OtaPluginOptions>;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
4
|
+
const PACKAGE_NAME = '@otaupdate/react-native';
|
|
5
|
+
function keysFor(options) {
|
|
6
|
+
const ios = options.iosDeploymentKey ?? options.deploymentKey;
|
|
7
|
+
const android = options.androidDeploymentKey ?? options.deploymentKey;
|
|
8
|
+
if (!ios || !android) {
|
|
9
|
+
throw new Error(`[${PACKAGE_NAME}] Missing deployment key. Provide "deploymentKey", or both ` +
|
|
10
|
+
'"iosDeploymentKey" and "androidDeploymentKey", in the plugin options.\n\n' +
|
|
11
|
+
' ["@otaupdate/react-native", { "serverUrl": "https://ota.example.com", ' +
|
|
12
|
+
'"iosDeploymentKey": "…", "androidDeploymentKey": "…" }]');
|
|
13
|
+
}
|
|
14
|
+
return { ios, android };
|
|
15
|
+
}
|
|
16
|
+
// --- iOS ---------------------------------------------------------------------
|
|
17
|
+
const withOtaInfoPlist = (config, options) => (0, config_plugins_1.withInfoPlist)(config, (mod) => {
|
|
18
|
+
mod.modResults.OtaDeploymentKey = keysFor(options).ios;
|
|
19
|
+
mod.modResults.OtaServerUrl = options.serverUrl;
|
|
20
|
+
return mod;
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Points React Native at the OTA bundle. Handles both AppDelegate flavours:
|
|
24
|
+
* Swift (Expo SDK 52+) and Objective-C++ (SDK 51 and earlier).
|
|
25
|
+
*/
|
|
26
|
+
const withOtaAppDelegate = (config) => (0, config_plugins_1.withAppDelegate)(config, (mod) => {
|
|
27
|
+
const { language } = mod.modResults;
|
|
28
|
+
let contents = mod.modResults.contents;
|
|
29
|
+
if (language === 'swift') {
|
|
30
|
+
if (!contents.includes('import OtaUpdate')) {
|
|
31
|
+
contents = contents.replace(/(import\s+React[^\n]*\n)/, `$1import OtaUpdate\n`);
|
|
32
|
+
if (!contents.includes('import OtaUpdate')) {
|
|
33
|
+
// Fall back to inserting after the first import of any kind.
|
|
34
|
+
contents = contents.replace(/^(import [^\n]+\n)/m, `$1import OtaUpdate\n`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!contents.includes('OtaUpdate.bundleURL()')) {
|
|
38
|
+
const replaced = contents.replace(/Bundle\.main\.url\(forResource:\s*"main",\s*withExtension:\s*"jsbundle"\)/g, 'OtaUpdate.bundleURL()');
|
|
39
|
+
if (replaced === contents) {
|
|
40
|
+
throw new Error(`[${PACKAGE_NAME}] Could not patch AppDelegate.swift — the release bundle lookup ` +
|
|
41
|
+
'was not found. Add `return OtaUpdate.bundleURL()` to bundleURL() manually.');
|
|
42
|
+
}
|
|
43
|
+
contents = replaced;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
if (!contents.includes('#import <OtaUpdate/OtaUpdate.h>')) {
|
|
48
|
+
contents = contents.replace(/(#import\s+"AppDelegate\.h"\n)/, `$1#import <OtaUpdate/OtaUpdate.h>\n`);
|
|
49
|
+
if (!contents.includes('#import <OtaUpdate/OtaUpdate.h>')) {
|
|
50
|
+
contents = `#import <OtaUpdate/OtaUpdate.h>\n${contents}`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!contents.includes('[OtaUpdate bundleURL]')) {
|
|
54
|
+
const replaced = contents.replace(/\[\[NSBundle mainBundle\] URLForResource:@"main" withExtension:@"jsbundle"\]/g, '[OtaUpdate bundleURL]');
|
|
55
|
+
if (replaced === contents) {
|
|
56
|
+
throw new Error(`[${PACKAGE_NAME}] Could not patch AppDelegate.mm — the release bundle lookup ` +
|
|
57
|
+
'was not found. Return `[OtaUpdate bundleURL]` from getBundleURL manually.');
|
|
58
|
+
}
|
|
59
|
+
contents = replaced;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
mod.modResults.contents = contents;
|
|
63
|
+
return mod;
|
|
64
|
+
});
|
|
65
|
+
// --- Android -----------------------------------------------------------------
|
|
66
|
+
const withOtaStrings = (config, options) => (0, config_plugins_1.withStringsXml)(config, (mod) => {
|
|
67
|
+
const { android } = keysFor(options);
|
|
68
|
+
mod.modResults = config_plugins_1.AndroidConfig.Strings.setStringItem([
|
|
69
|
+
// translatable=false keeps these out of localisation exports.
|
|
70
|
+
{ $: { name: 'ota_deployment_key', translatable: 'false' }, _: android },
|
|
71
|
+
{ $: { name: 'ota_server_url', translatable: 'false' }, _: options.serverUrl },
|
|
72
|
+
], mod.modResults);
|
|
73
|
+
return mod;
|
|
74
|
+
});
|
|
75
|
+
// Note: there is deliberately no MainApplication patch on Android.
|
|
76
|
+
//
|
|
77
|
+
// Expo apps are bridgeless — MainApplication builds a ReactHost directly from
|
|
78
|
+
// ExpoReactHostFactory and exposes no ReactNativeHost to override. The bundle
|
|
79
|
+
// path is instead supplied by OtaUpdateExpoPackage, which registers a
|
|
80
|
+
// ReactNativeHostHandler (Expo's own extension point, the same one
|
|
81
|
+
// expo-updates uses) and is picked up by Expo autolinking.
|
|
82
|
+
//
|
|
83
|
+
// Rewriting Kotlin source here would break every time the RN/Expo template
|
|
84
|
+
// changes — it already did, against the RN 0.86 template.
|
|
85
|
+
// --- Entry point --------------------------------------------------------------
|
|
86
|
+
const withOtaUpdate = (config, options) => {
|
|
87
|
+
if (!options?.serverUrl) {
|
|
88
|
+
throw new Error(`[${PACKAGE_NAME}] "serverUrl" is required.\n\n` +
|
|
89
|
+
' ["@otaupdate/react-native", { "serverUrl": "https://ota.example.com", "deploymentKey": "…" }]');
|
|
90
|
+
}
|
|
91
|
+
keysFor(options); // fail fast at config time rather than at build time
|
|
92
|
+
config = withOtaInfoPlist(config, options);
|
|
93
|
+
config = withOtaAppDelegate(config);
|
|
94
|
+
config = withOtaStrings(config, options);
|
|
95
|
+
return config;
|
|
96
|
+
};
|
|
97
|
+
exports.default = (0, config_plugins_1.createRunOncePlugin)(withOtaUpdate, PACKAGE_NAME, '1.0.0');
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "react-native-ota-update"
|
|
7
|
+
# module_name is what `import OtaUpdate` (Swift) and
|
|
8
|
+
# `#import <OtaUpdate/OtaUpdate.h>` (ObjC) resolve to in the host app.
|
|
9
|
+
s.module_name = "OtaUpdate"
|
|
10
|
+
s.header_dir = "OtaUpdate"
|
|
11
|
+
s.version = package["version"]
|
|
12
|
+
s.summary = package["description"]
|
|
13
|
+
s.license = package["license"]
|
|
14
|
+
s.authors = { "OTA Platform" => "noreply@example.com" }
|
|
15
|
+
s.homepage = "https://github.com/your-org/ota-platform"
|
|
16
|
+
s.platforms = { :ios => "13.4" }
|
|
17
|
+
s.source = { :git => "https://github.com/your-org/ota-platform.git", :tag => "v#{s.version}" }
|
|
18
|
+
|
|
19
|
+
s.source_files = "ios/**/*.{h,m,mm}"
|
|
20
|
+
s.public_header_files = "ios/OtaUpdate.h"
|
|
21
|
+
s.requires_arc = true
|
|
22
|
+
|
|
23
|
+
# Required for `import OtaUpdate` from a Swift AppDelegate.
|
|
24
|
+
#
|
|
25
|
+
# React Native and Expo build pods as static libraries by default, and an
|
|
26
|
+
# Objective-C static library is NOT importable as a Swift module unless
|
|
27
|
+
# CocoaPods emits a module map for it. DEFINES_MODULE makes it do that,
|
|
28
|
+
# generating `module OtaUpdate` from `module_name` above. Without this the
|
|
29
|
+
# host app fails to compile with "no such module 'OtaUpdate'" — even though
|
|
30
|
+
# the pod links fine and the ObjC side is completely healthy.
|
|
31
|
+
s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" }
|
|
32
|
+
|
|
33
|
+
# Unzipping the release package. SSZipArchive is the same dependency
|
|
34
|
+
# react-native-code-push uses, so most projects already resolve it cleanly.
|
|
35
|
+
s.dependency "SSZipArchive", "~> 2.4"
|
|
36
|
+
|
|
37
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
38
|
+
# RN >= 0.71 helper: wires up React-Core plus the new-architecture deps.
|
|
39
|
+
install_modules_dependencies(s)
|
|
40
|
+
else
|
|
41
|
+
s.dependency "React-Core"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// This package is linked by BOTH linkers, and needs to be:
|
|
2
|
+
//
|
|
3
|
+
// - React Native autolinking registers `OtaUpdatePackage`, the ReactPackage
|
|
4
|
+
// that exposes the `OtaUpdate` native module to JS.
|
|
5
|
+
// - Expo autolinking registers `OtaUpdateExpoPackage`, which supplies the
|
|
6
|
+
// downloaded bundle path via `ReactNativeHostHandler`.
|
|
7
|
+
//
|
|
8
|
+
// Expo's resolver deliberately drops a package from React Native autolinking
|
|
9
|
+
// when it is *also* an Expo module with its own Gradle file and no explicit
|
|
10
|
+
// React Native config — the two would otherwise race to link the same Gradle
|
|
11
|
+
// project. Declaring the config here opts out of that skip, so the native
|
|
12
|
+
// module still reaches JS. Without this file, `NativeModules.OtaUpdate` is
|
|
13
|
+
// undefined in Expo apps and every SDK call throws the linking error.
|
|
14
|
+
module.exports = {
|
|
15
|
+
dependency: {
|
|
16
|
+
platforms: {
|
|
17
|
+
android: {},
|
|
18
|
+
ios: {},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|