@vanikya/ota-react-native 0.2.0 → 0.2.2

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.
Files changed (37) hide show
  1. package/android/src/main/AndroidManifest.xml +2 -0
  2. package/android/src/main/java/com/otaupdate/OTAUpdateModule.kt +116 -25
  3. package/app.plugin.js +53 -12
  4. package/ios/OTAUpdate.swift +29 -0
  5. package/lib/commonjs/OTAProvider.js +37 -0
  6. package/lib/commonjs/OTAProvider.js.map +1 -1
  7. package/lib/commonjs/components/OTADebugPanel.js +426 -0
  8. package/lib/commonjs/components/OTADebugPanel.js.map +1 -0
  9. package/lib/commonjs/hooks/useOTAUpdate.js +38 -2
  10. package/lib/commonjs/hooks/useOTAUpdate.js.map +1 -1
  11. package/lib/commonjs/index.js +10 -1
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/utils/storage.js +79 -4
  14. package/lib/commonjs/utils/storage.js.map +1 -1
  15. package/lib/module/OTAProvider.js +38 -1
  16. package/lib/module/OTAProvider.js.map +1 -1
  17. package/lib/module/components/OTADebugPanel.js +418 -0
  18. package/lib/module/components/OTADebugPanel.js.map +1 -0
  19. package/lib/module/hooks/useOTAUpdate.js +38 -2
  20. package/lib/module/hooks/useOTAUpdate.js.map +1 -1
  21. package/lib/module/index.js +4 -1
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/utils/storage.js +79 -4
  24. package/lib/module/utils/storage.js.map +1 -1
  25. package/lib/typescript/OTAProvider.d.ts.map +1 -1
  26. package/lib/typescript/components/OTADebugPanel.d.ts +18 -0
  27. package/lib/typescript/components/OTADebugPanel.d.ts.map +1 -0
  28. package/lib/typescript/hooks/useOTAUpdate.d.ts.map +1 -1
  29. package/lib/typescript/index.d.ts +2 -1
  30. package/lib/typescript/index.d.ts.map +1 -1
  31. package/lib/typescript/utils/storage.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/OTAProvider.tsx +40 -0
  34. package/src/components/OTADebugPanel.tsx +447 -0
  35. package/src/hooks/useOTAUpdate.ts +49 -2
  36. package/src/index.ts +4 -1
  37. package/src/utils/storage.ts +105 -4
@@ -1,3 +1,5 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+ <!-- Internet permission is required for downloading OTA bundles -->
4
+ <uses-permission android:name="android.permission.INTERNET" />
3
5
  </manifest>
@@ -2,6 +2,8 @@ package com.otaupdate
2
2
 
3
3
  import android.content.Context
4
4
  import android.content.SharedPreferences
5
+ import android.os.Handler
6
+ import android.os.Looper
5
7
  import android.util.Base64
6
8
  import com.facebook.react.bridge.*
7
9
  import java.io.File
@@ -10,6 +12,7 @@ import java.io.InputStream
10
12
  import java.net.HttpURLConnection
11
13
  import java.net.URL
12
14
  import java.security.MessageDigest
15
+ import java.util.concurrent.Executors
13
16
 
14
17
  class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
15
18
 
@@ -17,6 +20,12 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
17
20
  reactContext.getSharedPreferences("OTAUpdate", Context.MODE_PRIVATE)
18
21
  }
19
22
 
23
+ // Use a thread pool for background operations instead of raw threads
24
+ private val executor = Executors.newFixedThreadPool(2)
25
+
26
+ // Handler to post results back to the main thread
27
+ private val mainHandler = Handler(Looper.getMainLooper())
28
+
20
29
  override fun getName(): String = "OTAUpdate"
21
30
 
22
31
  // File System Operations
@@ -100,25 +109,33 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
100
109
  // This is critical for large bundles (5MB+)
101
110
  @ReactMethod
