This repo is a minimal React Native 0.74 app wired to reproduce an iOS-only issue involving a custom OTA update mechanism (react-native-ota-hot-update) and Instabug.
- iOS only (Android intentionally skipped)
- OTA bundles are downloaded from a public URL defined in
public/update-ios.json - An express-less Node HTTP server is included to serve the JSON metadata locally
- Node 18+
- Xcode (latest) with iOS Simulator or a physical device
- CocoaPods installed (
gem install cocoapods)
# from repo root
npm install
cd ios && pod install && cd ..npx react-native run-iosThis launches the app in Debug (connects to Metro). Useful to verify UI and buttons.
Recommended for realistic OTA behavior.
- Open Xcode workspace:
open ios/RN74Example.xcworkspace- In Xcode:
- Select the
RN74Examplescheme - Product → Scheme → Edit Scheme… → Run → set Build Configuration to
Release - Choose a simulator or a physical device
- Product → Build (Cmd+B), then Run (Cmd+R)
The Release app embeds a production main.jsbundle and does not rely on Metro.
A tiny HTTP server serves the update JSON endpoint on http://localhost:3000.
node server.jsYou should see:
Server running at http://localhost:3000/
Serving update files:
- http://localhost:3000/update-android.json (ignored)
- http://localhost:3000/update-ios.json
The app fetches public/update-ios.json to determine the available update.
- Check for Updates: fetches
update-ios.json, downloads zip viadownloadIosUrl, installs bundle
- Swap
App.tsxto the updated version (shows "Welcome to Contact!"):
cp App.tsx App-original.tsx && cp App-updated.tsx App.tsx- Generate a production bundle + assets (standalone):
npx react-native bundle \
--platform ios \
--dev false \
--entry-file index.js \
--bundle-output ios-update-bundle.js \
--assets-dest ios-update-assets- Package in the expected OTA zip structure:
rm -rf ota-update-bundle && mkdir -p ota-update-bundle
cp ios-update-bundle.js ota-update-bundle/main.jsbundle
cp -r ios-update-assets/* ota-update-bundle/
zip -r ota-update-bundle.zip ota-update-bundle/- Restore original
App.tsxso the running app shows the old UI before update:
cp App-original.tsx App.tsxUpload ota-update-bundle.zip somewhere public and put the direct-download URL in public/update-ios.json:
{
"version": "2", // 2, 3, 4, ..., x
"versionName": "1",
"downloadIosUrl": "https://drive.google.com/uc?export=download&id=YOUR_FILE_ID"
}Notes for Google Drive:
- Share link looks like:
https://drive.google.com/file/d/FILE_ID/view?usp=sharing - Convert to direct download:
https://drive.google.com/uc?export=download&id=FILE_ID
- Start the metadata server:
node server.js- Run the app in Release via Xcode (see steps above)
- Tap "Check for Updates"
- Expected: download progress logs → app restarts → text changes to "Welcome to Contact!"
If the app doesn’t restart automatically, tap the manual restart button you added or re-open the app; the library should pick the latest bundle after restart.
- Download fails (E_UNZIP_FAIL): ensure the zip has this structure:
main.jsbundleassets/(folder) and that you zipped the containing folder (not just the files individually).
- App still shows old UI: ensure you restored
App.tsxto the original before testing, and thatrestartAfterInstall: trueis set. You can also callhotUpdate.resetApp()afterupdateSuccess. - App keeps connecting to Metro: you’re running Debug. Use Release build via Xcode as described above.
- Instabug token: replace placeholder token in
App.tsxif you want real Instabug behavior.
{
"scripts": {
"start": "react-native start",
"ios": "react-native run-ios",
"android": "react-native run-android",
"pod-install": "RCT_NEW_ARCH_ENABLED=1 npx pod-install"
}
}- iOS Release build (no Metro)
- Serving
public/update-ios.jsonlocally downloadIosUrlpoints to a zip withmain.jsbundle+assets/- The running app was built with the old UI; the OTA bundle contains the new UI
If anything fails or you want me to wire a different host than Google Drive, ping me and I’ll adjust the URLs or script the upload.