Still in Alpha and will have issues
β‘οΈ High-performance Over-The-Air (OTA) updates for React Native - Powered by Nitro Modules
Download, unzip, and apply JavaScript bundle updates at runtime without going through the App Store or Play Store review process.
- π Native Performance - Built with Nitro Modules for maximum speed
- π§΅ Off JS Thread - All operations run on different threads, keeping your JS thread free
- π Server Agnostic - Works with any CDN, S3, GitHub Releases, or custom server
- π¦ Automatic Bundle Management - Handles download, extraction, and cleanup
- π Version Control - Built-in version checking and management
npm install react-native-nitro-ota react-native-nitro-modules
# or
yarn add react-native-nitro-ota react-native-nitro-modulesNote:
react-native-nitro-modulesis required as this library relies on Nitro Modules.
In your MainApplication.kt, add the bundle path loader:
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.margelo.nitro.nitroota.core.getStoredBundlePath
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
// π₯ Load OTA bundle if available, otherwise use default
override fun getJSBundleFile(): String? {
return getStoredBundlePath(this@MainApplication)
}
}
}If using modern React host:
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.margelo.nitro.nitroota.core.getStoredBundlePath
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
jsBundleFilePath = getStoredBundlePath(applicationContext)
)
}
}- Add to your
Podfile:
pod 'NitroOtaBundleManager', :path => '../node_modules/react-native-nitro-ota'- Install pods:
cd ios && pod install- Update
AppDelegate.swift:
import UIKit
import React
import NitroOtaBundleManager
class AppDelegate: UIResponder, UIApplicationDelegate {
override func bundleURL() -> URL? {
#if DEBUG
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
// Check for OTA bundle
if let bundlePath = NitroOtaBundleManager.shared.getStoredBundlePath() {
let bundleURL = URL(fileURLWithPath: bundlePath)
return bundleURL
}
// Fallback to default bundle
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}Use the githubOTA helper to point directly to a GitHub repository:
import { githubOTA, OTAUpdateManager } from 'react-native-nitro-ota';
// Configure GitHub URLs
const { downloadUrl, versionUrl } = githubOTA({
githubUrl: 'https://github.com/your-username/your-ota-repo',
otaVersionPath: 'ota.version', // optional, defaults to 'ota.version'
ref: 'main' // optional, defaults to 'main'
});
// Create update manager
const otaManager = new OTAUpdateManager(downloadUrl, versionUrl);
// Check for updates
const hasUpdate = await otaManager.checkForUpdates();
if (hasUpdate) {
// Download update
await otaManager.downloadUpdate();
otaManager.reloadApp()
console.log('Update downloaded! Restart app to apply.');
}
// Get current version
const currentVersion = otaManager.getVersion();
console.log('Current OTA version:', currentVersion);import { NitroOta } from 'react-native-nitro-ota';
// Download and unzip bundle from any server
const updatePath = await NitroOta.downloadAndUnzipFromUrl(
'https://your-cdn.com/bundles/latest.zip',
'https://your-cdn.com/bundles/version.txt' // optional version file
);
console.log('Update downloaded to:', updatePath);
// Restart app to apply update
// Use your preferred restart method or RN's DevSettings// Check if a new version is available
const hasUpdate = await NitroOta.checkForUpdates(
'https://your-cdn.com/bundles/version.txt'
);
if (hasUpdate) {
console.log('New version available!');
// Download and apply update
}const currentVersion = NitroOta.getStoredOtaVersion();
console.log('Current OTA version:', currentVersion); NitroOta.reloadApp();The ota.version file is a simple text file that contains your current bundle version. The version can be anything - numbers, strings, or even creative identifiers like "apple", "orange", "winter2024", or "bugfix-v3".
Important: There's no "greater than" or "less than" logic. The library simply checks if currentVersion !== newVersion. This means you can use any naming scheme that makes sense for your workflow - just ensure each new update has a different version string than the previous one.
Creating the version file:
echo "1.0.0" > ota.version
# or
echo "apple" > ota.version
# or
echo "$(date +%Y%m%d)" > ota.version # Use current date as versionFollow these steps to generate and distribute your OTA bundle:
Run the following commands to create a production-ready bundle and assets for your platform:
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output android/App-Bundles/index.android.bundle \
--assets-dest android/App-Bundlesnpx react-native bundle \
--platform ios \
--dev false \
--entry-file index.js \
--bundle-output ios/App-Bundles/index.jsbundle \
--assets-dest ios/App-BundlesResult:
Your bundles and assets will be generated inandroid/App-Bundles/orios/App-Bundles/respectively.
After generating the bundle, compress the entire output folder (including the assets) into a single zip file:
# For Android
cd android && zip -r App-Bundles.zip App-Bundles
# For iOS
cd ios && zip -r App-Bundles.zip App-BundlesUpload the zipped bundle file to your backend, CDN, or preferred file hosting service so that your app can download it for OTA updates.
In the Jellify App:
- Bundles are uploaded to a dedicated Git branch named by version and platform (e.g.,
nitro_0.19.2_android). - The upload and versioning are automated via GitHub Actions workflow.
This keeps OTA releases well organized and accessible for deployment.
See CONTRIBUTING.md for development workflow and guidelines.
MIT