@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
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { checkForUpdate, sync } from './OtaUpdate';
|
|
3
|
+
import {
|
|
4
|
+
InstallMode,
|
|
5
|
+
SyncStatus,
|
|
6
|
+
type DownloadProgress,
|
|
7
|
+
type RemotePackage,
|
|
8
|
+
type SyncOptions,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
export interface UseOtaUpdateState {
|
|
12
|
+
status: SyncStatus;
|
|
13
|
+
progress: DownloadProgress | null;
|
|
14
|
+
/** Populated when a check found an update that has not been installed yet. */
|
|
15
|
+
available: RemotePackage | null;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
isSyncing: boolean;
|
|
18
|
+
check(): Promise<void>;
|
|
19
|
+
update(options?: SyncOptions): Promise<SyncStatus>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Hook for update UI — a "New version available" banner, a download progress
|
|
24
|
+
* bar, or a settings screen with a manual "Check for updates" button.
|
|
25
|
+
*/
|
|
26
|
+
export function useOtaUpdate(defaultOptions: SyncOptions = {}): UseOtaUpdateState {
|
|
27
|
+
const [status, setStatus] = useState<SyncStatus>(SyncStatus.UP_TO_DATE);
|
|
28
|
+
const [progress, setProgress] = useState<DownloadProgress | null>(null);
|
|
29
|
+
const [available, setAvailable] = useState<RemotePackage | null>(null);
|
|
30
|
+
const [error, setError] = useState<Error | null>(null);
|
|
31
|
+
const mounted = useRef(true);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
mounted.current = true;
|
|
35
|
+
return () => {
|
|
36
|
+
mounted.current = false;
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
const check = useCallback(async () => {
|
|
41
|
+
try {
|
|
42
|
+
setError(null);
|
|
43
|
+
setStatus(SyncStatus.CHECKING_FOR_UPDATE);
|
|
44
|
+
const result = await checkForUpdate(defaultOptions.deploymentKey);
|
|
45
|
+
if (!mounted.current) return;
|
|
46
|
+
setAvailable(result.update);
|
|
47
|
+
setStatus(result.update ? SyncStatus.AWAITING_USER_ACTION : SyncStatus.UP_TO_DATE);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
if (!mounted.current) return;
|
|
50
|
+
setError(err as Error);
|
|
51
|
+
setStatus(SyncStatus.UNKNOWN_ERROR);
|
|
52
|
+
}
|
|
53
|
+
// defaultOptions is intentionally read fresh on each call rather than
|
|
54
|
+
// captured as a dependency — callers routinely pass an inline object.
|
|
55
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
56
|
+
}, [defaultOptions.deploymentKey]);
|
|
57
|
+
|
|
58
|
+
const update = useCallback(
|
|
59
|
+
async (options: SyncOptions = {}) => {
|
|
60
|
+
setError(null);
|
|
61
|
+
const result = await sync({
|
|
62
|
+
installMode: InstallMode.ON_NEXT_RESTART,
|
|
63
|
+
...defaultOptions,
|
|
64
|
+
...options,
|
|
65
|
+
onSyncStatusChange: (s) => {
|
|
66
|
+
if (mounted.current) setStatus(s);
|
|
67
|
+
defaultOptions.onSyncStatusChange?.(s);
|
|
68
|
+
options.onSyncStatusChange?.(s);
|
|
69
|
+
},
|
|
70
|
+
onDownloadProgress: (p) => {
|
|
71
|
+
if (mounted.current) setProgress(p);
|
|
72
|
+
defaultOptions.onDownloadProgress?.(p);
|
|
73
|
+
options.onDownloadProgress?.(p);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
if (mounted.current && result === SyncStatus.UPDATE_INSTALLED) setAvailable(null);
|
|
77
|
+
return result;
|
|
78
|
+
},
|
|
79
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
80
|
+
[],
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
status,
|
|
85
|
+
progress,
|
|
86
|
+
available,
|
|
87
|
+
error,
|
|
88
|
+
isSyncing:
|
|
89
|
+
status === SyncStatus.CHECKING_FOR_UPDATE ||
|
|
90
|
+
status === SyncStatus.DOWNLOADING_PACKAGE ||
|
|
91
|
+
status === SyncStatus.INSTALLING_UPDATE ||
|
|
92
|
+
status === SyncStatus.SYNC_IN_PROGRESS,
|
|
93
|
+
check,
|
|
94
|
+
update,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { startAutoSync } from './OtaUpdate';
|
|
3
|
+
import type { OtaOptions } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wraps the root component so updates are checked on start and on resume, and
|
|
7
|
+
* the running bundle is confirmed (rollback-protection) as soon as it mounts.
|
|
8
|
+
*
|
|
9
|
+
* export default withOtaUpdate(App, { sync: { installMode: InstallMode.ON_NEXT_RESUME } })
|
|
10
|
+
*/
|
|
11
|
+
export function withOtaUpdate<P extends object>(
|
|
12
|
+
Component: React.ComponentType<P>,
|
|
13
|
+
options: OtaOptions = {},
|
|
14
|
+
): React.ComponentType<P> {
|
|
15
|
+
const Wrapped: React.FC<P> = (props) => {
|
|
16
|
+
useEffect(() => startAutoSync(options), []);
|
|
17
|
+
return <Component {...props} />;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
Wrapped.displayName = `withOtaUpdate(${Component.displayName ?? Component.name ?? 'Component'})`;
|
|
21
|
+
return Wrapped;
|
|
22
|
+
}
|