Getting started
This guide takes a React Native app from zero to receiving its first OTA update.
1. Run a server
Section titled “1. Run a server”For a quick try, run it locally (uses a local D1/R2 simulation):
git clone https://github.com/guhcostan-dev/react-native-airdrop && cd react-native-airdroppnpm installecho 'ADMIN_TOKEN=change-me' > apps/server/.dev.varspnpm dev:server # http://localhost:8787For production, follow Deploy on Cloudflare.
2. Install the CLI and log in
Section titled “2. Install the CLI and log in”npm install -g react-native-airdrop-cli # or: pnpm --filter react-native-airdrop-cli build && node packages/cli/dist/index.jsairdrop login --server https://ota.example.com --token <ADMIN_TOKEN>3. Create the app
Section titled “3. Create the app”From your React Native project root:
airdrop init --name "My App" --signThis creates the app on the server, writes airdrop.config.json (safe to commit) and,
with --sign, a private key airdrop-private-key.pem (never commit it; store it as a CI secret).
It prints the native configuration values used below.
4. Install the SDK
Section titled “4. Install the SDK”npm install react-native-airdropcd ios && pod installios/<App>/Info.plist:
<key>AirdropServerURL</key><string>https://ota.example.com</string><key>AirdropAppId</key><string>YOUR-APP-ID</string><!-- only if you used --sign --><key>AirdropPublicKey</key><string>BASE64-PUBLIC-KEY</string>AppDelegate.swift (RN ≥ 0.77):
import ReactNativeAirdrop
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate { override func bundleURL() -> URL? { #if DEBUG RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") #else RNAirdrop.bundleURL() #endif }}Objective-C AppDelegate.mm (RN 0.71 – 0.76). Use whichever method your template
already has (bundleURL, getBundleURL or sourceURLForBridge:) and return
[RNAirdrop bundleURL] in release builds:
#import <ReactNativeAirdrop/RNAirdrop.h>
- (NSURL *)bundleURL{#if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];#else return [RNAirdrop bundleURL];#endif}Android
Section titled “Android”android/app/src/main/res/values/strings.xml:
<string name="airdrop_server_url" translatable="false">https://ota.example.com</string><string name="airdrop_app_id" translatable="false">YOUR-APP-ID</string><!-- only if you used --sign --><string name="airdrop_public_key" translatable="false">BASE64-PUBLIC-KEY</string>MainApplication.kt (RN ≥ 0.80, getDefaultReactHost):
import com.rnairdrop.Airdrop
override val reactHost: ReactHost by lazy { getDefaultReactHost( context = applicationContext, packageList = PackageList(this).packages, jsBundleFilePath = Airdrop.getJSBundleFile(applicationContext), )}With a ReactNativeHost (RN 0.71 – 0.79, old or new architecture):
override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { // ... override fun getJSBundleFile(): String? = Airdrop.getJSBundleFile(applicationContext) }AirdropPackage is autolinked.
JavaScript
Section titled “JavaScript”Wrap your root component:
import { withAirdrop } from "react-native-airdrop";
function App() { /* ... */ }
export default withAirdrop(App);By default the SDK checks on app start, downloads in the background and applies the update on the next cold start. See SDK reference for other modes.
5. Ship a store build, then an OTA update
Section titled “5. Ship a store build, then an OTA update”OTA updates are disabled in debug builds (they load from Metro). Build a release app and install it, then change some JS and run:
airdrop release --platform ios --message "Fix checkout button" --private-key airdrop-private-key.pemairdrop release --platform android --message "Fix checkout button" --private-key airdrop-private-key.pemOpen the app (it downloads the update), close it and open it again: the new JS is running.
6. Manage releases
Section titled “6. Manage releases”airdrop updates list # history, installs and rollbacksairdrop release -p android --rollout 10 # staged rolloutairdrop rollout <updateId> 100 # widen itairdrop rollback <updateId> # pull a bad update; devices fall back automaticallyairdrop promote <updateId> --to production