react-native-ota-hot-update 2.4.0 → 2.4.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 (28) hide show
  1. package/README.md +48 -0
  2. package/android/generated/java/com/otahotupdate/NativeOtaHotUpdateSpec.java +4 -0
  3. package/android/generated/jni/RNOtaHotUpdateSpec-generated.cpp +6 -0
  4. package/android/generated/jni/react/renderer/components/RNOtaHotUpdateSpec/RNOtaHotUpdateSpecJSI-generated.cpp +9 -0
  5. package/android/generated/jni/react/renderer/components/RNOtaHotUpdateSpec/RNOtaHotUpdateSpecJSI.h +9 -0
  6. package/android/src/main/java/com/otahotupdate/CrashHandler.kt +39 -12
  7. package/android/src/main/java/com/otahotupdate/OtaHotUpdateModule.kt +79 -6
  8. package/android/src/oldarch/OtaHotUpdateSpec.kt +1 -0
  9. package/ios/OtaHotUpdate.mm +123 -60
  10. package/ios/generated/RNOtaHotUpdateSpec/RNOtaHotUpdateSpec-generated.mm +7 -0
  11. package/ios/generated/RNOtaHotUpdateSpec/RNOtaHotUpdateSpec.h +5 -0
  12. package/ios/generated/RNOtaHotUpdateSpecJSI-generated.cpp +9 -0
  13. package/ios/generated/RNOtaHotUpdateSpecJSI.h +9 -0
  14. package/lib/commonjs/NativeOtaHotUpdate.js.map +1 -1
  15. package/lib/commonjs/gits/helper/fs.js +28 -2
  16. package/lib/commonjs/gits/helper/fs.js.map +1 -1
  17. package/lib/module/NativeOtaHotUpdate.js.map +1 -1
  18. package/lib/module/gits/helper/fs.js +28 -2
  19. package/lib/module/gits/helper/fs.js.map +1 -1
  20. package/lib/typescript/commonjs/src/NativeOtaHotUpdate.d.ts +1 -0
  21. package/lib/typescript/commonjs/src/NativeOtaHotUpdate.d.ts.map +1 -1
  22. package/lib/typescript/commonjs/src/gits/helper/fs.d.ts.map +1 -1
  23. package/lib/typescript/module/src/NativeOtaHotUpdate.d.ts +1 -0
  24. package/lib/typescript/module/src/NativeOtaHotUpdate.d.ts.map +1 -1
  25. package/lib/typescript/module/src/gits/helper/fs.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/NativeOtaHotUpdate.ts +1 -0
  28. package/src/gits/helper/fs.ts +27 -3
package/README.md CHANGED
@@ -251,3 +251,51 @@ Using Strapi, you can build a tailored admin panel to manage React Native hot up
251
251
 
252
252
  ### Sponsor this project
253
253
  https://paypal.me/vantuan88291
254
+
255
+ ---
256
+
257
+ ## Architecture / Sequence Diagram
258
+
259
+ > Paste the content below into [https://sequencediagram.org/](https://sequencediagram.org/) to render the flow diagram.
260
+
261
+ ```
262
+ title react-native-ota-hot-update - Main Flow
263
+
264
+ actor Developer
265
+ participant "Your Server\n(or Git Repo)" as Server
266
+ participant "RN App" as App
267
+ participant "Native Module\n(iOS / Android)" as Native
268
+ participant "Local Storage\n& File System" as Local
269
+
270
+ == Download & Install Update ==
271
+
272
+ Developer->Server: Upload bundle.zip + update.json
273
+ App->Server: Fetch update.json → check new version available
274
+ App->Server: Download bundle.zip
275
+ Server-->App: bundle.zip saved to local path
276
+ App->Native: setupBundlePath(zipPath, version)
277
+ Native->Local: Unzip → output_v{version}_{timestamp}/bundle
278
+ Native->Local: Save bundle PATH to SharedPrefs / UserDefaults
279
+ Native-->App: success
280
+
281
+ alt restartAfterInstall = true
282
+ App->Native: restart()
283
+ end
284
+
285
+ == App Startup - Which Bundle to Load? ==
286
+
287
+ App->Native: getBundle() / bundleJS()
288
+ Native->Local: Read saved PATH
289
+ alt PATH exists AND file on disk AND app version matches
290
+ Native-->App: Use OTA bundle path
291
+ else
292
+ Native-->App: Use default bundle (built-in)
293
+ end
294
+ App->App: Load JS Bundle
295
+
296
+ == Crash Auto-Rollback ==
297
+
298
+ App->App: Crash within 2s of startup
299
+ Native->Local: Restore previous bundle PATH
300
+ Native->App: Restart app with safe bundle
301
+ ```
@@ -80,4 +80,8 @@ public abstract class NativeOtaHotUpdateSpec extends ReactContextBaseJavaModule
80
80
  @ReactMethod
81
81
  @DoNotStrip
82
82
  public abstract void clearAllBundles(double a, Promise promise);
83
+
84
+ @ReactMethod
85
+ @DoNotStrip
86
+ public abstract void writeFile(String path, String base64Content, String encoding, Promise promise);
83
87
  }
@@ -72,6 +72,11 @@ static facebook::jsi::Value __hostFunction_NativeOtaHotUpdateSpecJSI_clearAllBun
72
72
  return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "clearAllBundles", "(DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
73
73
  }
74
74
 
75
+ static facebook::jsi::Value __hostFunction_NativeOtaHotUpdateSpecJSI_writeFile(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
76
+ static jmethodID cachedMethodId = nullptr;
77
+ return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "writeFile", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
78
+ }
79
+
75
80
  NativeOtaHotUpdateSpecJSI::NativeOtaHotUpdateSpecJSI(const JavaTurboModule::InitParams &params)
76
81
  : JavaTurboModule(params) {
77
82
  methodMap_["setupBundlePath"] = MethodMetadata {5, __hostFunction_NativeOtaHotUpdateSpecJSI_setupBundlePath};
@@ -86,6 +91,7 @@ NativeOtaHotUpdateSpecJSI::NativeOtaHotUpdateSpecJSI(const JavaTurboModule::Init
86
91
  methodMap_["getBundleList"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateSpecJSI_getBundleList};
87
92
  methodMap_["deleteBundleById"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateSpecJSI_deleteBundleById};
88
93
  methodMap_["clearAllBundles"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateSpecJSI_clearAllBundles};
94
+ methodMap_["writeFile"] = MethodMetadata {3, __hostFunction_NativeOtaHotUpdateSpecJSI_writeFile};
89
95
  }
90
96
 
91
97
  std::shared_ptr<TurboModule> RNOtaHotUpdateSpec_ModuleProvider(const std::string &moduleName, const JavaTurboModule::InitParams &params) {
@@ -87,6 +87,14 @@ static jsi::Value __hostFunction_NativeOtaHotUpdateCxxSpecJSI_clearAllBundles(js
87
87
  count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber()
88
88
  );
89
89
  }
90
+ static jsi::Value __hostFunction_NativeOtaHotUpdateCxxSpecJSI_writeFile(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
91
+ return static_cast<NativeOtaHotUpdateCxxSpecJSI *>(&turboModule)->writeFile(
92
+ rt,
93
+ count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt),
94
+ count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt),
95
+ count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt)
96
+ );
97
+ }
90
98
 
91
99
  NativeOtaHotUpdateCxxSpecJSI::NativeOtaHotUpdateCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
