A simple ota solution for React Native apps
npm install react-native-simple-otaA lightweight OTA (Over-The-Air) update solution for React Native apps. It allows you to update your JavaScript code without going through App Store or Play Store releases.
---
- OTA (Over-The-Air) Updates: Updates pushed remotely to the app without requiring a new version from the App Store / Play Store.
- JS Bundle: The compiled version of your React Native JavaScript code.
>JSC
>
>It can generated using the following commands.
> - Android: react-native bundle --platform android --dev false --entry-file index.js >--bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/>main/res
> - iOS: react-native bundle --platform ios --dev false --entry-file index.js >--bundle-output ios/main.jsbundle
>
>
>Hermes
>
>It can be retrieved from the following places after successful build/archieve.
> - Android: android/build/generated/assets/createBundleReleaseJSAndAssets/index.android.bundle
> - iOS: YourApp.xcarchieve/Products/Applications/YourApp.app/main.jsbundle
- ⚠️ Note:
- react-native-simple-ota only updates JavaScript code, not native modules.
- Works only in release builds; in debug mode, Metro bundler is used instead.
---
- react-native-simple-ota stores and loads custom JS bundles (OTA updates) from the local device storage.
- OTA updates are applied on the next app launch.
- You control when and how to download OTA updates by implementing a custom OtaUpdateProvider. This ensures full flexibility for caching, version control, and download logic.
- On app launch, the library simply redirects the JS bundle loader to your downloaded OTA file (if available).
- react-native-simple-ota works with React Native Old & New Architecture and Expo Bare Work Flow.
---
``sh`
npm install react-native-simple-ota
ts
import {
getBundleVersion,
type OtaUpdate,
type OtaUpdateProvider,
} from 'react-native-simple-ota';
class MyOtaUpdateProvider implements OtaUpdateProvider {
isUserApplicableForUpdate(): boolean {
return true;
}
async getOtaUpdate(): Promise {
try {
const bundleInfo: BundleInfo = await this.getUpdate();
const update: OtaUpdate = {
bundleVersion: bundleInfo.bundle_version,
bundlePath: bundlePath,
};
return update;
} catch (e: any) {
}
return null;
}
}
`$3
`ts
import { init } from 'react-native-simple-ota';init(new MyOtaUpdateProvider());
`$3
`ts
import {
applyOTAIfApplicable,
} from 'react-native-simple-ota';// ...
useEffect(() => {
applyOTAIfApplicable();
}, []);
`$3
Note: Though the below file are in Kotlin and Swift they can be used in Java and Objective C respectively- Android
The Application class might not exist in your Android code so you'll have to create it at
myapp/android/app/src/main/java and add it in manifest file.`kotlinimport android.app.Application
import dev.droid.simpleota.ReactNativeSimpleOtaModule
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List =
PackageList(this).packages
override fun getJSMainModuleName(): String = "index"
override fun getJSBundleFile(): String? {
return ReactNativeSimpleOtaModule.getJSBundleFile(this@MainApplication) ?: super.getJSBundleFile()
}
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
}
`- iOS
`swiftimport UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import ReactNativeSimpleOta
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let delegate = ReactNativeDelegate()
let factory = RCTReactNativeFactory(delegate: delegate)
delegate.dependencyProvider = RCTAppDependencyProvider()
reactNativeDelegate = delegate
reactNativeFactory = factory
window = UIWindow(frame: UIScreen.main.bounds)
factory.startReactNative(
withModuleName: "SimpleOtaExample",
in: window,
launchOptions: launchOptions
)
return true
}
}
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
override func sourceURL(for bridge: RCTBridge) -> URL? {
self.bundleURL()
}
override func bundleURL() -> URL? {
#if DEBUG
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
if let customBundlePath = ReactNativeSimpleOta.getJSBundleFile() {
return URL(fileURLWithPath: customBundlePath)
}
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}
```