102
111
  fun downloadFile(urlString: String, destPath: String, promise: Promise) {
103
- Thread {
112
+ executor.execute {
104
113
  var connection: HttpURLConnection? = null
105
114
  var inputStream: InputStream? = null
106
115
  var outputStream: FileOutputStream? = null
107
116
 
108
117
  try {
118
+ android.util.Log.d("OTAUpdate", "Starting download from: $urlString to: $destPath")
119
+
109
120
  val url = URL(urlString)
110
121
  connection = url.openConnection() as HttpURLConnection
111
122
  connection.connectTimeout = 30000
112
- connection.readTimeout = 60000
123
+ connection.readTimeout = 120000 // Increased read timeout for large files
113
124
  connection.requestMethod = "GET"
125
+ connection.setRequestProperty("Accept-Encoding", "identity") // Disable compression for reliable streaming
114
126
  connection.connect()
115
127
 
116
128
  val responseCode = connection.responseCode
117
129
  if (responseCode != HttpURLConnection.HTTP_OK) {
118
- promise.reject("DOWNLOAD_ERROR", "Download failed with status $responseCode")
119
- return@Thread
130
+ val errorMsg = "Download failed with status $responseCode"
131
+ android.util.Log.e("OTAUpdate", errorMsg)
132
+ mainHandler.post { promise.reject("DOWNLOAD_ERROR", errorMsg) }
133
+ return@execute
120
134
  }
121
135
 
136
+ val contentLength = connection.contentLengthLong
137
+ android.util.Log.d("OTAUpdate", "Content-Length: $contentLength bytes")
138
+
122
139
  // Ensure parent directory exists
123
140
  val destFile = File(destPath)
124
141
  destFile.parentFile?.mkdirs()
@@ -137,22 +154,36 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
137
154
 
138
155
  outputStream.flush()
139
156
 
157
+ // Verify written file size
158
+ val writtenSize = destFile.length()
159
+ android.util.Log.d("OTAUpdate", "Download complete: $totalBytesRead bytes read, $writtenSize bytes written")
160
+
161
+ if (contentLength > 0 && writtenSize != contentLength) {
162
+ val errorMsg = "File size mismatch: expected $contentLength, got $writtenSize"
163
+ android.util.Log.e("OTAUpdate", errorMsg)
164
+ destFile.delete()
165
+ mainHandler.post { promise.reject("DOWNLOAD_ERROR", errorMsg) }
166
+ return@execute
167
+ }
168
+
140
169
  val result = Arguments.createMap()
141
170
  result.putDouble("fileSize", totalBytesRead.toDouble())
142
- promise.resolve(result)
171
+ // Resolve promise on main thread to avoid React Native bridge issues
172
+ mainHandler.post { promise.resolve(result) }
143
173
 
144
174
  } catch (e: Exception) {
145
- promise.reject("DOWNLOAD_ERROR", "Failed to download file: ${e.message}", e)
175
+ android.util.Log.e("OTAUpdate", "Download failed: ${e.message}", e)
176
+ mainHandler.post { promise.reject("DOWNLOAD_ERROR", "Failed to download file: ${e.message}", e) }
146
177
  } finally {
147
178
  try {
148
179
  inputStream?.close()
149
180
  outputStream?.close()
150
181
  connection?.disconnect()
151
182
  } catch (e: Exception) {
152
- // Ignore cleanup errors
183
+ android.util.Log.w("OTAUpdate", "Error during cleanup: ${e.message}")
153
184
  }
154
185
  }
155
- }.start()
186
+ }
156
187
  }
157
188
 
158
189
  // Cryptography
@@ -174,14 +205,16 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
174
205
  // Critical for large bundles (5MB+)
175
206
  @ReactMethod
176
207
  fun calculateSHA256FromFile(filePath: String, promise: Promise) {
177
- Thread {
208
+ executor.execute {
178
209
  try {
179
210
  val file = File(filePath)
180
211
  if (!file.exists()) {
181
- promise.reject("FILE_ERROR", "File not found: $filePath")
182
- return@Thread
212
+ mainHandler.post { promise.reject("FILE_ERROR", "File not found: $filePath") }
213
+ return@execute
183
214
  }
184
215
 
216
+ android.util.Log.d("OTAUpdate", "Calculating hash for: $filePath (${file.length()} bytes)")
217
+
185
218
  val digest = MessageDigest.getInstance("SHA-256")
186
219
  val buffer = ByteArray(8192) // 8KB buffer
187
220
  var bytesRead: Int
@@ -194,11 +227,14 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
194
227
 
195
228
  val hash = digest.digest()
196
229
  val hexString = hash.joinToString("") { "%02x".format(it) }
197
- promise.resolve(hexString)
230
+ android.util.Log.d("OTAUpdate", "Hash calculated: $hexString")
231
+ // Resolve promise on main thread
232
+ mainHandler.post { promise.resolve(hexString) }
198
233
  } catch (e: Exception) {
199
- promise.reject("HASH_ERROR", "Failed to calculate hash: ${e.message}", e)
234
+ android.util.Log.e("OTAUpdate", "Hash calculation failed: ${e.message}", e)
235
+ mainHandler.post { promise.reject("HASH_ERROR", "Failed to calculate hash: ${e.message}", e) }
200
236
  }
201
- }.start()
237
+ }
202
238
  }
