rn-ota
v1.0.0
Published
Self-hosted React Native OTA updates (push + pull)
Maintainers
Readme
rn-ota 🚀
A lightweight Over-The-Air (OTA) update system for React Native inspired by CodePush.
rn-ota lets you push JavaScript bundles to your own server and pull updates inside the app, without relying on third‑party services.
⚠️ OTA updates apply only to JavaScript & assets. Native changes still require a store update.
✨ Features
- 📦 Push JS bundles to your own server
- 🔄 Pull OTA updates at runtime
- 🔐 SHA256 hash verification
- 🧠 Version & binary version control
- 🔁 Safe app restart (Android)
- 🍎 App Store–compliant (iOS)
- 🧩 Optional
react-native-restartsupport - 🪶 Minimal & dependency‑light
📦 Installation
npm install rn-otaOptional (recommended for Android dev)
npm install react-native-restart🗂️ Project Structure
project-root
├── ota.config.json
├── ota/
│ ├── index.android.bundle
│ ├── index.ios.bundle
│ └── manifest.json⚙️ Configuration
Create ota.config.json in your project root:
{
"version": "1.0.1",
"binaryVersion": "1.0.0",
"server": {
"host": "your-server.com",
"user": "username",
"password": "password",
"path": "/public/ota"
}
}🚀 Push OTA Update (CLI)
npx rn-ota push android
npx rn-ota push iosThis will:
- Bundle JS
- Generate SHA256 hash
- Create
manifest.json - Upload bundle + manifest to your server
📄 Manifest Format
{
"version": "1.0.1",
"binaryVersion": "1.0.0",
"platform": "android",
"bundle": "index.android.bundle",
"hash": "<sha256>"
}📲 Pull OTA Update (JS)
import { pullUpdate, restartApp } from "rn-ota";
const result = await pullUpdate(
"https://your-server.com/ota",
"1.0.0", // current JS version
"1.0.0" // native app version
);
if (result.updated) {
restartApp();
}🔁 Restart Logic
Android
- Uses native Activity restart (safe & reliable)
- Reloads OTA bundle immediately
iOS
- App cannot be restarted programmatically
- Update applies on next cold launch
🔧 Android Native Setup (REQUIRED)
1️⃣ Override bundle loader
MainApplication.java
@Override
protected String getJSBundleFile() {
File file = new File(
getApplicationContext().getFilesDir(),
"index.android.bundle"
);
return file.exists()
? file.getAbsolutePath()
: super.getJSBundleFile();
}2️⃣ Register restart module
packages.add(new RNOtaRestartPackage());🔒 Security
- SHA256 bundle verification
- Corrupt bundles rejected
- Fallback to embedded bundle
❌ What rn-ota does NOT do
- ❌ Modify native code
- ❌ Bypass App Store policies
- ❌ Force iOS restart
- ❌ Delta updates (yet)
🧠 Best Practices
- Change
versionon every OTA push - Match
binaryVersionwith app build - Restart app after update
- Always keep a fallback bundle
🧪 Debugging
console.log("OTA VERSION", result.version);If version changes after restart → OTA is working ✅
🆚 rn-ota vs CodePush
| Feature | rn-ota | CodePush | | -------------- | ------ | -------- | | Server control | ✅ | ❌ | | Open source | ✅ | ❌ | | Vendor lock-in | ❌ | ✅ | | Delta updates | ❌ | ✅ |
🛣️ Roadmap
- 🔁 Rollback on crash
- 📦 Delta updates
- 📊 Analytics hooks
- 🧪 Canary channels
⚠️ Disclaimer
Use OTA responsibly. Ensure updates comply with Google Play and App Store guidelines.
📄 License
MIT
Made with ❤️ for React Native developers