92
100
  : TurboModule("OtaHotUpdate", jsInvoker) {
@@ -102,6 +110,7 @@ NativeOtaHotUpdateCxxSpecJSI::NativeOtaHotUpdateCxxSpecJSI(std::shared_ptr<CallI
102
110
  methodMap_["getBundleList"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_getBundleList};
103
111
  methodMap_["deleteBundleById"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_deleteBundleById};
104
112
  methodMap_["clearAllBundles"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_clearAllBundles};
113
+ methodMap_["writeFile"] = MethodMetadata {3, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_writeFile};
105
114
  }
106
115
 
107
116
 
@@ -32,6 +32,7 @@ public:
32
32
  virtual jsi::Value getBundleList(jsi::Runtime &rt, double a) = 0;
33
33
  virtual jsi::Value deleteBundleById(jsi::Runtime &rt, jsi::String id) = 0;
34
34
  virtual jsi::Value clearAllBundles(jsi::Runtime &rt, double a) = 0;
35
+ virtual jsi::Value writeFile(jsi::Runtime &rt, jsi::String path, jsi::String base64Content, jsi::String encoding) = 0;
35
36
 
36
37
  };
37
38
 
@@ -154,6 +155,14 @@ private:
154
155
  return bridging::callFromJs<jsi::Value>(
155
156
  rt, &T::clearAllBundles, jsInvoker_, instance_, std::move(a));
156
157
  }
158
+ jsi::Value writeFile(jsi::Runtime &rt, jsi::String path, jsi::String base64Content, jsi::String encoding) override {
159
+ static_assert(
160
+ bridging::getParameterCount(&T::writeFile) == 4,
161
+ "Expected writeFile(...) to have 4 parameters");
162
+
163
+ return bridging::callFromJs<jsi::Value>(
164
+ rt, &T::writeFile, jsInvoker_, instance_, std::move(path), std::move(base64Content), std::move(encoding));
165
+ }
157
166
 
158
167
  private:
159
168
  friend class NativeOtaHotUpdateCxxSpec;
@@ -4,12 +4,15 @@ import android.content.Context
4
4
  import android.widget.Toast
5
5
  import com.jakewharton.processphoenix.ProcessPhoenix
6
6
  import com.rnhotupdate.Common.PATH
7
- import com.rnhotupdate.Common.PREVIOUS_PATH
7
+ import com.rnhotupdate.Common.VERSION
8
+ import com.rnhotupdate.Common.BUNDLE_HISTORY
8
9
  import com.rnhotupdate.SharedPrefs
9
10
  import kotlinx.coroutines.Dispatchers
10
11
  import kotlinx.coroutines.GlobalScope
11
12
  import kotlinx.coroutines.delay
12
13
  import kotlinx.coroutines.launch
14
+ import org.json.JSONArray
15
+ import java.io.File
13
16
 
14
17
  class CrashHandler(private val context: Context) : Thread.UncaughtExceptionHandler {
15
18
  private val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
@@ -23,20 +26,45 @@ class CrashHandler(private val context: Context) : Thread.UncaughtExceptionHandl
23
26
  }
