@vanikya/ota-react-native 0.1.5 → 0.1.7
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 +47 -3
- package/lib/commonjs/hooks/useOTAUpdate.js +25 -8
- package/lib/commonjs/hooks/useOTAUpdate.js.map +1 -1
- package/lib/commonjs/utils/storage.js +90 -8
- package/lib/commonjs/utils/storage.js.map +1 -1
- package/lib/commonjs/utils/verification.js +6 -8
- package/lib/commonjs/utils/verification.js.map +1 -1
- package/lib/module/hooks/useOTAUpdate.js +26 -9
- package/lib/module/hooks/useOTAUpdate.js.map +1 -1
- package/lib/module/utils/storage.js +90 -8
- package/lib/module/utils/storage.js.map +1 -1
- package/lib/module/utils/verification.js +6 -8
- package/lib/module/utils/verification.js.map +1 -1
- package/lib/typescript/hooks/useOTAUpdate.d.ts.map +1 -1
- package/lib/typescript/utils/storage.d.ts +19 -0
- package/lib/typescript/utils/storage.d.ts.map +1 -1
- package/lib/typescript/utils/verification.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/hooks/useOTAUpdate.ts +28 -10
- package/src/utils/storage.ts +90 -8
- package/src/utils/verification.ts +10 -11
package/README.md
CHANGED
|
@@ -12,14 +12,36 @@ Works with both **Expo** and **bare React Native** apps.
|
|
|
12
12
|
npm install @vanikya/ota-react-native
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
### For Expo apps
|
|
15
|
+
### For Expo apps (EAS Build)
|
|
16
16
|
|
|
17
|
-
Install Expo dependencies:
|
|
17
|
+
1. Install Expo dependencies:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
npx expo install expo-file-system expo-crypto
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
2. Add the config plugin to your `app.json` or `app.config.js`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"expo": {
|
|
28
|
+
"plugins": [
|
|
29
|
+
"@vanikya/ota-react-native"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Rebuild your app with EAS Build:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
eas build --platform android
|
|
39
|
+
# or
|
|
40
|
+
eas build --platform ios
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> **Important**: OTA updates require a native build with EAS Build. They will NOT work in Expo Go because the plugin modifies native code to load custom bundles.
|
|
44
|
+
|
|
23
45
|
### For bare React Native apps
|
|
24
46
|
|
|
25
47
|
Install pods (iOS):
|
|
@@ -34,6 +56,7 @@ cd ios && pod install
|
|
|
34
56
|
|
|
35
57
|
```tsx
|
|
36
58
|
import { OTAProvider } from '@vanikya/ota-react-native';
|
|
59
|
+
import Constants from 'expo-constants';
|
|
37
60
|
|
|
38
61
|
export default function App() {
|
|
39
62
|
return (
|
|
@@ -42,6 +65,7 @@ export default function App() {
|
|
|
42
65
|
serverUrl: 'https://your-server.workers.dev',
|
|
43
66
|
appSlug: 'my-app',
|
|
44
67
|
channel: 'production',
|
|
68
|
+
appVersion: Constants.expoConfig?.version || '1.0.0',
|
|
45
69
|
// Optional: public key for signature verification
|
|
46
70
|
publicKey: 'your-public-key-hex',
|
|
47
71
|
}}
|
|
@@ -99,10 +123,11 @@ function UpdateChecker() {
|
|
|
99
123
|
|------|------|----------|-------------|
|
|
100
124
|
| `config.serverUrl` | string | Yes | Your OTA server URL |
|
|
101
125
|
| `config.appSlug` | string | Yes | Your app's slug |
|
|
126
|
+
| `config.appVersion` | string | Yes | Your native app version (e.g., "1.0.0") |
|
|
102
127
|
| `config.channel` | string | No | Release channel (default: 'production') |
|
|
103
128
|
| `config.publicKey` | string | No | Ed25519 public key for signature verification |
|
|
104
129
|
| `config.checkOnMount` | boolean | No | Auto-check for updates on mount |
|
|
105
|
-
| `config.
|
|
130
|
+
| `config.checkOnForeground` | boolean | No | Auto-check when app comes to foreground |
|
|
106
131
|
|
|
107
132
|
### useOTAUpdate Hook
|
|
108
133
|
|
|
@@ -220,6 +245,25 @@ This SDK requires a backend server. See the [main repository](https://github.com
|
|
|
220
245
|
|
|
221
246
|
Updates are stored locally, so the app works offline after the first download.
|
|
222
247
|
|
|
248
|
+
### How Expo Plugin Works
|
|
249
|
+
|
|
250
|
+
For Expo apps built with EAS Build, the config plugin modifies the native code to enable OTA updates:
|
|
251
|
+
|
|
252
|
+
**Android** (`MainApplication.kt`):
|
|
253
|
+
- Overrides `getJSBundleFile()` to check SharedPreferences for a downloaded bundle path
|
|
254
|
+
- If a valid bundle exists, it loads that instead of the built-in bundle
|
|
255
|
+
|
|
256
|
+
**iOS** (`AppDelegate.swift`):
|
|
257
|
+
- Modifies `bundleURL()` to check UserDefaults for a downloaded bundle path
|
|
258
|
+
- If a valid bundle exists, it returns that URL instead of the built-in bundle
|
|
259
|
+
|
|
260
|
+
When you call `applyUpdate()` or the download completes:
|
|
261
|
+
1. The bundle is saved to the device's document directory
|
|
262
|
+
2. The path is registered with native storage (SharedPreferences/UserDefaults)
|
|
263
|
+
3. On the next app restart, the native code loads the OTA bundle
|
|
264
|
+
|
|
265
|
+
> **Note**: OTA updates only work on EAS Build apps, not Expo Go, because Expo Go doesn't include the native module.
|
|
266
|
+
|
|
223
267
|
## License
|
|
224
268
|
|
|
225
269
|
MIT
|
|
@@ -9,7 +9,6 @@ var _reactNative = require("react-native");
|
|
|
9
9
|
var _api = require("../utils/api");
|
|
10
10
|
var _storage = require("../utils/storage");
|
|
11
11
|
var _verification = require("../utils/verification");
|
|
12
|
-
const OTAUpdateNative = _reactNative.NativeModules.OTAUpdate;
|
|
13
12
|
// Generate or get device ID
|
|
14
13
|
async function getDeviceId() {
|
|
15
14
|
// Try to get from native module or AsyncStorage
|
|
@@ -146,6 +145,17 @@ function useOTAUpdate(config) {
|
|
|
146
145
|
bundleHash: release.bundleHash,
|
|
147
146
|
downloadedAt: Date.now()
|
|
148
147
|
});
|
|
148
|
+
|
|
149
|
+
// Register the bundle path with native module (for next app restart)
|
|
150
|
+
// This saves to SharedPreferences (Android) / UserDefaults (iOS)
|
|
151
|
+
const registered = await storage.current.registerBundleWithNative(bundlePath, false);
|
|
152
|
+
if (__DEV__) {
|
|
153
|
+
if (registered) {
|
|
154
|
+
console.log('[OTAUpdate] Bundle registered with native module. Will apply on app restart.');
|
|
155
|
+
} else {
|
|
156
|
+
console.log('[OTAUpdate] Could not register with native module. If using Expo Go, this is expected.');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
149
159
|
setStatus('ready');
|
|
150
160
|
} catch (err) {
|
|
151
161
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -186,14 +196,18 @@ function useOTAUpdate(config) {
|
|
|
186
196
|
deviceInfo: (0, _api.getDeviceInfo)()
|
|
187
197
|
});
|
|
188
198
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
//
|
|
194
|
-
// The bundle will be loaded on next app start
|
|
199
|
+
// Register bundle path with native module and optionally restart
|
|
200
|
+
// This ensures the path is saved to SharedPreferences/UserDefaults
|
|
201
|
+
const registered = await storage.current.registerBundleWithNative(metadata.bundlePath, restartApp);
|
|
202
|
+
if (!registered && restartApp) {
|
|
203
|
+
// Native module not available
|
|
195
204
|
if (__DEV__) {
|
|
196
|
-
console.log('[OTAUpdate] Update ready.
|
|
205
|
+
console.log('[OTAUpdate] Update ready. Close and reopen the app to apply the update.');
|
|
206
|
+
console.log('[OTAUpdate] Note: For Expo Go, OTA updates require a native build (EAS Build).');
|
|
207
|
+
}
|
|
208
|
+
} else if (registered && !restartApp) {
|
|
209
|
+
if (__DEV__) {
|
|
210
|
+
console.log('[OTAUpdate] Update registered. Will apply on next app restart.');
|
|
197
211
|
}
|
|
198
212
|
}
|
|
199
213
|
|
|
@@ -232,6 +246,9 @@ function useOTAUpdate(config) {
|
|
|
232
246
|
await storage.current.deleteBundle(metadata.releaseId);
|
|
233
247
|
await storage.current.clearMetadata();
|
|
234
248
|
}
|
|
249
|
+
|
|
250
|
+
// Also clear from native storage (SharedPreferences/UserDefaults)
|
|
251
|
+
await storage.current.clearNativePendingBundle();
|
|
235
252
|
setUpdateInfo(null);
|
|
236
253
|
releaseRef.current = null;
|
|
237
254
|
setStatus('idle');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_reactNative","_api","_storage","_verification","
|
|
1
|
+
{"version":3,"names":["_react","require","_reactNative","_api","_storage","_verification","getDeviceId","id","Math","random","toString","substring","useOTAUpdate","config","serverUrl","appSlug","channel","appVersion","publicKey","checkOnMount","checkOnForeground","status","setStatus","useState","updateInfo","setUpdateInfo","downloadProgress","setDownloadProgress","error","setError","currentVersion","setCurrentVersion","apiClient","useRef","OTAApiClient","storage","UpdateStorage","deviceIdRef","releaseRef","useEffect","loadCurrentVersion","metadata","current","getMetadata","version","getDeviceIdCached","useCallback","checkForUpdate","deviceId","currentMetadata","response","checkUpdate","platform","Platform","OS","updateAvailable","release","info","releaseId","bundleSize","isMandatory","releaseNotes","err","Error","String","downloadUpdate","downloadedBytes","totalBytes","percentage","reportEvent","eventType","deviceInfo","getDeviceInfo","bundleData","downloadBundle","bundleUrl","byteLength","verification","verifyBundle","bundleHash","bundleSignature","valid","bundlePath","saveBundle","saveMetadata","downloadedAt","Date","now","registered","registerBundleWithNative","__DEV__","console","log","errorMessage","message","applyUpdate","restartApp","clearPendingUpdate","deleteBundle","clearMetadata","clearNativePendingBundle","handleAppStateChange","nextAppState","subscription","AppState","addEventListener","remove"],"sourceRoot":"../../../src","sources":["hooks/useOTAUpdate.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -8,12 +8,27 @@ exports.getStorageAdapter = getStorageAdapter;
|
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
// Types
|
|
10
10
|
|
|
11
|
+
// Helper to normalize file paths (remove file:// prefix)
|
|
12
|
+
function normalizePath(path) {
|
|
13
|
+
if (path.startsWith('file://')) {
|
|
14
|
+
return path.slice(7);
|
|
15
|
+
}
|
|
16
|
+
return path;
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
// Try to use Expo FileSystem if available
|
|
20
|
+
// Use legacy API to avoid deprecation warnings in expo-file-system v54+
|
|
12
21
|
let ExpoFileSystem = null;
|
|
13
22
|
try {
|
|
14
|
-
|
|
23
|
+
// Try legacy import first (expo-file-system v54+)
|
|
24
|
+
ExpoFileSystem = require('expo-file-system/legacy');
|
|
15
25
|
} catch {
|
|
16
|
-
|
|
26
|
+
try {
|
|
27
|
+
// Fallback to regular import for older versions
|
|
28
|
+
ExpoFileSystem = require('expo-file-system');
|
|
29
|
+
} catch {
|
|
30
|
+
// Expo not available, will use native module
|
|
31
|
+
}
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
// Native module for bare React Native
|
|
@@ -147,7 +162,10 @@ function getStorageAdapter() {
|
|
|
147
162
|
class UpdateStorage {
|
|
148
163
|
constructor() {
|
|
149
164
|
this.storage = getStorageAdapter();
|
|
165
|
+
this.isExpo = !!ExpoFileSystem;
|
|
150
166
|
this.baseDir = `${this.storage.getDocumentDirectory()}ota-update/`;
|
|
167
|
+
// Keep a normalized version for native module calls
|
|
168
|
+
this.baseDirNormalized = normalizePath(this.baseDir);
|
|
151
169
|
}
|
|
152
170
|
async ensureDirectory() {
|
|
153
171
|
const exists = await this.storage.exists(this.baseDir);
|
|
@@ -155,24 +173,40 @@ class UpdateStorage {
|
|
|
155
173
|
await this.storage.makeDirectory(this.baseDir);
|
|
156
174
|
}
|
|
157
175
|
}
|
|
176
|
+
|
|
177
|
+
// Get normalized path (without file:// prefix) for native module compatibility
|
|
178
|
+
getNormalizedPath(path) {
|
|
179
|
+
return normalizePath(path);
|
|
180
|
+
}
|
|
158
181
|
async saveBundle(releaseId, data) {
|
|
159
182
|
await this.ensureDirectory();
|
|
160
183
|
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
161
184
|
await this.storage.writeFile(bundlePath, data);
|
|
162
|
-
|
|
185
|
+
|
|
186
|
+
// Return normalized path for native module compatibility
|
|
187
|
+
return normalizePath(bundlePath);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Get the raw bundle path (with file:// for Expo) - for internal storage operations
|
|
191
|
+
getRawBundlePath(releaseId) {
|
|
192
|
+
return `${this.baseDir}${releaseId}.bundle`;
|
|
163
193
|
}
|
|
164
194
|
async getBundlePath(releaseId) {
|
|
165
|
-
const bundlePath =
|
|
195
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
166
196
|
const exists = await this.storage.exists(bundlePath);
|
|
167
|
-
|
|
197
|
+
// Return normalized path for native module compatibility
|
|
198
|
+
return exists ? normalizePath(bundlePath) : null;
|
|
168
199
|
}
|
|
169
200
|
async readBundle(releaseId) {
|
|
170
|
-
const bundlePath =
|
|
171
|
-
|
|
201
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
202
|
+
const exists = await this.storage.exists(bundlePath);
|
|
203
|
+
if (!exists) return null;
|
|
204
|
+
|
|
205
|
+
// Use raw path for storage operations (expo needs file:// prefix)
|
|
172
206
|
return this.storage.readFileAsBuffer(bundlePath);
|
|
173
207
|
}
|
|
174
208
|
async deleteBundle(releaseId) {
|
|
175
|
-
const bundlePath =
|
|
209
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
176
210
|
if (await this.storage.exists(bundlePath)) {
|
|
177
211
|
await this.storage.deleteFile(bundlePath);
|
|
178
212
|
}
|
|
@@ -204,6 +238,54 @@ class UpdateStorage {
|
|
|
204
238
|
// For now, we just keep one bundle at a time
|
|
205
239
|
// In a more advanced implementation, we might keep a few for rollback
|
|
206
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Register the bundle path with the native module.
|
|
244
|
+
* This saves the path to SharedPreferences (Android) or UserDefaults (iOS)
|
|
245
|
+
* so the app can load the OTA bundle on restart.
|
|
246
|
+
*
|
|
247
|
+
* @param bundlePath The normalized path to the bundle file
|
|
248
|
+
* @param restart Whether to restart the app immediately
|
|
249
|
+
* @returns true if successfully registered with native module, false otherwise
|
|
250
|
+
*/
|
|
251
|
+
async registerBundleWithNative(bundlePath, restart = false) {
|
|
252
|
+
try {
|
|
253
|
+
if (OTAUpdateNative?.applyBundle) {
|
|
254
|
+
// Ensure path is normalized before passing to native module
|
|
255
|
+
const normalizedPath = normalizePath(bundlePath);
|
|
256
|
+
await OTAUpdateNative.applyBundle(normalizedPath, restart);
|
|
257
|
+
return true;
|
|
258
|
+
} else {
|
|
259
|
+
// Native module not available - this is expected for Expo Go
|
|
260
|
+
// but should work for EAS Build apps
|
|
261
|
+
if (__DEV__) {
|
|
262
|
+
console.log('[OTAUpdate] Native module not available. Update will apply on next build with native modules.');
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (__DEV__) {
|
|
268
|
+
console.error('[OTAUpdate] Failed to register bundle with native module:', error);
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Clear the pending bundle from native storage.
|
|
276
|
+
* This removes the bundle path from SharedPreferences (Android) or UserDefaults (iOS).
|
|
277
|
+
*/
|
|
278
|
+
async clearNativePendingBundle() {
|
|
279
|
+
try {
|
|
280
|
+
if (OTAUpdateNative?.clearPendingBundle) {
|
|
281
|
+
await OTAUpdateNative.clearPendingBundle();
|
|
282
|
+
}
|
|
283
|
+
} catch (error) {
|
|
284
|
+
if (__DEV__) {
|
|
285
|
+
console.error('[OTAUpdate] Failed to clear pending bundle:', error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
207
289
|
}
|
|
208
290
|
exports.UpdateStorage = UpdateStorage;
|
|
209
291
|
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","ExpoFileSystem","OTAUpdateNative","NativeModules","OTAUpdate","ExpoStorageAdapter","getDocumentDirectory","documentDirectory","writeFile","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","normalizePath","path","startsWith","slice","ExpoFileSystem","OTAUpdateNative","NativeModules","OTAUpdate","ExpoStorageAdapter","getDocumentDirectory","documentDirectory","writeFile","data","ArrayBuffer","bytes","Uint8Array","binary","i","length","String","fromCharCode","base64","btoa","writeAsStringAsync","encoding","EncodingType","Base64","readFile","readAsStringAsync","readFileAsBuffer","atob","charCodeAt","buffer","deleteFile","deleteAsync","idempotent","exists","info","getInfoAsync","makeDirectory","makeDirectoryAsync","intermediates","NativeStorageAdapter","Error","writeFileBase64","readFileBase64","getStorageAdapter","UpdateStorage","constructor","storage","isExpo","baseDir","baseDirNormalized","ensureDirectory","getNormalizedPath","saveBundle","releaseId","bundlePath","getRawBundlePath","getBundlePath","readBundle","deleteBundle","saveMetadata","update","metadataPath","JSON","stringify","getMetadata","content","parse","clearMetadata","cleanOldBundles","keepReleaseId","registerBundleWithNative","restart","applyBundle","normalizedPath","__DEV__","console","log","error","clearNativePendingBundle","clearPendingBundle","exports"],"sourceRoot":"../../../src","sources":["utils/storage.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -34,15 +34,8 @@ function hexToBytes(hex) {
|
|
|
34
34
|
|
|
35
35
|
// Calculate SHA-256 hash of data
|
|
36
36
|
async function calculateHash(data) {
|
|
37
|
-
|
|
38
|
-
// Use Expo Crypto
|
|
39
|
-
const hash = await ExpoCrypto.digestStringAsync(ExpoCrypto.CryptoDigestAlgorithm.SHA256, bufferToHex(data), {
|
|
40
|
-
encoding: ExpoCrypto.CryptoEncoding.HEX
|
|
41
|
-
});
|
|
42
|
-
return 'sha256:' + hash;
|
|
43
|
-
}
|
|
37
|
+
// Use native module first (most reliable for binary data)
|
|
44
38
|
if (OTAUpdateNative?.calculateSHA256) {
|
|
45
|
-
// Use native module
|
|
46
39
|
const bytes = new Uint8Array(data);
|
|
47
40
|
let binary = '';
|
|
48
41
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -52,6 +45,11 @@ async function calculateHash(data) {
|
|
|
52
45
|
const hash = await OTAUpdateNative.calculateSHA256(base64);
|
|
53
46
|
return 'sha256:' + hash;
|
|
54
47
|
}
|
|
48
|
+
if (ExpoCrypto?.digest) {
|
|
49
|
+
// Use Expo Crypto digest (takes Uint8Array, returns ArrayBuffer)
|
|
50
|
+
const hashBuffer = await ExpoCrypto.digest(ExpoCrypto.CryptoDigestAlgorithm.SHA256, new Uint8Array(data));
|
|
51
|
+
return 'sha256:' + bufferToHex(hashBuffer);
|
|
52
|
+
}
|
|
55
53
|
|
|
56
54
|
// Fallback: Use SubtleCrypto (not available in all RN environments)
|
|
57
55
|
if (typeof crypto !== 'undefined' && crypto.subtle) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","ExpoCrypto","OTAUpdateNative","NativeModules","OTAUpdate","bufferToHex","buffer","bytes","Uint8Array","Array","from","map","b","toString","padStart","join","hexToBytes","hex","length","i","parseInt","substr","calculateHash","data","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","ExpoCrypto","OTAUpdateNative","NativeModules","OTAUpdate","bufferToHex","buffer","bytes","Uint8Array","Array","from","map","b","toString","padStart","join","hexToBytes","hex","length","i","parseInt","substr","calculateHash","data","calculateSHA256","binary","String","fromCharCode","base64","btoa","hash","digest","hashBuffer","CryptoDigestAlgorithm","SHA256","crypto","subtle","Error","verifyBundleHash","expectedHash","actualHash","verifySignature","signatureHex","publicKeyHex","__DEV__","console","warn","verifyBundle","signature","publicKey","hashValid","error","valid","signatureValid"],"sourceRoot":"../../../src","sources":["utils/verification.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
-
import { AppState,
|
|
2
|
+
import { AppState, Platform } from 'react-native';
|
|
3
3
|
import { OTAApiClient, getDeviceInfo } from '../utils/api';
|
|
4
4
|
import { UpdateStorage } from '../utils/storage';
|
|
5
5
|
import { verifyBundle } from '../utils/verification';
|
|
6
|
-
const OTAUpdateNative = NativeModules.OTAUpdate;
|
|
7
6
|
// Generate or get device ID
|
|
8
7
|
async function getDeviceId() {
|
|
9
8
|
// Try to get from native module or AsyncStorage
|
|
@@ -140,6 +139,17 @@ export function useOTAUpdate(config) {
|
|
|
140
139
|
bundleHash: release.bundleHash,
|
|
141
140
|
downloadedAt: Date.now()
|
|
142
141
|
});
|
|
142
|
+
|
|
143
|
+
// Register the bundle path with native module (for next app restart)
|
|
144
|
+
// This saves to SharedPreferences (Android) / UserDefaults (iOS)
|
|
145
|
+
const registered = await storage.current.registerBundleWithNative(bundlePath, false);
|
|
146
|
+
if (__DEV__) {
|
|
147
|
+
if (registered) {
|
|
148
|
+
console.log('[OTAUpdate] Bundle registered with native module. Will apply on app restart.');
|
|
149
|
+
} else {
|
|
150
|
+
console.log('[OTAUpdate] Could not register with native module. If using Expo Go, this is expected.');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
143
153
|
setStatus('ready');
|
|
144
154
|
} catch (err) {
|
|
145
155
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -180,14 +190,18 @@ export function useOTAUpdate(config) {
|
|
|
180
190
|
deviceInfo: getDeviceInfo()
|
|
181
191
|
});
|
|
182
192
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
//
|
|
188
|
-
// The bundle will be loaded on next app start
|
|
193
|
+
// Register bundle path with native module and optionally restart
|
|
194
|
+
// This ensures the path is saved to SharedPreferences/UserDefaults
|
|
195
|
+
const registered = await storage.current.registerBundleWithNative(metadata.bundlePath, restartApp);
|
|
196
|
+
if (!registered && restartApp) {
|
|
197
|
+
// Native module not available
|
|
189
198
|
if (__DEV__) {
|
|
190
|
-
console.log('[OTAUpdate] Update ready.
|
|
199
|
+
console.log('[OTAUpdate] Update ready. Close and reopen the app to apply the update.');
|
|
200
|
+
console.log('[OTAUpdate] Note: For Expo Go, OTA updates require a native build (EAS Build).');
|
|
201
|
+
}
|
|
202
|
+
} else if (registered && !restartApp) {
|
|
203
|
+
if (__DEV__) {
|
|
204
|
+
console.log('[OTAUpdate] Update registered. Will apply on next app restart.');
|
|
191
205
|
}
|
|
192
206
|
}
|
|
193
207
|
|
|
@@ -226,6 +240,9 @@ export function useOTAUpdate(config) {
|
|
|
226
240
|
await storage.current.deleteBundle(metadata.releaseId);
|
|
227
241
|
await storage.current.clearMetadata();
|
|
228
242
|
}
|
|
243
|
+
|
|
244
|
+
// Also clear from native storage (SharedPreferences/UserDefaults)
|
|
245
|
+
await storage.current.clearNativePendingBundle();
|
|
229
246
|
setUpdateInfo(null);
|
|
230
247
|
releaseRef.current = null;
|
|
231
248
|
setStatus('idle');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useState","useCallback","useEffect","useRef","AppState","
|
|
1
|
+
{"version":3,"names":["useState","useCallback","useEffect","useRef","AppState","Platform","OTAApiClient","getDeviceInfo","UpdateStorage","verifyBundle","getDeviceId","id","Math","random","toString","substring","useOTAUpdate","config","serverUrl","appSlug","channel","appVersion","publicKey","checkOnMount","checkOnForeground","status","setStatus","updateInfo","setUpdateInfo","downloadProgress","setDownloadProgress","error","setError","currentVersion","setCurrentVersion","apiClient","storage","deviceIdRef","releaseRef","loadCurrentVersion","metadata","current","getMetadata","version","getDeviceIdCached","checkForUpdate","deviceId","currentMetadata","response","checkUpdate","platform","OS","updateAvailable","release","info","releaseId","bundleSize","isMandatory","releaseNotes","err","Error","String","downloadUpdate","downloadedBytes","totalBytes","percentage","reportEvent","eventType","deviceInfo","bundleData","downloadBundle","bundleUrl","byteLength","verification","bundleHash","bundleSignature","valid","bundlePath","saveBundle","saveMetadata","downloadedAt","Date","now","registered","registerBundleWithNative","__DEV__","console","log","errorMessage","message","applyUpdate","restartApp","clearPendingUpdate","deleteBundle","clearMetadata","clearNativePendingBundle","handleAppStateChange","nextAppState","subscription","addEventListener","remove"],"sourceRoot":"../../../src","sources":["hooks/useOTAUpdate.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -2,12 +2,27 @@ import { NativeModules } from 'react-native';
|
|
|
2
2
|
|
|
3
3
|
// Types
|
|
4
4
|
|
|
5
|
+
// Helper to normalize file paths (remove file:// prefix)
|
|
6
|
+
function normalizePath(path) {
|
|
7
|
+
if (path.startsWith('file://')) {
|
|
8
|
+
return path.slice(7);
|
|
9
|
+
}
|
|
10
|
+
return path;
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
// Try to use Expo FileSystem if available
|
|
14
|
+
// Use legacy API to avoid deprecation warnings in expo-file-system v54+
|
|
6
15
|
let ExpoFileSystem = null;
|
|
7
16
|
try {
|
|
8
|
-
|
|
17
|
+
// Try legacy import first (expo-file-system v54+)
|
|
18
|
+
ExpoFileSystem = require('expo-file-system/legacy');
|
|
9
19
|
} catch {
|
|
10
|
-
|
|
20
|
+
try {
|
|
21
|
+
// Fallback to regular import for older versions
|
|
22
|
+
ExpoFileSystem = require('expo-file-system');
|
|
23
|
+
} catch {
|
|
24
|
+
// Expo not available, will use native module
|
|
25
|
+
}
|
|
11
26
|
}
|
|
12
27
|
|
|
13
28
|
// Native module for bare React Native
|
|
@@ -141,7 +156,10 @@ export function getStorageAdapter() {
|
|
|
141
156
|
export class UpdateStorage {
|
|
142
157
|
constructor() {
|
|
143
158
|
this.storage = getStorageAdapter();
|
|
159
|
+
this.isExpo = !!ExpoFileSystem;
|
|
144
160
|
this.baseDir = `${this.storage.getDocumentDirectory()}ota-update/`;
|
|
161
|
+
// Keep a normalized version for native module calls
|
|
162
|
+
this.baseDirNormalized = normalizePath(this.baseDir);
|
|
145
163
|
}
|
|
146
164
|
async ensureDirectory() {
|
|
147
165
|
const exists = await this.storage.exists(this.baseDir);
|
|
@@ -149,24 +167,40 @@ export class UpdateStorage {
|
|
|
149
167
|
await this.storage.makeDirectory(this.baseDir);
|
|
150
168
|
}
|
|
151
169
|
}
|
|
170
|
+
|
|
171
|
+
// Get normalized path (without file:// prefix) for native module compatibility
|
|
172
|
+
getNormalizedPath(path) {
|
|
173
|
+
return normalizePath(path);
|
|
174
|
+
}
|
|
152
175
|
async saveBundle(releaseId, data) {
|
|
153
176
|
await this.ensureDirectory();
|
|
154
177
|
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
155
178
|
await this.storage.writeFile(bundlePath, data);
|
|
156
|
-
|
|
179
|
+
|
|
180
|
+
// Return normalized path for native module compatibility
|
|
181
|
+
return normalizePath(bundlePath);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Get the raw bundle path (with file:// for Expo) - for internal storage operations
|
|
185
|
+
getRawBundlePath(releaseId) {
|
|
186
|
+
return `${this.baseDir}${releaseId}.bundle`;
|
|
157
187
|
}
|
|
158
188
|
async getBundlePath(releaseId) {
|
|
159
|
-
const bundlePath =
|
|
189
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
160
190
|
const exists = await this.storage.exists(bundlePath);
|
|
161
|
-
|
|
191
|
+
// Return normalized path for native module compatibility
|
|
192
|
+
return exists ? normalizePath(bundlePath) : null;
|
|
162
193
|
}
|
|
163
194
|
async readBundle(releaseId) {
|
|
164
|
-
const bundlePath =
|
|
165
|
-
|
|
195
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
196
|
+
const exists = await this.storage.exists(bundlePath);
|
|
197
|
+
if (!exists) return null;
|
|
198
|
+
|
|
199
|
+
// Use raw path for storage operations (expo needs file:// prefix)
|
|
166
200
|
return this.storage.readFileAsBuffer(bundlePath);
|
|
167
201
|
}
|
|
168
202
|
async deleteBundle(releaseId) {
|
|
169
|
-
const bundlePath =
|
|
203
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
170
204
|
if (await this.storage.exists(bundlePath)) {
|
|
171
205
|
await this.storage.deleteFile(bundlePath);
|
|
172
206
|
}
|
|
@@ -198,5 +232,53 @@ export class UpdateStorage {
|
|
|
198
232
|
// For now, we just keep one bundle at a time
|
|
199
233
|
// In a more advanced implementation, we might keep a few for rollback
|
|
200
234
|
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Register the bundle path with the native module.
|
|
238
|
+
* This saves the path to SharedPreferences (Android) or UserDefaults (iOS)
|
|
239
|
+
* so the app can load the OTA bundle on restart.
|
|
240
|
+
*
|
|
241
|
+
* @param bundlePath The normalized path to the bundle file
|
|
242
|
+
* @param restart Whether to restart the app immediately
|
|
243
|
+
* @returns true if successfully registered with native module, false otherwise
|
|
244
|
+
*/
|
|
245
|
+
async registerBundleWithNative(bundlePath, restart = false) {
|
|
246
|
+
try {
|
|
247
|
+
if (OTAUpdateNative?.applyBundle) {
|
|
248
|
+
// Ensure path is normalized before passing to native module
|
|
249
|
+
const normalizedPath = normalizePath(bundlePath);
|
|
250
|
+
await OTAUpdateNative.applyBundle(normalizedPath, restart);
|
|
251
|
+
return true;
|
|
252
|
+
} else {
|
|
253
|
+
// Native module not available - this is expected for Expo Go
|
|
254
|
+
// but should work for EAS Build apps
|
|
255
|
+
if (__DEV__) {
|
|
256
|
+
console.log('[OTAUpdate] Native module not available. Update will apply on next build with native modules.');
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
if (__DEV__) {
|
|
262
|
+
console.error('[OTAUpdate] Failed to register bundle with native module:', error);
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Clear the pending bundle from native storage.
|
|
270
|
+
* This removes the bundle path from SharedPreferences (Android) or UserDefaults (iOS).
|
|
271
|
+
*/
|
|
272
|
+
async clearNativePendingBundle() {
|
|
273
|
+
try {
|
|
274
|
+
if (OTAUpdateNative?.clearPendingBundle) {
|
|
275
|
+
await OTAUpdateNative.clearPendingBundle();
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
if (__DEV__) {
|
|
279
|
+
console.error('[OTAUpdate] Failed to clear pending bundle:', error);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
201
283
|
}
|
|
202
284
|
//# sourceMappingURL=storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","ExpoFileSystem","require","OTAUpdateNative","OTAUpdate","ExpoStorageAdapter","getDocumentDirectory","documentDirectory","writeFile","
|
|
1
|
+
{"version":3,"names":["NativeModules","normalizePath","path","startsWith","slice","ExpoFileSystem","require","OTAUpdateNative","OTAUpdate","ExpoStorageAdapter","getDocumentDirectory","documentDirectory","writeFile","data","ArrayBuffer","bytes","Uint8Array","binary","i","length","String","fromCharCode","base64","btoa","writeAsStringAsync","encoding","EncodingType","Base64","readFile","readAsStringAsync","readFileAsBuffer","atob","charCodeAt","buffer","deleteFile","deleteAsync","idempotent","exists","info","getInfoAsync","makeDirectory","makeDirectoryAsync","intermediates","NativeStorageAdapter","Error","writeFileBase64","readFileBase64","getStorageAdapter","UpdateStorage","constructor","storage","isExpo","baseDir","baseDirNormalized","ensureDirectory","getNormalizedPath","saveBundle","releaseId","bundlePath","getRawBundlePath","getBundlePath","readBundle","deleteBundle","saveMetadata","update","metadataPath","JSON","stringify","getMetadata","content","parse","clearMetadata","cleanOldBundles","keepReleaseId","registerBundleWithNative","restart","applyBundle","normalizedPath","__DEV__","console","log","error","clearNativePendingBundle","clearPendingBundle"],"sourceRoot":"../../../src","sources":["utils/storage.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -26,15 +26,8 @@ function hexToBytes(hex) {
|
|
|
26
26
|
|
|
27
27
|
// Calculate SHA-256 hash of data
|
|
28
28
|
export async function calculateHash(data) {
|
|
29
|
-
|
|
30
|
-
// Use Expo Crypto
|
|
31
|
-
const hash = await ExpoCrypto.digestStringAsync(ExpoCrypto.CryptoDigestAlgorithm.SHA256, bufferToHex(data), {
|
|
32
|
-
encoding: ExpoCrypto.CryptoEncoding.HEX
|
|
33
|
-
});
|
|
34
|
-
return 'sha256:' + hash;
|
|
35
|
-
}
|
|
29
|
+
// Use native module first (most reliable for binary data)
|
|
36
30
|
if (OTAUpdateNative?.calculateSHA256) {
|
|
37
|
-
// Use native module
|
|
38
31
|
const bytes = new Uint8Array(data);
|
|
39
32
|
let binary = '';
|
|
40
33
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -44,6 +37,11 @@ export async function calculateHash(data) {
|
|
|
44
37
|
const hash = await OTAUpdateNative.calculateSHA256(base64);
|
|
45
38
|
return 'sha256:' + hash;
|
|
46
39
|
}
|
|
40
|
+
if (ExpoCrypto?.digest) {
|
|
41
|
+
// Use Expo Crypto digest (takes Uint8Array, returns ArrayBuffer)
|
|
42
|
+
const hashBuffer = await ExpoCrypto.digest(ExpoCrypto.CryptoDigestAlgorithm.SHA256, new Uint8Array(data));
|
|
43
|
+
return 'sha256:' + bufferToHex(hashBuffer);
|
|
44
|
+
}
|
|
47
45
|
|
|
48
46
|
// Fallback: Use SubtleCrypto (not available in all RN environments)
|
|
49
47
|
if (typeof crypto !== 'undefined' && crypto.subtle) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","ExpoCrypto","require","OTAUpdateNative","OTAUpdate","bufferToHex","buffer","bytes","Uint8Array","Array","from","map","b","toString","padStart","join","hexToBytes","hex","length","i","parseInt","substr","calculateHash","data","
|
|
1
|
+
{"version":3,"names":["NativeModules","ExpoCrypto","require","OTAUpdateNative","OTAUpdate","bufferToHex","buffer","bytes","Uint8Array","Array","from","map","b","toString","padStart","join","hexToBytes","hex","length","i","parseInt","substr","calculateHash","data","calculateSHA256","binary","String","fromCharCode","base64","btoa","hash","digest","hashBuffer","CryptoDigestAlgorithm","SHA256","crypto","subtle","Error","verifyBundleHash","expectedHash","actualHash","verifySignature","signatureHex","publicKeyHex","__DEV__","console","warn","verifyBundle","signature","publicKey","hashValid","error","valid","signatureValid"],"sourceRoot":"../../../src","sources":["utils/verification.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOTAUpdate.d.ts","sourceRoot":"","sources":["../../../src/hooks/useOTAUpdate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useOTAUpdate.d.ts","sourceRoot":"","sources":["../../../src/hooks/useOTAUpdate.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,UAAU,GACV,WAAW,GACX,aAAa,GACb,WAAW,GACX,OAAO,GACP,UAAU,GACV,OAAO,GACP,YAAY,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACjD,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAWD,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,kBAAkB,CA2SxE"}
|
|
@@ -18,9 +18,13 @@ export declare function getStorageAdapter(): StorageAdapter;
|
|
|
18
18
|
export declare class UpdateStorage {
|
|
19
19
|
private storage;
|
|
20
20
|
private baseDir;
|
|
21
|
+
private baseDirNormalized;
|
|
22
|
+
private isExpo;
|
|
21
23
|
constructor();
|
|
22
24
|
private ensureDirectory;
|
|
25
|
+
getNormalizedPath(path: string): string;
|
|
23
26
|
saveBundle(releaseId: string, data: ArrayBuffer): Promise<string>;
|
|
27
|
+
private getRawBundlePath;
|
|
24
28
|
getBundlePath(releaseId: string): Promise<string | null>;
|
|
25
29
|
readBundle(releaseId: string): Promise<ArrayBuffer | null>;
|
|
26
30
|
deleteBundle(releaseId: string): Promise<void>;
|
|
@@ -28,5 +32,20 @@ export declare class UpdateStorage {
|
|
|
28
32
|
getMetadata(): Promise<StoredUpdate | null>;
|
|
29
33
|
clearMetadata(): Promise<void>;
|
|
30
34
|
cleanOldBundles(keepReleaseId: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Register the bundle path with the native module.
|
|
37
|
+
* This saves the path to SharedPreferences (Android) or UserDefaults (iOS)
|
|
38
|
+
* so the app can load the OTA bundle on restart.
|
|
39
|
+
*
|
|
40
|
+
* @param bundlePath The normalized path to the bundle file
|
|
41
|
+
* @param restart Whether to restart the app immediately
|
|
42
|
+
* @returns true if successfully registered with native module, false otherwise
|
|
43
|
+
*/
|
|
44
|
+
registerBundleWithNative(bundlePath: string, restart?: boolean): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Clear the pending bundle from native storage.
|
|
47
|
+
* This removes the bundle path from SharedPreferences (Android) or UserDefaults (iOS).
|
|
48
|
+
*/
|
|
49
|
+
clearNativePendingBundle(): Promise<void>;
|
|
31
50
|
}
|
|
32
51
|
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,oBAAoB,IAAI,MAAM,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,oBAAoB,IAAI,MAAM,CAAC;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAuJD,wBAAgB,iBAAiB,IAAI,cAAc,CAYlD;AAGD,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,MAAM,CAAU;;YAUV,eAAe;IAQ7B,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIjC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAWvE,OAAO,CAAC,gBAAgB;IAIlB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAOxD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAS1D,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9C,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,WAAW,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAe3C,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D;;;;;;;;OAQG;IACG,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC;IAuB9F;;;OAGG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CAWhD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../src/utils/verification.ts"],"names":[],"mappings":"AA8BA,wBAAsB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../src/utils/verification.ts"],"names":[],"mappings":"AA8BA,wBAAsB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA6BtE;AAGD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAGlB;AAGD,wBAAsB,eAAe,CACnC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAGD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAoD7B"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
-
import { AppState, AppStateStatus,
|
|
2
|
+
import { AppState, AppStateStatus, Platform } from 'react-native';
|
|
3
3
|
import { OTAApiClient, ReleaseInfo, getDeviceInfo } from '../utils/api';
|
|
4
4
|
import { UpdateStorage, StoredUpdate } from '../utils/storage';
|
|
5
5
|
import { verifyBundle, VerificationResult } from '../utils/verification';
|
|
6
6
|
|
|
7
|
-
const OTAUpdateNative = NativeModules.OTAUpdate;
|
|
8
|
-
|
|
9
7
|
export interface OTAUpdateConfig {
|
|
10
8
|
serverUrl: string;
|
|
11
9
|
appSlug: string;
|
|
@@ -206,6 +204,18 @@ export function useOTAUpdate(config: OTAUpdateConfig): UseOTAUpdateResult {
|
|
|
206
204
|
downloadedAt: Date.now(),
|
|
207
205
|
});
|
|
208
206
|
|
|
207
|
+
// Register the bundle path with native module (for next app restart)
|
|
208
|
+
// This saves to SharedPreferences (Android) / UserDefaults (iOS)
|
|
209
|
+
const registered = await storage.current.registerBundleWithNative(bundlePath, false);
|
|
210
|
+
|
|
211
|
+
if (__DEV__) {
|
|
212
|
+
if (registered) {
|
|
213
|
+
console.log('[OTAUpdate] Bundle registered with native module. Will apply on app restart.');
|
|
214
|
+
} else {
|
|
215
|
+
console.log('[OTAUpdate] Could not register with native module. If using Expo Go, this is expected.');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
209
219
|
setStatus('ready');
|
|
210
220
|
} catch (err) {
|
|
211
221
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
@@ -250,14 +260,19 @@ export function useOTAUpdate(config: OTAUpdateConfig): UseOTAUpdateResult {
|
|
|
250
260
|
deviceInfo: getDeviceInfo(),
|
|
251
261
|
});
|
|
252
262
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
//
|
|
263
|
+
// Register bundle path with native module and optionally restart
|
|
264
|
+
// This ensures the path is saved to SharedPreferences/UserDefaults
|
|
265
|
+
const registered = await storage.current.registerBundleWithNative(metadata.bundlePath, restartApp);
|
|
266
|
+
|
|
267
|
+
if (!registered && restartApp) {
|
|
268
|
+
// Native module not available
|
|
269
|
+
if (__DEV__) {
|
|
270
|
+
console.log('[OTAUpdate] Update ready. Close and reopen the app to apply the update.');
|
|
271
|
+
console.log('[OTAUpdate] Note: For Expo Go, OTA updates require a native build (EAS Build).');
|
|
272
|
+
}
|
|
273
|
+
} else if (registered && !restartApp) {
|
|
259
274
|
if (__DEV__) {
|
|
260
|
-
console.log('[OTAUpdate] Update
|
|
275
|
+
console.log('[OTAUpdate] Update registered. Will apply on next app restart.');
|
|
261
276
|
}
|
|
262
277
|
}
|
|
263
278
|
|
|
@@ -301,6 +316,9 @@ export function useOTAUpdate(config: OTAUpdateConfig): UseOTAUpdateResult {
|
|
|
301
316
|
await storage.current.clearMetadata();
|
|
302
317
|
}
|
|
303
318
|
|
|
319
|
+
// Also clear from native storage (SharedPreferences/UserDefaults)
|
|
320
|
+
await storage.current.clearNativePendingBundle();
|
|
321
|
+
|
|
304
322
|
setUpdateInfo(null);
|
|
305
323
|
releaseRef.current = null;
|
|
306
324
|
setStatus('idle');
|
package/src/utils/storage.ts
CHANGED
|
@@ -19,12 +19,27 @@ export interface StorageAdapter {
|
|
|
19
19
|
makeDirectory(path: string): Promise<void>;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Helper to normalize file paths (remove file:// prefix)
|
|
23
|
+
function normalizePath(path: string): string {
|
|
24
|
+
if (path.startsWith('file://')) {
|
|
25
|
+
return path.slice(7);
|
|
26
|
+
}
|
|
27
|
+
return path;
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
// Try to use Expo FileSystem if available
|
|
31
|
+
// Use legacy API to avoid deprecation warnings in expo-file-system v54+
|
|
23
32
|
let ExpoFileSystem: any = null;
|
|
24
33
|
try {
|
|
25
|
-
|
|
34
|
+
// Try legacy import first (expo-file-system v54+)
|
|
35
|
+
ExpoFileSystem = require('expo-file-system/legacy');
|
|
26
36
|
} catch {
|
|
27
|
-
|
|
37
|
+
try {
|
|
38
|
+
// Fallback to regular import for older versions
|
|
39
|
+
ExpoFileSystem = require('expo-file-system');
|
|
40
|
+
} catch {
|
|
41
|
+
// Expo not available, will use native module
|
|
42
|
+
}
|
|
28
43
|
}
|
|
29
44
|
|
|
30
45
|
// Native module for bare React Native
|
|
@@ -171,10 +186,15 @@ export function getStorageAdapter(): StorageAdapter {
|
|
|
171
186
|
export class UpdateStorage {
|
|
172
187
|
private storage: StorageAdapter;
|
|
173
188
|
private baseDir: string;
|
|
189
|
+
private baseDirNormalized: string;
|
|
190
|
+
private isExpo: boolean;
|
|
174
191
|
|
|
175
192
|
constructor() {
|
|
176
193
|
this.storage = getStorageAdapter();
|
|
194
|
+
this.isExpo = !!ExpoFileSystem;
|
|
177
195
|
this.baseDir = `${this.storage.getDocumentDirectory()}ota-update/`;
|
|
196
|
+
// Keep a normalized version for native module calls
|
|
197
|
+
this.baseDirNormalized = normalizePath(this.baseDir);
|
|
178
198
|
}
|
|
179
199
|
|
|
180
200
|
private async ensureDirectory(): Promise<void> {
|
|
@@ -184,30 +204,44 @@ export class UpdateStorage {
|
|
|
184
204
|
}
|
|
185
205
|
}
|
|
186
206
|
|
|
207
|
+
// Get normalized path (without file:// prefix) for native module compatibility
|
|
208
|
+
getNormalizedPath(path: string): string {
|
|
209
|
+
return normalizePath(path);
|
|
210
|
+
}
|
|
211
|
+
|
|
187
212
|
async saveBundle(releaseId: string, data: ArrayBuffer): Promise<string> {
|
|
188
213
|
await this.ensureDirectory();
|
|
189
214
|
|
|
190
215
|
const bundlePath = `${this.baseDir}${releaseId}.bundle`;
|
|
191
216
|
await this.storage.writeFile(bundlePath, data);
|
|
192
217
|
|
|
193
|
-
|
|
218
|
+
// Return normalized path for native module compatibility
|
|
219
|
+
return normalizePath(bundlePath);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Get the raw bundle path (with file:// for Expo) - for internal storage operations
|
|
223
|
+
private getRawBundlePath(releaseId: string): string {
|
|
224
|
+
return `${this.baseDir}${releaseId}.bundle`;
|
|
194
225
|
}
|
|
195
226
|
|
|
196
227
|
async getBundlePath(releaseId: string): Promise<string | null> {
|
|
197
|
-
const bundlePath =
|
|
228
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
198
229
|
const exists = await this.storage.exists(bundlePath);
|
|
199
|
-
|
|
230
|
+
// Return normalized path for native module compatibility
|
|
231
|
+
return exists ? normalizePath(bundlePath) : null;
|
|
200
232
|
}
|
|
201
233
|
|
|
202
234
|
async readBundle(releaseId: string): Promise<ArrayBuffer | null> {
|
|
203
|
-
const bundlePath =
|
|
204
|
-
|
|
235
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
236
|
+
const exists = await this.storage.exists(bundlePath);
|
|
237
|
+
if (!exists) return null;
|
|
205
238
|
|
|
239
|
+
// Use raw path for storage operations (expo needs file:// prefix)
|
|
206
240
|
return this.storage.readFileAsBuffer(bundlePath);
|
|
207
241
|
}
|
|
208
242
|
|
|
209
243
|
async deleteBundle(releaseId: string): Promise<void> {
|
|
210
|
-
const bundlePath =
|
|
244
|
+
const bundlePath = this.getRawBundlePath(releaseId);
|
|
211
245
|
if (await this.storage.exists(bundlePath)) {
|
|
212
246
|
await this.storage.deleteFile(bundlePath);
|
|
213
247
|
}
|
|
@@ -246,4 +280,52 @@ export class UpdateStorage {
|
|
|
246
280
|
// For now, we just keep one bundle at a time
|
|
247
281
|
// In a more advanced implementation, we might keep a few for rollback
|
|
248
282
|
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Register the bundle path with the native module.
|
|
286
|
+
* This saves the path to SharedPreferences (Android) or UserDefaults (iOS)
|
|
287
|
+
* so the app can load the OTA bundle on restart.
|
|
288
|
+
*
|
|
289
|
+
* @param bundlePath The normalized path to the bundle file
|
|
290
|
+
* @param restart Whether to restart the app immediately
|
|
291
|
+
* @returns true if successfully registered with native module, false otherwise
|
|
292
|
+
*/
|
|
293
|
+
async registerBundleWithNative(bundlePath: string, restart: boolean = false): Promise<boolean> {
|
|
294
|
+
try {
|
|
295
|
+
if (OTAUpdateNative?.applyBundle) {
|
|
296
|
+
// Ensure path is normalized before passing to native module
|
|
297
|
+
const normalizedPath = normalizePath(bundlePath);
|
|
298
|
+
await OTAUpdateNative.applyBundle(normalizedPath, restart);
|
|
299
|
+
return true;
|
|
300
|
+
} else {
|
|
301
|
+
// Native module not available - this is expected for Expo Go
|
|
302
|
+
// but should work for EAS Build apps
|
|
303
|
+
if (__DEV__) {
|
|
304
|
+
console.log('[OTAUpdate] Native module not available. Update will apply on next build with native modules.');
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (__DEV__) {
|
|
310
|
+
console.error('[OTAUpdate] Failed to register bundle with native module:', error);
|
|
311
|
+
}
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Clear the pending bundle from native storage.
|
|
318
|
+
* This removes the bundle path from SharedPreferences (Android) or UserDefaults (iOS).
|
|
319
|
+
*/
|
|
320
|
+
async clearNativePendingBundle(): Promise<void> {
|
|
321
|
+
try {
|
|
322
|
+
if (OTAUpdateNative?.clearPendingBundle) {
|
|
323
|
+
await OTAUpdateNative.clearPendingBundle();
|
|
324
|
+
}
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (__DEV__) {
|
|
327
|
+
console.error('[OTAUpdate] Failed to clear pending bundle:', error);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
249
331
|
}
|
|
@@ -29,18 +29,8 @@ function hexToBytes(hex: string): Uint8Array {
|
|
|
29
29
|
|
|
30
30
|
// Calculate SHA-256 hash of data
|
|
31
31
|
export async function calculateHash(data: ArrayBuffer): Promise<string> {
|
|
32
|
-
|
|
33
|
-
// Use Expo Crypto
|
|
34
|
-
const hash = await ExpoCrypto.digestStringAsync(
|
|
35
|
-
ExpoCrypto.CryptoDigestAlgorithm.SHA256,
|
|
36
|
-
bufferToHex(data),
|
|
37
|
-
{ encoding: ExpoCrypto.CryptoEncoding.HEX }
|
|
38
|
-
);
|
|
39
|
-
return 'sha256:' + hash;
|
|
40
|
-
}
|
|
41
|
-
|
|
32
|
+
// Use native module first (most reliable for binary data)
|
|
42
33
|
if (OTAUpdateNative?.calculateSHA256) {
|
|
43
|
-
// Use native module
|
|
44
34
|
const bytes = new Uint8Array(data);
|
|
45
35
|
let binary = '';
|
|
46
36
|
for (let i = 0; i < bytes.length; i++) {
|
|
@@ -51,6 +41,15 @@ export async function calculateHash(data: ArrayBuffer): Promise<string> {
|
|
|
51
41
|
return 'sha256:' + hash;
|
|
52
42
|
}
|
|
53
43
|
|
|
44
|
+
if (ExpoCrypto?.digest) {
|
|
45
|
+
// Use Expo Crypto digest (takes Uint8Array, returns ArrayBuffer)
|
|
46
|
+
const hashBuffer = await ExpoCrypto.digest(
|
|
47
|
+
ExpoCrypto.CryptoDigestAlgorithm.SHA256,
|
|
48
|
+
new Uint8Array(data)
|
|
49
|
+
);
|
|
50
|
+
return 'sha256:' + bufferToHex(hashBuffer);
|
|
51
|
+
}
|
|
52
|
+
|
|
54
53
|
// Fallback: Use SubtleCrypto (not available in all RN environments)
|
|
55
54
|
if (typeof crypto !== 'undefined' && crypto.subtle) {
|
|
56
55
|
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|