203
239
 
204
240
  @ReactMethod
@@ -229,21 +265,69 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
229
265
  @ReactMethod
230
266
  fun applyBundle(bundlePath: String, restart: Boolean, promise: Promise) {
231
267
  try {
268
+ // Validate bundle file exists before storing path
269
+ val bundleFile = File(bundlePath)
270
+ if (!bundleFile.exists()) {
271
+ promise.reject("APPLY_ERROR", "Bundle file does not exist: $bundlePath")
272
+ return
273
+ }
274
+ if (!bundleFile.canRead()) {
275
+ promise.reject("APPLY_ERROR", "Bundle file is not readable: $bundlePath")
276
+ return
277
+ }
278
+ if (bundleFile.length() < 100) {
279
+ promise.reject("APPLY_ERROR", "Bundle file is too small (likely corrupted): ${bundleFile.length()} bytes")
280
+ return
281
+ }
282
+
283
+ // Log for debugging
284
+ android.util.Log.d("OTAUpdate", "Applying bundle: $bundlePath (${bundleFile.length()} bytes)")
285
+
232
286
  // Store the bundle path for next launch
233
- prefs.edit().putString("BundlePath", bundlePath).apply()
287
+ // CRITICAL: Use commit() instead of apply() to ensure synchronous write
288
+ // This prevents a race condition where the app kills before the write completes
289
+ val success = prefs.edit().putString("BundlePath", bundlePath).commit()
290
+ if (!success) {
291
+ android.util.Log.e("OTAUpdate", "Failed to save bundle path to SharedPreferences")
292
+ promise.reject("APPLY_ERROR", "Failed to save bundle path")
293
+ return
294
+ }
295
+ android.util.Log.d("OTAUpdate", "Bundle path saved to SharedPreferences: $bundlePath")
296
+
297
+ // Verify the path was actually saved
298
+ val savedPath = prefs.getString("BundlePath", null)
299
+ if (savedPath != bundlePath) {
300
+ android.util.Log.e("OTAUpdate", "Bundle path verification failed: expected $bundlePath, got $savedPath")
301
+ promise.reject("APPLY_ERROR", "Bundle path verification failed")
302
+ return
303
+ }
234
304
 
235
305
  if (restart) {
236
- // Restart the app
237
- val context = reactApplicationContext
238
- val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
239
- intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP)
240
- intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
241
- context.startActivity(intent)
242
- android.os.Process.killProcess(android.os.Process.myPid())
306
+ android.util.Log.d("OTAUpdate", "Restarting app to apply bundle...")
307
+
308
+ // Resolve promise before restarting so JS knows it succeeded
309
+ promise.resolve(null)
310
+
311
+ // Give a small delay to ensure the promise is sent back to JS
312
+ mainHandler.postDelayed({
313
+ // Restart the app
314
+ val context = reactApplicationContext
315
+ val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
316
+ intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP)
317
+ intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
318
+ intent?.addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK)
319
+ context.startActivity(intent)
320
+
321
+ // Small delay before killing to allow activity to start
322
+ mainHandler.postDelayed({
323
+ android.os.Process.killProcess(android.os.Process.myPid())
324
+ }, 100)
325
+ }, 100)
326
+ } else {
327
+ promise.resolve(null)
243
328
  }
244
-
245
- promise.resolve(null)
246
329
  } catch (e: Exception) {
330
+ android.util.Log.e("OTAUpdate", "Failed to apply bundle: ${e.message}", e)
247
331
  promise.reject("APPLY_ERROR", "Failed to apply bundle: ${e.message}", e)
248
332
  }
