SDK
Installation
Five steps: install the package, wire the iOS and Android bundle hooks, initialise in JavaScript, and verify. Autolinking handles the rest — there’s no manual native linking.
apk_live_… key in step 4.1. Install the package
npm install react-native-aeropushThe package is a New Architecture Turbo Module. React Native Codegen generates the native interface automatically the next time you build.
2. iOS setup
2.1 — Install pods
cd ios && pod installAutolinking picks up the podspec and generates AeropushSpec. No manual linking.
2.2 — Bridging header
The bundle hook calls the SDK’s Objective-C++ launcher from Swift, so the app target needs a bridging header. Create ios/<AppName>/<AppName>-Bridging-Header.h:
#import "Aeropush.h"Then point Build Settings → Objective-C Bridging Header at it for both the Debug and Release configurations. If you already have a bridging header, just add the import.
2.3 — Bundle hook
Override bundleURL() so release builds boot from the staged OTA bundle. Aeropush.bundleURL() runs the launch-counter check (auto-rollback) and returns nil when no OTA bundle is active.
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
override func sourceURL(for bridge: RCTBridge) -> URL? {
self.bundleURL()
}
override func bundleURL() -> URL? {
#if DEBUG
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
// Prefer the active OTA bundle; fall back to the embedded binary bundle.
Aeropush.bundleURL()
?? Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
}
}3. Android setup
Autolinking registers the Turbo Module. The only manual step is the bundle hook in MainApplication.kt. AeropushModule.getJSBundleFile(context) runs the launch-counter check and returns null when no OTA bundle is active (falling back to the embedded assets://index.android.bundle).
import com.aeropush.AeropushModule
class MainApplication : Application(), ReactApplication {
override val reactHost: ReactHost by lazy {
getDefaultReactHost(
context = applicationContext,
packageList = PackageList(this).packages,
// AeroPush OTA hook: boot from the staged bundle when one is active.
jsBundleFilePath =
if (BuildConfig.DEBUG) null
else AeropushModule.getJSBundleFile(applicationContext),
)
}
}4. JavaScript setup
Initialise once at module scope (before first render), sync on launch, and wrap your app in the crash boundary. Get your appKey from the dashboard.
import AeroPush, { AeroPushBoundary, InstallMode } from 'react-native-aeropush';
// 1. Initialise before the component tree renders.
AeroPush.init({ appKey: 'YOUR_APP_KEY', channel: 'production' });
// 2. Check for + stage updates (e.g. on launch).
AeroPush.sync({ installMode: InstallMode.ON_NEXT_RESTART });
// 3. Crash guard: a render crash marks the bundle failed; a successful
// mount marks it healthy (resets the native launch counter).
export default function App() {
return (
<AeroPushBoundary>
<YourApp />
</AeroPushBoundary>
);
}AeroPushBoundary, call AeroPush.markBundleHealthy() yourself after a successful mount — otherwise the native launch counter rolls a healthy bundle back after 3 launches.5. Verify
Make a release build, then publish a bundle and relaunch:
export AEROPUSH_APP_KEY=apk_live_…
npx aeropush release --channel productionThe app picks up the new bundle on its next cold launch. Next, see the full SDK API or the CLI reference.
Optional: Metro banner
Wrap your Metro config to print a small AeroPush banner whenever the dev server starts — a handy confirmation that AeroPush is wired in, and a reminder that OTA only affects release builds. It returns your config unchanged.
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { withAeroPush } = require('react-native-aeropush/metro');
const config = {};
module.exports = withAeroPush(mergeConfig(getDefaultConfig(__dirname), config));On npx react-native start you’ll see:
▲ AeroPush v0.1.22 · over-the-air updates active
Debug builds load from Metro — OTA updates apply to release builds.
Docs: https://aeropush.tech/docswithAeroPush(config, { banner: false }) or set AEROPUSH_NO_BANNER=1 to silence it.