24
27
  override fun uncaughtException(thread: Thread, throwable: Throwable) {
25
28
  if (beginning) {
26
- //begin remove and using previous bundle
27
29
  val sharedPrefs = SharedPrefs(context)
28
- val oldPath = sharedPrefs.getString(PREVIOUS_PATH)
29
- if (oldPath != "") {
30
- val isDeleted = utils.deleteOldBundleIfneeded(PATH)
31
- if (isDeleted) {
32
- sharedPrefs.putString(PATH, oldPath)
33
- sharedPrefs.putString(PREVIOUS_PATH, "")
34
- } else {
35
- sharedPrefs.putString(PATH, "")
30
+ val currentPath = sharedPrefs.getString(PATH)
31
+
32
+ // Try to rollback using history system
33
+ val historyJson = sharedPrefs.getString(BUNDLE_HISTORY)
34
+ var rolledBack = false
35
+
36
+ if (!historyJson.isNullOrEmpty() && !currentPath.isNullOrEmpty()) {
37
+ try {
38
+ val jsonArray = JSONArray(historyJson)
39
+ val history = (0 until jsonArray.length()).map { i ->
40
+ val obj = jsonArray.getJSONObject(i)
41
+ Pair(obj.getInt("version"), obj.getString("path"))
42
+ }.sortedByDescending { it.first }
43
+
44
+ val currentBundle = history.find { it.second == currentPath }
45
+ if (currentBundle != null) {
46
+ val previousBundle = history
47
+ .filter { it.first < currentBundle.first }
48
+ .maxByOrNull { it.first }
49
+
50
+ if (previousBundle != null && File(previousBundle.second).exists()) {
51
+ val isDeleted = utils.deleteOldBundleIfneeded(PATH)
52
+ if (isDeleted) {
53
+ sharedPrefs.putString(PATH, previousBundle.second)
54
+ sharedPrefs.putString(VERSION, previousBundle.first.toString())
55
+ rolledBack = true
56
+ }
57
+ }
58
+ }
59
+ } catch (e: Exception) {
60
+ // ignore, fall through to clear path
36
61
  }
37
- } else {
62
+ }
63
+
64
+ if (!rolledBack) {
38
65
  sharedPrefs.putString(PATH, "")
39
66
  }
67
+
40
68
  val errorMessage = throwable.message ?: "Unknown error occurred"
41
69
  Toast.makeText(context, "Update failed: $errorMessage", Toast.LENGTH_LONG).show()
42
70
  GlobalScope.launch(Dispatchers.IO) {
@@ -48,4 +76,3 @@ class CrashHandler(private val context: Context) : Thread.UncaughtExceptionHandl
48
76
  }
49
77
  }
50
78
  }
51
-
@@ -14,7 +14,6 @@ import com.rnhotupdate.Common.VERSION
14
14
  import com.rnhotupdate.Common.PREVIOUS_VERSION
15
15
  import com.rnhotupdate.Common.METADATA
16
16
  import com.rnhotupdate.Common.BUNDLE_HISTORY
17
- import com.rnhotupdate.Common.DEFAULT_MAX_BUNDLE_VERSIONS
18
17
  import com.rnhotupdate.SharedPrefs
19
18
  import kotlinx.coroutines.CoroutineScope
20
19
  import kotlinx.coroutines.Dispatchers
@@ -22,7 +21,12 @@ import kotlinx.coroutines.SupervisorJob
22
21
  import kotlinx.coroutines.cancel
23
22
  import kotlinx.coroutines.launch
24
23
  import kotlinx.coroutines.withContext
24
+ import android.util.Base64
25
+ import com.facebook.react.bridge.UiThreadUtil
26
+ import java.util.concurrent.Executors
25
27
  import java.io.File
28
+ import java.io.FileOutputStream
29
+ import java.io.IOException
26
30
  import org.json.JSONArray
27
31
  import org.json.JSONObject
28
32
 
@@ -37,6 +41,7 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
37
41
  OtaHotUpdateSpec(context) {
38
42
  private val utils: Utils = Utils(context)
39
43
  private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
44
+ private val fileWriterExecutor = Executors.newSingleThreadExecutor()
40
45
 
41
46
  override fun getName(): String {
42
47
  return NAME
@@ -45,6 +50,7 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
45
50
  override fun invalidate() {
46
51
  super.invalidate()
47
52
  scope.cancel()
53
+ fileWriterExecutor.shutdown()
48
54
  }
49
55
 
50
56
  private fun loadBundleHistory(): List<BundleVersion> {
@@ -182,7 +188,11 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
182
188
  val versionsToKeep = finalHistory.map { it.version }.toSet()
183
189
  updatedHistory.forEach { bundle ->
184
190
  if (bundle.version !in versionsToKeep) {
185
- utils.deleteOldBundleIfneeded(bundle.path)
191
+ val bundleFile = File(bundle.path)
192
+ val parentDir = bundleFile.parentFile
193
+ if (parentDir != null && parentDir.exists() && parentDir.isDirectory) {
194
+ utils.deleteDirectory(parentDir)
195
+ }
186
196
  }
187
197
  }
188
198
 
@@ -194,7 +204,13 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
194
204
  sharedPrefs.putString(VERSION, version.toString())
195
205
  }
196
206
 
197
- private fun processBundleFile(path: String?, extension: String?, version: Int?, maxVersions: Int?, metadata: String?): Boolean {
207
+ private fun processBundleFile(
208
+ path: String?,
209
+ extension: String?,
210
+ version: Int?,
211
+ maxVersions: Int?,
212
+ metadata: String?
213
+ ): Boolean {
198
214
  if (path != null) {
199
215
  val file = File(path)
200
216
  if (file.exists() && file.isFile) {
@@ -230,8 +246,16 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
230
246
  throw Exception("Invalid path: $path")
231
247
  }
232
248
  }
249
+
233
250
  @ReactMethod
234
- override fun setupBundlePath(path: String?, extension: String?, version: Double?, maxVersions: Double?, metadata: String?, promise: Promise) {
251
+ override fun setupBundlePath(
252
+ path: String?,
253
+ extension: String?,
254
+ version: Double?,
255
+ maxVersions: Double?,
256
+ metadata: String?,
257
+ promise: Promise
258
+ ) {
235
259
  scope.launch {
236
260
  try {
237
261
  val versionInt = version?.toInt()
@@ -282,8 +306,11 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
282
306
 
283
307
  @ReactMethod
284
308
  override fun restart() {
285
- val context: Context? = reactApplicationContext.currentActivity
286
- ProcessPhoenix.triggerRebirth(context)
309
+ val activity = reactApplicationContext.currentActivity
310
+ val context: Context = activity ?: reactApplicationContext
311
+ UiThreadUtil.runOnUiThread {
312
+ ProcessPhoenix.triggerRebirth(context)
313
+ }
287
314
  }
288
315
 
289
316
  @ReactMethod
@@ -509,6 +536,52 @@ class OtaHotUpdateModule internal constructor(context: ReactApplicationContext)
509
536
  }
510
537
  }
511
538
  }
539
+
540
+ }
541
+
542
+ override fun writeFile(
543
+ path: String?,
544
+ base64Content: String?,
545
+ encoding: String?,
546
+ promise: Promise?
547
+ ) {
548
+ if (path == null || base64Content == null) {
549
+ promise?.reject("INVALID_ARG", "Path and base64Content are required", null)
550
+ return
551
+ }
552
+
553
+ fileWriterExecutor.execute {
554
+ try {
555
+ // Decode base64 to bytes
556
+ val bytes = Base64.decode(base64Content, Base64.DEFAULT)
557
+
558
+ // Ensure parent directory exists
559
+ val file = File(path)
560
+ val parentDir = file.parentFile
561
+ if (parentDir != null && !parentDir.exists()) {
562
+ parentDir.mkdirs()
563
+ }
564
+
565
+ // Write file on background thread
566
+ FileOutputStream(file).use { fos ->
567
+ fos.write(bytes)
568
+ fos.flush()
569
+ }
570
+
571
+ // Resolve on UI thread (React Native requirement)
572
+ UiThreadUtil.runOnUiThread {
573
+ promise?.resolve(true)
574
+ }
575
+ } catch (e: IOException) {
576
+ UiThreadUtil.runOnUiThread {
577
+ promise?.reject("WRITE_ERROR", "Failed to write file: ${e.message}", e)
578
+ }
579
+ } catch (e: Exception) {
580
+ UiThreadUtil.runOnUiThread {
581
+ promise?.reject("WRITE_ERROR", "Unexpected error: ${e.message}", e)
582
+ }
583
+ }
584
+ }
512
585
  }
513
586
 
514
587
  companion object {
@@ -19,4 +19,5 @@ abstract class OtaHotUpdateSpec internal constructor(context: ReactApplicationCo
19
19
  abstract fun getBundleList(a: Double, promise: Promise)
20
20
  abstract fun deleteBundleById(id: String, promise: Promise)
21
21
  abstract fun clearAllBundles(a: Double, promise: Promise)
22
+ abstract fun writeFile(path: String?, base64Content: String?, encoding: String?, promise: Promise)
22
23
  }
@@ -14,6 +14,9 @@ static BOOL isBeginning = YES;
14
14
  @implementation OtaHotUpdate
15
15
  RCT_EXPORT_MODULE()
16
16
 
17
+ + (BOOL)requiresMainQueueSetup {
18
+ return NO;
19
+ }
17
20
 
18
21
  - (instancetype)init {
19
22
  self = [super init];
@@ -36,16 +39,24 @@ RCT_EXPORT_MODULE()
36
39
  void OTASignalHandler(int sig) {
37
40
  if (isBeginning) {
38
41
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
39
- NSString *oldPath = [defaults stringForKey:@"OLD_PATH"];
40
- if (oldPath) {
42
+ // Use PREVIOUS_BUNDLE_PATH (simple key, written by saveBundleVersion before each update)
43
+ NSString *previousPath = [defaults stringForKey:@"PREVIOUS_BUNDLE_PATH"];
44
+ if (previousPath && previousPath.length > 0) {
41
45
  BOOL isDeleted = [OtaHotUpdate removeBundleIfNeeded:@"PATH"];
42
46
  if (isDeleted) {
43
- [defaults setObject:oldPath forKey:@"PATH"];
47
+ [defaults setObject:previousPath forKey:@"PATH"];
48
+ NSString *previousVersion = [defaults stringForKey:@"PREVIOUS_BUNDLE_VERSION"];
49
+ if (previousVersion) {
50
+ [defaults setObject:previousVersion forKey:@"VERSION"];
51
+ }
52
+ } else {
53
+ [defaults removeObjectForKey:@"PATH"];
44
54
  }
45
- [defaults removeObjectForKey:@"OLD_PATH"];
46
55
  } else {
47
56
  [defaults removeObjectForKey:@"PATH"];
48
57
  }
58
+ [defaults removeObjectForKey:@"PREVIOUS_BUNDLE_PATH"];
59
+ [defaults removeObjectForKey:@"PREVIOUS_BUNDLE_VERSION"];
49
60
  [defaults synchronize];
50
61
  }
51
62
 
@@ -55,20 +66,24 @@ void OTASignalHandler(int sig) {
55
66
  void OTAExceptionHandler(NSException *exception) {
56
67
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
57
68
  if (isBeginning) {
58
- NSString *oldPath = [defaults stringForKey:@"OLD_PATH"];
59
- if (oldPath) {
60
- BOOL isDeleted = [OtaHotUpdate removeBundleIfNeeded:@"PATH"];
61
- if (isDeleted) {
62
- [defaults setObject:oldPath forKey:@"PATH"];
63
- [defaults removeObjectForKey:@"OLD_PATH"];
64
- } else {
65
- [defaults removeObjectForKey:@"OLD_PATH"];
66
- [defaults removeObjectForKey:@"PATH"];
67
- }
69
+ NSString *previousPath = [defaults stringForKey:@"PREVIOUS_BUNDLE_PATH"];
70
+ if (previousPath && previousPath.length > 0) {
71
+ BOOL isDeleted = [OtaHotUpdate removeBundleIfNeeded:@"PATH"];
72
+ if (isDeleted) {
73
+ [defaults setObject:previousPath forKey:@"PATH"];
74
+ NSString *previousVersion = [defaults stringForKey:@"PREVIOUS_BUNDLE_VERSION"];
75
+ if (previousVersion) {
76
+ [defaults setObject:previousVersion forKey:@"VERSION"];
77
+ }
78
+ } else {
79
+ [defaults removeObjectForKey:@"PATH"];
80
+ }
68
81
  } else {
69
- [defaults removeObjectForKey:@"PATH"];
82
+ [defaults removeObjectForKey:@"PATH"];
70
83
  }
71
- [defaults synchronize];
84
+ [defaults removeObjectForKey:@"PREVIOUS_BUNDLE_PATH"];
85
+ [defaults removeObjectForKey:@"PREVIOUS_BUNDLE_VERSION"];
86
+ [defaults synchronize];
72
87
  } else if (previousHandler) {
73
88
  previousHandler(exception);
74
89
  }
@@ -237,7 +252,7 @@ void OTAExceptionHandler(NSException *exception) {
237
252
  [dateFormatter setDateFormat:@"yyyy_MM_dd_HH_mm"];
238
253
  [dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
239
254
  NSString *timestamp = [dateFormatter stringFromDate:[NSDate date]];
240
- NSString *folderName = version != nil
255
+ NSString *folderName = version != nil
241
256
  ? [NSString stringWithFormat:@"output_v%@_%@", version, timestamp]
242
257
  : [NSString stringWithFormat:@"output_%@", timestamp];
243
258
  NSString *newFolderPath = [directoryPath stringByAppendingPathComponent:folderName];
@@ -297,13 +312,11 @@ RCT_EXPORT_METHOD(setupBundlePath:(NSString *)path extension:(NSString *)extensi
297
312
  resolve:(RCTPromiseResolveBlock)resolve
298
313
  reject:(RCTPromiseRejectBlock)reject) {
299
314
  if ([OtaHotUpdate isFilePathValid:path]) {
300
- [OtaHotUpdate removeBundleIfNeeded:nil];
301
315
  //Unzip file
302
316
  NSString *extractedFilePath = [self unzipFileAtPath:path extension:(extension != nil) ? extension : @".jsbundle" version:version];
303
317
  if (extractedFilePath) {
304
318
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
305
- NSString *oldPath = [defaults stringForKey:@"PATH"];
306
-
319
+
307
320
  // If version is provided, save to history system
308
321
  if (version != nil) {
309
322
  // Default maxVersions to 2 if not provided (backward compatible)
@@ -314,7 +327,7 @@ RCT_EXPORT_METHOD(setupBundlePath:(NSString *)path extension:(NSString *)extensi
314
327
  // No version (e.g., Git update) - just set path, no history
315
328
  [defaults setObject:extractedFilePath forKey:@"PATH"];
316
329
  }
317
-
330
+
318
331
  [defaults setObject:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] forKey:@"VERSION_NAME"];
319
332
  [defaults synchronize];
320
333
  isBeginning = YES;
@@ -331,10 +344,10 @@ RCT_EXPORT_METHOD(deleteBundle:(double)i
331
344
  reject:(RCTPromiseRejectBlock)reject) {
332
345
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
333
346
  NSString *currentPath = [defaults stringForKey:@"PATH"];
334
-
347
+
335
348
  // Delete current bundle from file system
336
349
  BOOL isDeleted = [OtaHotUpdate removeBundleIfNeeded:@"PATH"];
337
-
350
+
338
351
  // Remove current bundle from history if exists
339
352
  if (currentPath && currentPath.length > 0) {
340
353
  NSArray *history = [self loadBundleHistory];
@@ -346,12 +359,12 @@ RCT_EXPORT_METHOD(deleteBundle:(double)i
346
359
  }
347
360
  [self saveBundleHistory:updatedHistory];
348
361
  }
349
-
362
+
350
363
  // Clear paths and version
351
364
  [defaults removeObjectForKey:@"PATH"];
352
365
  [defaults setObject:@"0" forKey:@"VERSION"];
353
366
  [defaults synchronize];
354
-
367
+
355
368
  resolve(@(isDeleted));
356
369
  }
357
370
  // Expose deleteBundle method to JavaScript
@@ -360,7 +373,7 @@ RCT_EXPORT_METHOD(rollbackToPreviousBundle:(double)i
360
373
  reject:(RCTPromiseRejectBlock)reject) {
361
374
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
362
375
  NSString *currentPath = [defaults stringForKey:@"PATH"];
363
-
376
+
364
377
  // Use history to find previous version
365
378
  NSArray *history = [self loadBundleHistory];
366
379
  if (history.count > 0 && currentPath && currentPath.length > 0) {
@@ -372,7 +385,7 @@ RCT_EXPORT_METHOD(rollbackToPreviousBundle:(double)i
372
385
  break;
373
386
  }
374
387
  }
375
-
388
+
376
389
  if (currentBundle) {
377
390
  // Find previous version (older than current, max version)
378
391
  NSDictionary *previousBundle = nil;
@@ -385,7 +398,7 @@ RCT_EXPORT_METHOD(rollbackToPreviousBundle:(double)i
385
398
  }
386
399
  }
387
400
  }
388
-
401
+
389
402
  if (previousBundle && [OtaHotUpdate isFilePathValid:previousBundle[@"path"]]) {
390
403
  // Rollback to previous bundle from history
391
404
  BOOL isDeleted = [OtaHotUpdate removeBundleIfNeeded:@"PATH"];
@@ -399,7 +412,7 @@ RCT_EXPORT_METHOD(rollbackToPreviousBundle:(double)i
399
412
  }
400
413
  }
401
414
  }
402
-
415
+
403
416
  resolve(@(NO));
404
417
  }
405
418
 
@@ -478,7 +491,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
478
491
  - (NSArray *)loadBundleHistory {
479
492
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
480
493
  NSString *historyJson = [defaults stringForKey:@"BUNDLE_HISTORY"];
481
-
494
+
482
495
  // If history exists, load it
483
496
  if (historyJson && historyJson.length > 0) {
484
497
  NSData *data = [historyJson dataUsingEncoding:NSUTF8StringEncoding];
@@ -488,20 +501,20 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
488
501
  return history;
489
502
  }
490
503
  }
491
-
504
+
492
505
  // Migration: If history is empty but PATH exists, migrate from old system
493
506
  NSString *currentPath = [defaults stringForKey:@"PATH"];
494
507
  NSString *currentVersion = [defaults stringForKey:@"VERSION"];
495
508
  NSString *previousPath = [defaults stringForKey:@"OLD_PATH"];
496
509
  NSString *previousVersion = [defaults stringForKey:@"PREVIOUS_VERSION"];
497
-
510
+
498
511
  if (!currentPath || currentPath.length == 0) {
499
512
  return @[];
500
513
  }
501
-
514
+
502
515
  // Migrate current bundle
503
516
  NSMutableArray *migratedHistory = [NSMutableArray array];
504
-
517
+
505
518
  // Add current bundle if has version
506
519
  if (currentVersion && currentVersion.length > 0) {
507
520
  NSInteger version = [currentVersion integerValue];
@@ -510,7 +523,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
510
523
  NSDictionary *attributes = [fileManager attributesOfItemAtPath:currentPath error:nil];
511
524
  NSDate *modificationDate = attributes[NSFileModificationDate];
512
525
  long long timestamp = modificationDate ? (long long)([modificationDate timeIntervalSince1970] * 1000) : (long long)([[NSDate date] timeIntervalSince1970] * 1000);
513
-
526
+
514
527
  NSMutableDictionary *bundle = [NSMutableDictionary dictionary];
515
528
  bundle[@"version"] = @(version);
516
529
  bundle[@"path"] = currentPath;
@@ -519,7 +532,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
519
532
  [migratedHistory addObject:bundle];
520
533
  }
521
534
  }
522
-
535
+
523
536
  // Add previous bundle if exists
524
537
  if (previousPath && previousPath.length > 0 && previousVersion && previousVersion.length > 0) {
525
538
  NSInteger version = [previousVersion integerValue];
@@ -528,7 +541,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
528
541
  NSDictionary *attributes = [fileManager attributesOfItemAtPath:previousPath error:nil];
529
542
  NSDate *modificationDate = attributes[NSFileModificationDate];
530
543
  long long timestamp = modificationDate ? (long long)([modificationDate timeIntervalSince1970] * 1000) : (long long)([[NSDate date] timeIntervalSince1970] * 1000);
531
-
544
+
532
545
  NSMutableDictionary *bundle = [NSMutableDictionary dictionary];
533
546
  bundle[@"version"] = @(version);
534
547
  bundle[@"path"] = previousPath;
@@ -537,7 +550,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
537
550
  [migratedHistory addObject:bundle];
538
551
  }
539
552
  }
540
-
553
+
541
554
  // Save migrated history if any
542
555
  if (migratedHistory.count > 0) {
543
556
  // Sort by version descending
@@ -551,7 +564,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
551
564
  [self saveBundleHistory:sortedHistory];
552
565
  return sortedHistory;
553
566
  }
554
-
567
+
555
568
  return @[];
556
569
  }
557
570
 
@@ -573,7 +586,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
573
586
  - (void)saveBundleVersion:(NSString *)path version:(NSInteger)version maxVersions:(NSInteger)maxVersions metadata:(NSString *)metadata {
574
587
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
575
588
  NSArray *history = [self loadBundleHistory];
576
-
589
+
577
590
  // Create new bundle entry
578
591
  NSMutableDictionary *newBundle = [NSMutableDictionary dictionary];
579
592
  newBundle[@"version"] = @(version);
@@ -582,11 +595,11 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
582
595
  if (metadata) {
583
596
  newBundle[@"metadata"] = metadata;
584
597
  }
585
-
598
+
586
599
  // Combine with existing history
587
600
  NSMutableArray *updatedHistory = [NSMutableArray arrayWithObject:newBundle];
588
601
  [updatedHistory addObjectsFromArray:history];
589
-
602
+
590
603
  // Sort by version descending and remove duplicates
591
604
  [updatedHistory sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
592
605
  NSInteger v1 = [obj1[@"version"] integerValue];
@@ -595,7 +608,7 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
595
608
  if (v1 < v2) return NSOrderedDescending;
596
609
  return NSOrderedSame;
597
610
  }];
598
-
611
+
599
612
  // Remove duplicates by version
600
613
  NSMutableArray *uniqueHistory = [NSMutableArray array];
601
614
  NSMutableSet *seenVersions = [NSMutableSet set];
@@ -606,25 +619,35 @@ RCT_EXPORT_METHOD(setExactBundlePath:(NSString *)path
606
619
  [uniqueHistory addObject:bundle];
607
620
  }
608
621
  }
609
-
622
+
610
623
  // Keep only maxVersions most recent
611
624
  NSArray *finalHistory = [uniqueHistory subarrayWithRange:NSMakeRange(0, MIN(maxVersions, uniqueHistory.count))];
612
-
625
+
613
626
  // Delete old versions beyond limit
614
627
  NSMutableSet *versionsToKeep = [NSMutableSet set];
615
628
  for (NSDictionary *bundle in finalHistory) {
616
629
  [versionsToKeep addObject:bundle[@"version"]];
617
630
  }
618
-
631
+
619
632
  for (NSDictionary *bundle in uniqueHistory) {
620
633
  if (![versionsToKeep containsObject:bundle[@"version"]]) {
621
634
  [OtaHotUpdate deleteBundleAtPath:bundle[@"path"]];
622
635
  }
623
636
  }
624
-
637
+
625
638
  // Save updated history
626
639
  [self saveBundleHistory:finalHistory];
627
-
640
+
641
+ // Before updating current path, save it as fallback for crash handler
642
+ NSString *currentPath = [defaults stringForKey:@"PATH"];
643
+ NSString *currentVersion = [defaults stringForKey:@"VERSION"];
644
+ if (currentPath && currentPath.length > 0) {
645
+ [defaults setObject:currentPath forKey:@"PREVIOUS_BUNDLE_PATH"];
646
+ if (currentVersion) {
647
+ [defaults setObject:currentVersion forKey:@"PREVIOUS_BUNDLE_VERSION"];
648
+ }
649
+ }
650
+
628
651
  // Set current path and version
629
652
  [defaults setObject:path forKey:@"PATH"];
630
653
  [defaults setObject:[NSString stringWithFormat:@"%ld", (long)version] forKey:@"VERSION"];
@@ -649,7 +672,7 @@ RCT_EXPORT_METHOD(getBundleList:(double)a
649
672
  NSArray *history = [self loadBundleHistory];
650
673
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
651
674
  NSString *activePath = [defaults stringForKey:@"PATH"];
652
-
675
+
653
676
  NSMutableArray *bundleList = [NSMutableArray array];
654
677
  for (NSDictionary *bundle in history) {
655
678
  NSString *path = bundle[@"path"];
@@ -669,7 +692,7 @@ RCT_EXPORT_METHOD(getBundleList:(double)a
669
692
  }
670
693
  [bundleList addObject:bundleInfo];
671
694
  }
672
-
695
+
673
696
  NSError *error = nil;
674
697
  NSData *data = [NSJSONSerialization dataWithJSONObject:bundleList options:0 error:&error];
675
698
  if (!error && data) {
@@ -686,7 +709,7 @@ RCT_EXPORT_METHOD(deleteBundleById:(NSString *)id
686
709
  NSArray *history = [self loadBundleHistory];
687
710
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
688
711
  NSString *activePath = [defaults stringForKey:@"PATH"];
689
-
712
+
690
713
  NSDictionary *bundleToDelete = nil;
691
714
  for (NSDictionary *bundle in history) {
692
715
  NSString *folderName = [self extractFolderName:bundle[@"path"]];
@@ -695,12 +718,12 @@ RCT_EXPORT_METHOD(deleteBundleById:(NSString *)id
695
718
  break;
696
719
  }
697
720
  }
698
-
721
+
699
722
  if (!bundleToDelete) {
700
723
  resolve(@(NO));
701
724
  return;
702
725
  }
703
-
726
+
704
727
  // If deleting active bundle, rollback to oldest remaining bundle or clear
705
728
  if ([bundleToDelete[@"path"] isEqualToString:activePath]) {
706
729
  NSMutableArray *remainingBundles = [NSMutableArray array];
@@ -725,10 +748,10 @@ RCT_EXPORT_METHOD(deleteBundleById:(NSString *)id
725
748
  }
726
749
  [defaults synchronize];
727
750
  }
728
-
751
+
729
752
  // Delete bundle folder
730
753
  BOOL isDeleted = [OtaHotUpdate deleteBundleAtPath:bundleToDelete[@"path"]];
731
-
754
+
732
755
  // Remove from history
733
756
  NSMutableArray *updatedHistory = [NSMutableArray array];
734
757
  for (NSDictionary *bundle in history) {
@@ -737,7 +760,7 @@ RCT_EXPORT_METHOD(deleteBundleById:(NSString *)id
737
760
  }
738
761
  }
739
762
  [self saveBundleHistory:updatedHistory];
740
-
763
+
741
764
  resolve(@(isDeleted));
742
765
  }
743
766
 
@@ -746,23 +769,63 @@ RCT_EXPORT_METHOD(clearAllBundles:(double)a
746
769
  reject:(RCTPromiseRejectBlock)reject) {
747
770
  NSArray *history = [self loadBundleHistory];
748
771
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
749
-
772
+
750
773
  // Delete all bundle folders
751
774
  for (NSDictionary *bundle in history) {
752
775
  [OtaHotUpdate deleteBundleAtPath:bundle[@"path"]];
753
776
  }
754
-
777
+
755
778
  // Clear history
756
779
  [self saveBundleHistory:@[]];
757
-
780
+
758
781
  // Clear current path and version
759
782
  [defaults removeObjectForKey:@"PATH"];
760
783
  [defaults removeObjectForKey:@"VERSION"];
761
784
  [defaults synchronize];
762
-
785
+
763
786
  resolve(@(YES));
764
787
  }
765
788
 
789
+ RCT_EXPORT_METHOD(writeFile:(NSString *)path
790
+ base64Content:(NSString *)base64Content
791
+ encoding:(NSString *)encoding
792
+ resolve:(RCTPromiseResolveBlock)resolve
793
+ reject:(RCTPromiseRejectBlock)reject) {
794
+ // Run on background queue to avoid blocking JS thread
795
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
796
+ @try {
797
+ // Decode base64 to NSData
798
+ NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Content options:0];
799
+ if (!data) {
800
+ reject(@"DECODE_ERROR", @"Failed to decode base64 content", nil);
801
+ return;
802
+ }
803
+
804
+ // Ensure parent directory exists
805
+ NSString *parentDir = [path stringByDeletingLastPathComponent];
806
+ NSFileManager *fileManager = [NSFileManager defaultManager];
807
+ if (![fileManager fileExistsAtPath:parentDir]) {
808
+ NSError *error;
809
+ if (![fileManager createDirectoryAtPath:parentDir withIntermediateDirectories:YES attributes:nil error:&error]) {
810
+ reject(@"CREATE_DIR_ERROR", [NSString stringWithFormat:@"Failed to create directory: %@", error.localizedDescription], error);
811
+ return;
812
+ }
813
+ }
814
+
815
+ // Write file on background thread
816
+ NSError *error;
817
+ if (![data writeToFile:path options:NSDataWritingAtomic error:&error]) {
818
+ reject(@"WRITE_ERROR", [NSString stringWithFormat:@"Failed to write file: %@", error.localizedDescription], error);
819
+ return;
820
+ }
821
+
822
+ resolve(@(YES));
823
+ } @catch (NSException *exception) {
824
+ reject(@"WRITE_ERROR", [NSString stringWithFormat:@"Unexpected error: %@", exception.reason], nil);
825
+ }
826
+ });
827
+ }
828
+
766
829
  // Don't compile this code when we build for the old architecture.
767
830
  #ifdef RCT_NEW_ARCH_ENABLED
768
831
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
@@ -74,6 +74,10 @@ namespace facebook::react {
74
74
  return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, "clearAllBundles", @selector(clearAllBundles:resolve:reject:), args, count);
75
75
  }
76
76
 
77
+ static facebook::jsi::Value __hostFunction_NativeOtaHotUpdateSpecJSI_writeFile(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
78
+ return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, PromiseKind, "writeFile", @selector(writeFile:base64Content:encoding:resolve:reject:), args, count);
79
+ }
80
+
77
81
  NativeOtaHotUpdateSpecJSI::NativeOtaHotUpdateSpecJSI(const ObjCTurboModule::InitParams &params)
78
82
  : ObjCTurboModule(params) {
79
83
 
@@ -112,5 +116,8 @@ namespace facebook::react {
112
116
 
113
117
  methodMap_["clearAllBundles"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateSpecJSI_clearAllBundles};
114
118
 
119
+
120
+ methodMap_["writeFile"] = MethodMetadata {3, __hostFunction_NativeOtaHotUpdateSpecJSI_writeFile};
121
+
115
122
  }
116
123
  } // namespace facebook::react
@@ -71,6 +71,11 @@
71
71
  - (void)clearAllBundles:(double)a
72
72
  resolve:(RCTPromiseResolveBlock)resolve
73
73
  reject:(RCTPromiseRejectBlock)reject;
74
+ - (void)writeFile:(NSString *)path
75
+ base64Content:(NSString *)base64Content
76
+ encoding:(NSString *)encoding
77
+ resolve:(RCTPromiseResolveBlock)resolve
78
+ reject:(RCTPromiseRejectBlock)reject;
74
79
 
75
80
  @end
76
81
 
@@ -87,6 +87,14 @@ static jsi::Value __hostFunction_NativeOtaHotUpdateCxxSpecJSI_clearAllBundles(js
87
87
  count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asNumber()
88
88
  );
89
89
  }
90
+ static jsi::Value __hostFunction_NativeOtaHotUpdateCxxSpecJSI_writeFile(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
91
+ return static_cast<NativeOtaHotUpdateCxxSpecJSI *>(&turboModule)->writeFile(
92
+ rt,
93
+ count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt),
94
+ count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt),
95
+ count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt)
96
+ );
97
+ }
90
98
 
91
99
  NativeOtaHotUpdateCxxSpecJSI::NativeOtaHotUpdateCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
92
100
  : TurboModule("OtaHotUpdate", jsInvoker) {
@@ -102,6 +110,7 @@ NativeOtaHotUpdateCxxSpecJSI::NativeOtaHotUpdateCxxSpecJSI(std::shared_ptr<CallI
102
110
  methodMap_["getBundleList"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_getBundleList};
103
111
  methodMap_["deleteBundleById"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_deleteBundleById};
104
112
  methodMap_["clearAllBundles"] = MethodMetadata {1, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_clearAllBundles};
113
+ methodMap_["writeFile"] = MethodMetadata {3, __hostFunction_NativeOtaHotUpdateCxxSpecJSI_writeFile};
105
114
  }
106
115
 
107
116
 
@@ -32,6 +32,7 @@ public:
32
32
  virtual jsi::Value getBundleList(jsi::Runtime &rt, double a) = 0;
33
33
  virtual jsi::Value deleteBundleById(jsi::Runtime &rt, jsi::String id) = 0;
34
34
  virtual jsi::Value clearAllBundles(jsi::Runtime &rt, double a) = 0;
35
+ virtual jsi::Value writeFile(jsi::Runtime &rt, jsi::String path, jsi::String base64Content, jsi::String encoding) = 0;
35
36
 
36
37
  };
37
38
 
@@ -154,6 +155,14 @@ private:
154
155
  return bridging::callFromJs<jsi::Value>(
155
156
  rt, &T::clearAllBundles, jsInvoker_, instance_, std::move(a));
156
157
  }
158
+ jsi::Value writeFile(jsi::Runtime &rt, jsi::String path, jsi::String base64Content, jsi::String encoding) override {
159
+ static_assert(
160
+ bridging::getParameterCount(&T::writeFile) == 4,
161
+ "Expected writeFile(...) to have 4 parameters");
162
+
163
+ return bridging::callFromJs<jsi::Value>(
164
+ rt, &T::writeFile, jsInvoker_, instance_, std::move(path), std::move(base64Content), std::move(encoding));
165
+ }
157
166
 
158
167
  private:
159
168
  friend class NativeOtaHotUpdateCxxSpec;
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeOtaHotUpdate.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAAmD,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAiBpCC,gCAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeOtaHotUpdate.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAAmD,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAkBpCC,gCAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
@@ -16,6 +16,17 @@ let RNFS = {
16
16
  try {
17
17
  RNFS = require('react-native-fs');
18
18
  } catch {}
19
+
20
+ // Try to load native OtaHotUpdate module for better performance
21
+ let OtaHotUpdateNative = null;
22
+ try {
23
+ const {
24
+ NativeModules
25
+ } = require('react-native');
26
+ OtaHotUpdateNative = NativeModules.OtaHotUpdate;
27
+ } catch (e) {
28
+ // Native module not available, will fallback to RNFS
29
+ }
19
30
  function Err(name) {
20
31
  return class extends Error {
21
32
  code = name;
@@ -83,12 +94,27 @@ const writeFile = async (path, content, opts) => {
83
94
  encoding = opts.encoding;
84
95
  }
85
96
  if (typeof content === 'string') {
97
+ // Text file - use RNFS (fast enough for text)
86
98
  encoding = encoding || 'utf8';
99
+ await RNFS.writeFile(path, content, encoding);
87
100
  } else {
101
+ // Binary file - try native module first for better performance
88
102
  encoding = 'base64';
89
- content = _buffer.Buffer.from(content).toString('base64');
103
+ const base64Content = _buffer.Buffer.from(content).toString('base64');
104
+ if (OtaHotUpdateNative && OtaHotUpdateNative.writeFile) {
105
+ try {
106
+ // Use native write (runs on native thread, doesn't block JS thread)
107
+ await OtaHotUpdateNative.writeFile(path, base64Content, encoding);
108
+ } catch (e) {
109
+ // Fallback to RNFS if native fails
110
+ console.warn('OtaHotUpdate.writeFile failed, falling back to RNFS:', e);
111
+ await RNFS.writeFile(path, base64Content, encoding);
112
+ }
113
+ } else {
114
+ // No native module available - use RNFS
115
+ await RNFS.writeFile(path, base64Content, encoding);
116
+ }
90
117
  }
91
- await RNFS.writeFile(path, content, encoding);
92
118
  };
93
119
  exports.writeFile = writeFile;
94
120
  const stat = async path => {
@@ -1 +1 @@
1
- {"version":3,"names":["_buffer","require","RNFS","unlink","console","log","readdir","mkdir","readFile","writeFile","stat","Err","name","Error","code","constructor","args","message","ENOENT","ENOTDIR","path","err","exports","opts","encoding","result","Buffer","from","content","toString","r","isSymbolicLink","lstat","rmdir","readlink","symlink","chmod"],"sourceRoot":"../../../../src","sources":["gits/helper/fs.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_buffer","require","RNFS","unlink","console","log","readdir","mkdir","readFile","writeFile","stat","OtaHotUpdateNative","NativeModules","OtaHotUpdate","e","Err","name","Error","code","constructor","args","message","ENOENT","ENOTDIR","path","err","exports","opts","encoding","result","Buffer","from","content","base64Content","toString","warn","r","isSymbolicLink","lstat","rmdir","readlink","symlink","chmod"],"sourceRoot":"../../../../src","sources":["gits/helper/fs.ts"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeOtaHotUpdate.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAiBlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeOtaHotUpdate.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAkBlD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,cAAc,CAAC","ignoreList":[]}
@@ -12,6 +12,17 @@ let RNFS = {
12
12
  try {
13
13
  RNFS = require('react-native-fs');
14
14
  } catch {}
15
+
16
+ // Try to load native OtaHotUpdate module for better performance
17
+ let OtaHotUpdateNative = null;
18
+ try {
19
+ const {
20
+ NativeModules
21
+ } = require('react-native');
22
+ OtaHotUpdateNative = NativeModules.OtaHotUpdate;
23
+ } catch (e) {
24
+ // Native module not available, will fallback to RNFS
25
+ }
15
26
  function Err(name) {
16
27
  return class extends Error {
17
28
  code = name;
@@ -76,12 +87,27 @@ export const writeFile = async (path, content, opts) => {
76
87
  encoding = opts.encoding;
77
88
  }
78
89
  if (typeof content === 'string') {
90
+ // Text file - use RNFS (fast enough for text)
79
91
  encoding = encoding || 'utf8';
92
+ await RNFS.writeFile(path, content, encoding);
80
93
  } else {
94
+ // Binary file - try native module first for better performance
81
95
  encoding = 'base64';
82
- content = Buffer.from(content).toString('base64');
96
+ const base64Content = Buffer.from(content).toString('base64');
97
+ if (OtaHotUpdateNative && OtaHotUpdateNative.writeFile) {
98
+ try {
99
+ // Use native write (runs on native thread, doesn't block JS thread)
100
+ await OtaHotUpdateNative.writeFile(path, base64Content, encoding);
101
+ } catch (e) {
102
+ // Fallback to RNFS if native fails
103
+ console.warn('OtaHotUpdate.writeFile failed, falling back to RNFS:', e);
104
+ await RNFS.writeFile(path, base64Content, encoding);
105
+ }
106
+ } else {
107
+ // No native module available - use RNFS
108
+ await RNFS.writeFile(path, base64Content, encoding);
109
+ }
83
110
  }
84
- await RNFS.writeFile(path, content, encoding);
85
111
  };
86
112
  export const stat = async path => {
87
113
  try {
@@ -1 +1 @@
1
- {"version":3,"names":["Buffer","RNFS","unlink","console","log","readdir","mkdir","readFile","writeFile","stat","require","Err","name","Error","code","constructor","args","message","ENOENT","ENOTDIR","path","err","opts","encoding","result","from","content","toString","r","isSymbolicLink","lstat","rmdir","readlink","symlink","chmod"],"sourceRoot":"../../../../src","sources":["gits/helper/fs.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["Buffer","RNFS","unlink","console","log","readdir","mkdir","readFile","writeFile","stat","require","OtaHotUpdateNative","NativeModules","OtaHotUpdate","e","Err","name","Error","code","constructor","args","message","ENOENT","ENOTDIR","path","err","opts","encoding","result","from","content","base64Content","toString","warn","r","isSymbolicLink","lstat","rmdir","readlink","symlink","chmod"],"sourceRoot":"../../../../src","sources":["gits/helper/fs.ts"],"mappings":"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","ignoreList":[]}
@@ -12,6 +12,7 @@ export interface Spec extends TurboModule {
12
12
  getBundleList(a: number): Promise<string>;
13
13
  deleteBundleById(id: string): Promise<boolean>;
14
14
  clearAllBundles(a: number): Promise<boolean>;
15
+ writeFile(path: string, base64Content: string, encoding: string): Promise<boolean>;
15
16
  }
16
17
  declare const _default: Spec;
17
18
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeOtaHotUpdate.d.ts","sourceRoot":"","sources":["../../../../src/NativeOtaHotUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9H,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC;IAChB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;;AAED,wBAAsE"}
1
+ {"version":3,"file":"NativeOtaHotUpdate.d.ts","sourceRoot":"","sources":["../../../../src/NativeOtaHotUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9H,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC;IAChB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;;AAED,wBAAsE"}
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../../../src/gits/helper/fs.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,OAAO,SAAgB,MAAM,kBAezC,CAAC;AAEF,eAAO,MAAM,KAAK,SAAgB,MAAM,kBAEvC,CAAC;AAEF,eAAO,MAAM,QAAQ,SACb,MAAM,SACL,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kDAsB1C,CAAC;AACF,eAAO,MAAM,SAAS,SACd,MAAM,WACH,MAAM,GAAG,UAAU,SACrB,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kBAkB1C,CAAC;AAEF,eAAO,MAAM,IAAI,SAAgB,MAAM,kBAiBtC,CAAC;AAGF,eAAO,MAAM,KAAK,SApBe,MAAM,kBAoBd,CAAC;AAE1B,eAAO,MAAM,MAAM,SAAgB,MAAM,kBAYxC,CAAC;AAGF,eAAO,MAAM,KAAK,SAfiB,MAAM,kBAed,CAAC;AAG5B,eAAO,MAAM,QAAQ,sBAEpB,CAAC;AACF,eAAO,MAAM,OAAO,sBAEnB,CAAC;AAIF,eAAO,MAAM,KAAK,sBAEjB,CAAC"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../../../src/gits/helper/fs.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,OAAO,SAAgB,MAAM,kBAezC,CAAC;AAEF,eAAO,MAAM,KAAK,SAAgB,MAAM,kBAEvC,CAAC;AAEF,eAAO,MAAM,QAAQ,SACb,MAAM,SACL,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kDAsB1C,CAAC;AACF,eAAO,MAAM,SAAS,SACd,MAAM,WACH,MAAM,GAAG,UAAU,SACrB,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kBAiC1C,CAAC;AAEF,eAAO,MAAM,IAAI,SAAgB,MAAM,kBAiBtC,CAAC;AAGF,eAAO,MAAM,KAAK,SApBe,MAAM,kBAoBd,CAAC;AAE1B,eAAO,MAAM,MAAM,SAAgB,MAAM,kBAYxC,CAAC;AAGF,eAAO,MAAM,KAAK,SAfiB,MAAM,kBAed,CAAC;AAG5B,eAAO,MAAM,QAAQ,sBAEpB,CAAC;AACF,eAAO,MAAM,OAAO,sBAEnB,CAAC;AAIF,eAAO,MAAM,KAAK,sBAEjB,CAAC"}
@@ -12,6 +12,7 @@ export interface Spec extends TurboModule {
12
12
  getBundleList(a: number): Promise<string>;
13
13
  deleteBundleById(id: string): Promise<boolean>;
14
14
  clearAllBundles(a: number): Promise<boolean>;
15
+ writeFile(path: string, base64Content: string, encoding: string): Promise<boolean>;
15
16
  }
16
17
  declare const _default: Spec;
17
18
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeOtaHotUpdate.d.ts","sourceRoot":"","sources":["../../../../src/NativeOtaHotUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9H,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC;IAChB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;;AAED,wBAAsE"}
1
+ {"version":3,"file":"NativeOtaHotUpdate.d.ts","sourceRoot":"","sources":["../../../../src/NativeOtaHotUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9H,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAI,IAAI,CAAC;IAChB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpF;;AAED,wBAAsE"}
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../../../src/gits/helper/fs.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,OAAO,SAAgB,MAAM,kBAezC,CAAC;AAEF,eAAO,MAAM,KAAK,SAAgB,MAAM,kBAEvC,CAAC;AAEF,eAAO,MAAM,QAAQ,SACb,MAAM,SACL,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kDAsB1C,CAAC;AACF,eAAO,MAAM,SAAS,SACd,MAAM,WACH,MAAM,GAAG,UAAU,SACrB,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kBAkB1C,CAAC;AAEF,eAAO,MAAM,IAAI,SAAgB,MAAM,kBAiBtC,CAAC;AAGF,eAAO,MAAM,KAAK,SApBe,MAAM,kBAoBd,CAAC;AAE1B,eAAO,MAAM,MAAM,SAAgB,MAAM,kBAYxC,CAAC;AAGF,eAAO,MAAM,KAAK,SAfiB,MAAM,kBAed,CAAC;AAG5B,eAAO,MAAM,QAAQ,sBAEpB,CAAC;AACF,eAAO,MAAM,OAAO,sBAEnB,CAAC;AAIF,eAAO,MAAM,KAAK,sBAEjB,CAAC"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../../../src/gits/helper/fs.ts"],"names":[],"mappings":"AA0CA,eAAO,MAAM,OAAO,SAAgB,MAAM,kBAezC,CAAC;AAEF,eAAO,MAAM,KAAK,SAAgB,MAAM,kBAEvC,CAAC;AAEF,eAAO,MAAM,QAAQ,SACb,MAAM,SACL,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kDAsB1C,CAAC;AACF,eAAO,MAAM,SAAS,SACd,MAAM,WACH,MAAM,GAAG,UAAU,SACrB,MAAM,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,kBAiC1C,CAAC;AAEF,eAAO,MAAM,IAAI,SAAgB,MAAM,kBAiBtC,CAAC;AAGF,eAAO,MAAM,KAAK,SApBe,MAAM,kBAoBd,CAAC;AAE1B,eAAO,MAAM,MAAM,SAAgB,MAAM,kBAYxC,CAAC;AAGF,eAAO,MAAM,KAAK,SAfiB,MAAM,kBAed,CAAC;AAG5B,eAAO,MAAM,QAAQ,sBAEpB,CAAC;AACF,eAAO,MAAM,OAAO,sBAEnB,CAAC;AAIF,eAAO,MAAM,KAAK,sBAEjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ota-hot-update",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "Hot update for react native",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",
@@ -14,6 +14,7 @@ export interface Spec extends TurboModule {
14
14
  getBundleList(a: number): Promise<string>;
15
15
  deleteBundleById(id: string): Promise<boolean>;
16
16
  clearAllBundles(a: number): Promise<boolean>;
17
+ writeFile(path: string, base64Content: string, encoding: string): Promise<boolean>;
17
18
  }
18
19
 
19
20
  export default TurboModuleRegistry.getEnforcing<Spec>('OtaHotUpdate');
@@ -12,6 +12,15 @@ try {
12
12
  RNFS = require('react-native-fs');
13
13
  } catch {}
14
14
 
15
+ // Try to load native OtaHotUpdate module for better performance
16
+ let OtaHotUpdateNative: any = null;
17
+ try {
18
+ const { NativeModules } = require('react-native');
19
+ OtaHotUpdateNative = NativeModules.OtaHotUpdate;
20
+ } catch (e) {
21
+ // Native module not available, will fallback to RNFS
22
+ }
23
+
15
24
  function Err(name: string) {
16
25
  return class extends Error {
17
26
  public code = name;
@@ -91,13 +100,28 @@ export const writeFile = async (
91
100
  }
92
101
 
93
102
  if (typeof content === 'string') {
103
+ // Text file - use RNFS (fast enough for text)
94
104
  encoding = encoding || 'utf8';
105
+ await RNFS.writeFile(path, content, encoding);
95
106
  } else {
107
+ // Binary file - try native module first for better performance
96
108
  encoding = 'base64';
97
- content = Buffer.from(content).toString('base64');
109
+ const base64Content = Buffer.from(content).toString('base64');
110
+
111
+ if (OtaHotUpdateNative && OtaHotUpdateNative.writeFile) {
112
+ try {
113
+ // Use native write (runs on native thread, doesn't block JS thread)
114
+ await OtaHotUpdateNative.writeFile(path, base64Content, encoding);
115
+ } catch (e) {
116
+ // Fallback to RNFS if native fails
117
+ console.warn('OtaHotUpdate.writeFile failed, falling back to RNFS:', e);
118
+ await RNFS.writeFile(path, base64Content, encoding);
119
+ }
120
+ } else {
121
+ // No native module available - use RNFS
122
+ await RNFS.writeFile(path, base64Content, encoding);
123
+ }
98
124
  }
99
-
100
- await RNFS.writeFile(path, content as string, encoding);
101
125
  };
102
126
 
103
127
  export const stat = async (path: string) => {