249
333
  }
@@ -256,7 +340,8 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
256
340
 
257
341
  @ReactMethod
258
342
  fun clearPendingBundle(promise: Promise) {
259
- prefs.edit().remove("BundlePath").apply()
343
+ prefs.edit().remove("BundlePath").commit()
344
+ android.util.Log.d("OTAUpdate", "Pending bundle cleared")
260
345
  promise.resolve(null)
261
346
  }
262
347
 
@@ -273,6 +358,12 @@ class OTAUpdateModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
273
358
  return data
274
359
  }
275
360
 
361
+ // Cleanup executor when module is destroyed
362
+ override fun onCatalystInstanceDestroy() {
363
+ super.onCatalystInstanceDestroy()
364
+ executor.shutdown()
365
+ }
366
+
276
367
  companion object {
277
368
  const val NAME = "OTAUpdate"
278
369
  }
package/app.plugin.js CHANGED
@@ -41,9 +41,17 @@ function withOTAUpdateAndroid(config) {
41
41
  override fun getJSBundleFile(): String? {
42
42
  val prefs: SharedPreferences = applicationContext.getSharedPreferences("OTAUpdate", android.content.Context.MODE_PRIVATE)
43
43
  val bundlePath = prefs.getString("BundlePath", null)
44
- if (bundlePath != null && File(bundlePath).exists()) {
45
- return bundlePath
44
+ android.util.Log.d("OTAUpdate", "getJSBundleFile called, stored path: $bundlePath")
45
+ if (bundlePath != null) {
46
+ val file = File(bundlePath)
47
+ if (file.exists() && file.canRead()) {
48
+ android.util.Log.d("OTAUpdate", "Loading OTA bundle: $bundlePath (${file.length()} bytes)")
49
+ return bundlePath
50
+ } else {
51
+ android.util.Log.w("OTAUpdate", "OTA bundle not found or not readable: $bundlePath, exists=${file.exists()}")
52
+ }
46
53
  }
54
+ android.util.Log.d("OTAUpdate", "Loading default bundle")
47
55
  return null
48
56
  }
49
57
  `;
@@ -64,9 +72,17 @@ function withOTAUpdateAndroid(config) {
64
72
  override fun getJSBundleFile(): String? {
65
73
  val prefs: SharedPreferences = applicationContext.getSharedPreferences("OTAUpdate", android.content.Context.MODE_PRIVATE)
66
74
  val bundlePath = prefs.getString("BundlePath", null)
67
- if (bundlePath != null && File(bundlePath).exists()) {
68
- return bundlePath
75
+ android.util.Log.d("OTAUpdate", "getJSBundleFile called, stored path: $bundlePath")
76
+ if (bundlePath != null) {
77
+ val file = File(bundlePath)
78
+ if (file.exists() && file.canRead()) {
79
+ android.util.Log.d("OTAUpdate", "Loading OTA bundle: $bundlePath (${file.length()} bytes)")
80
+ return bundlePath
81
+ } else {
82
+ android.util.Log.w("OTAUpdate", "OTA bundle not found or not readable: $bundlePath, exists=${file.exists()}")
83
+ }
69
84
  }
85
+ android.util.Log.d("OTAUpdate", "Loading default bundle")
70
86
  return null
71
87
  }
72
88
  `;
@@ -86,9 +102,17 @@ function withOTAUpdateAndroid(config) {
86
102
  const getJSBundleFileOverride = `override fun getJSBundleFile(): String? {
87
103
  val prefs: SharedPreferences = applicationContext.getSharedPreferences("OTAUpdate", android.content.Context.MODE_PRIVATE)
88
104
  val bundlePath = prefs.getString("BundlePath", null)
89
- if (bundlePath != null && File(bundlePath).exists()) {
90
- return bundlePath
105
+ android.util.Log.d("OTAUpdate", "getJSBundleFile called, stored path: $bundlePath")
106
+ if (bundlePath != null) {
107
+ val file = File(bundlePath)
108
+ if (file.exists() && file.canRead()) {
109
+ android.util.Log.d("OTAUpdate", "Loading OTA bundle: $bundlePath (${file.length()} bytes)")
110
+ return bundlePath
111
+ } else {
112
+ android.util.Log.w("OTAUpdate", "OTA bundle not found or not readable: $bundlePath, exists=${file.exists()}")
113
+ }
91
114
  }
115
+ android.util.Log.d("OTAUpdate", "Loading default bundle")
92
116
  return null
93
117
  }
94
118
 
@@ -114,9 +138,17 @@ function withOTAUpdateAndroid(config) {
114
138
  override fun getJSBundleFile(): String? {
115
139
  val prefs: SharedPreferences = applicationContext.getSharedPreferences("OTAUpdate", android.content.Context.MODE_PRIVATE)
116
140
  val bundlePath = prefs.getString("BundlePath", null)
117
- if (bundlePath != null && File(bundlePath).exists()) {
118
- return bundlePath
141
+ android.util.Log.d("OTAUpdate", "getJSBundleFile called, stored path: $bundlePath")
142
+ if (bundlePath != null) {
143
+ val file = File(bundlePath)
144
+ if (file.exists() && file.canRead()) {
145
+ android.util.Log.d("OTAUpdate", "Loading OTA bundle: $bundlePath (${file.length()} bytes)")
146
+ return bundlePath
147
+ } else {
148
+ android.util.Log.w("OTAUpdate", "OTA bundle not found or not readable: $bundlePath, exists=${file.exists()}")
149
+ }
119
150
  }
151
+ android.util.Log.d("OTAUpdate", "Loading default bundle")
120
152
  return null
121
153
  }
122
154
  `;
@@ -152,12 +184,21 @@ function withOTAUpdateIOS(config) {
152
184
  const helperFunction = `
153
185
  // OTA Update: Check for downloaded bundle
154
186
  private func getOTABundleURL() -> URL? {
155
- if let bundlePath = UserDefaults.standard.string(forKey: "OTAUpdateBundlePath") {
156
- let fileURL = URL(fileURLWithPath: bundlePath)
157
- if FileManager.default.fileExists(atPath: bundlePath) {
158
- return fileURL
187
+ let bundlePath = UserDefaults.standard.string(forKey: "OTAUpdateBundlePath")
188
+ NSLog("[OTAUpdate] getOTABundleURL called, stored path: %@", bundlePath ?? "nil")
189
+ if let path = bundlePath {
190
+ let fileManager = FileManager.default
191
+ if fileManager.fileExists(atPath: path) {
192
+ if let attrs = try? fileManager.attributesOfItem(atPath: path),
193
+ let size = attrs[.size] as? Int64 {
194
+ NSLog("[OTAUpdate] Loading OTA bundle: %@ (%lld bytes)", path, size)
195
+ }
196
+ return URL(fileURLWithPath: path)
197
+ } else {
198
+ NSLog("[OTAUpdate] OTA bundle not found at path: %@", path)
159
199
  }
160
200
  }
201
+ NSLog("[OTAUpdate] Loading default bundle")
161
202
  return nil
162
203
  }
163
204
  `;
@@ -240,6 +240,35 @@ class OTAUpdate: NSObject {
240
240
 
241
241
  @objc
242
242
  func applyBundle(_ bundlePath: String, restart: Bool, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
243
+ // Validate bundle file exists before storing path
244
+ let fileManager = FileManager.default
245
+
246
+ guard fileManager.fileExists(atPath: bundlePath) else {
247
+ rejecter("APPLY_ERROR", "Bundle file does not exist: \(bundlePath)", nil)
248
+ return
249
+ }
250
+
251
+ guard fileManager.isReadableFile(atPath: bundlePath) else {
252
+ rejecter("APPLY_ERROR", "Bundle file is not readable: \(bundlePath)", nil)
253
+ return
254
+ }
255
+
256
+ // Check file size
257
+ do {
258
+ let attributes = try fileManager.attributesOfItem(atPath: bundlePath)
259
+ let fileSize = attributes[.size] as? Int64 ?? 0
260
+ if fileSize < 100 {
261
+ rejecter("APPLY_ERROR", "Bundle file is too small (likely corrupted): \(fileSize) bytes", nil)
262
+ return
263
+ }
264
+
265
+ // Log for debugging
266
+ NSLog("[OTAUpdate] Applying bundle: %@ (%lld bytes)", bundlePath, fileSize)
267
+ } catch {
268
+ rejecter("APPLY_ERROR", "Failed to get bundle file attributes: \(error.localizedDescription)", error)
269
+ return
270
+ }
271
+
243
272
  // Store the bundle path for next launch
244
273
  UserDefaults.standard.set(bundlePath, forKey: "OTAUpdateBundlePath")
245
274
  UserDefaults.standard.synchronize()
@@ -10,6 +10,7 @@ exports.withOTA = withOTA;
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var _reactNative = require("react-native");
12
12
  var _useOTAUpdate = require("./hooks/useOTAUpdate");
13
+ var _storage = require("./utils/storage");
13
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
15
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
15
16
  // Context type
@@ -30,6 +31,42 @@ function OTAProvider({
30
31
  }) {
31
32
  const ota = (0, _useOTAUpdate.useOTAUpdate)(config);
32
33
  const [handledMandatory, setHandledMandatory] = (0, _react.useState)(false);
34
+ const initRef = (0, _react.useRef)(false);
35
+
36
+ // Startup initialization - check for and clear corrupted bundles
37
+ (0, _react.useEffect)(() => {
38
+ if (initRef.current) return;
39
+ initRef.current = true;
40
+ const initializeOTA = async () => {
41
+ try {
42
+ const storage = new _storage.UpdateStorage();
43
+
44
+ // Check for corrupted bundle and clear it
45
+ const wasCorrupted = await storage.clearCorruptedBundle();
46
+ if (wasCorrupted && __DEV__) {
47
+ console.log('[OTAUpdate] Cleared corrupted bundle on startup');
48
+ }
49
+
50
+ // Also validate that if there's a pending bundle path, the file actually exists
51
+ const metadata = await storage.getMetadata();
52
+ if (metadata && metadata.bundlePath) {
53
+ const bundleExists = await storage.validateBundle(metadata.releaseId);
54
+ if (!bundleExists) {
55
+ if (__DEV__) {
56
+ console.log('[OTAUpdate] Bundle file missing or invalid, clearing metadata');
57
+ }
58
+ await storage.clearMetadata();
59
+ await storage.clearNativePendingBundle();
60
+ }
61
+ }
62
+ } catch (error) {
63
+ if (__DEV__) {
64
+ console.error('[OTAUpdate] Startup initialization error:', error);
65
+ }
66
+ }
67
+ };
68
+ initializeOTA();
69
+ }, []);
33
70
 
34
71
  // Handle callbacks
35
72
  (0, _react.useEffect)(() => {
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useOTAUpdate","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","OTAContext","createContext","OTAProvider","children","config","onUpdateAvailable","onUpdateDownloaded","onError","showMandatoryUpdateAlert","mandatoryUpdateAlertTitle","mandatoryUpdateAlertMessage","ota","useOTAUpdate","handledMandatory","setHandledMandatory","useState","useEffect","status","updateInfo","isMandatory","Alert","alert","text","onPress","downloadUpdate","applyUpdate","error","contextValue","createElement","Provider","value","useOTA","context","useContext","Error","withOTA","Component","WithOTA","props","UpdateBanner","renderAvailable","renderDownloading","renderReady","Fragment","downloadProgress","percentage"],"sourceRoot":"../../src","sources":["OTAProvider.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useOTAUpdate","_storage","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","OTAContext","createContext","OTAProvider","children","config","onUpdateAvailable","onUpdateDownloaded","onError","showMandatoryUpdateAlert","mandatoryUpdateAlertTitle","mandatoryUpdateAlertMessage","ota","useOTAUpdate","handledMandatory","setHandledMandatory","useState","initRef","useRef","useEffect","current","initializeOTA","storage","UpdateStorage","wasCorrupted","clearCorruptedBundle","__DEV__","console","log","metadata","getMetadata","bundlePath","bundleExists","validateBundle","releaseId","clearMetadata","clearNativePendingBundle","error","status","updateInfo","isMandatory","Alert","alert","text","onPress","downloadUpdate","applyUpdate","contextValue","createElement","Provider","value","useOTA","context","useContext","Error","withOTA","Component","WithOTA","props","UpdateBanner","renderAvailable","renderDownloading","renderReady","Fragment","downloadProgress","percentage"],"sourceRoot":"../../src","sources":["OTAProvider.tsx"],"mappings":"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","ignoreList":[]}