
Research
/Security News
PolinRider Spreads Through Compromised GitHub Accounts and Packagist
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.
react-native-nitro-ota
Advanced tools
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.
npm install react-native-nitro-ota react-native-nitro-modules
# or
yarn add react-native-nitro-ota react-native-nitro-modules
Note:
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)
)
}
}
cd ios && pod install
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', // or 'ota.version.json' for advanced features
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) {
await otaManager.downloadUpdate();
otaManager.reloadApp();
}
// Or use advanced JS checking (supports JSON format)
const updateInfo = await otaManager.checkForUpdatesJS();
if (updateInfo?.hasUpdate && updateInfo.isCompatible) {
console.log('Compatible update available:', updateInfo.remoteVersion);
await otaManager.downloadUpdate();
otaManager.reloadApp();
}
// 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();
⚠️ HIGHLY ALPHA FEATURE - This feature is experimental and needs thorough testing. Use with caution in production.
Schedule automatic background checks for updates that run periodically:
import { OTAUpdateManager } from 'react-native-nitro-ota';
const otaManager = new OTAUpdateManager(downloadUrl, versionCheckUrl);
// Schedule background check every hour (3600 seconds)
otaManager.scheduleBackgroundCheck(3600);
ota.version (Simple Text)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".
echo "1.0.0" > ota.version
ota.version.json (With Metadata)For more control, use the JSON format with semantic versioning and target app versions:
{
"version": "1.2.3",
"isSemver": true,
"targetVersions": {
"android": ["2.30.1", "2.30.2"],
"ios": ["2.30.1"]
},
"releaseNotes": "Bug fixes and improvements"
}
JavaScript API for Advanced Checking:
import { checkForOTAUpdatesJS } from 'react-native-nitro-ota';
// Get detailed update info
const result = await checkForOTAUpdatesJS(
'https://example.com/ota.version.json'
);
if (result?.hasUpdate && result.isCompatible) {
console.log(`New version: ${result.remoteVersion}`);
console.log(`Notes: ${result.metadata?.releaseNotes}`);
}
Note: Both formats are supported. The library automatically detects which one you're using.
Follow 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-Bundles
npx react-native bundle \
--platform ios \
--dev false \
--entry-file index.js \
--bundle-output ios/App-Bundles/index.jsbundle \
--assets-dest ios/App-Bundles
Result:
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-Bundles
Upload 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:
nitro_0.19.2_android).This keeps OTA releases well organized and accessible for deployment.
See CONTRIBUTING.md for development workflow and guidelines.
MIT
FAQs
A package to react-native-nitro-ota
The npm package react-native-nitro-ota receives a total of 651 weekly downloads. As such, react-native-nitro-ota popularity was classified as not popular.
We found that react-native-nitro-ota demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.

Company News
Allow myself to introduce... myself.