Mobile App
The Bellamy Book mobile app is a thin native shell (Expo / React Native) that loads your self-hosted frontend in a WebView. Users enter the frontend URL once; the app saves it and opens it on every launch. All API calls go from the frontend inside the WebView; the app does not talk to the backend directly. The app also obtains an Expo push token and injects it into the WebView so the frontend can register with the API for chat and call notifications.
Overview
| Area | Status | Notes |
|---|---|---|
| URL entry (first launch) | ✅ Done | Enter frontend URL, validation, save to AsyncStorage |
| WebView (main app) | ✅ Done | Loads saved URL; chat, calls, media work inside WebView |
| Settings | ✅ Done | Change URL, remove URL, back to app (gear in header) |
| Persistence | ✅ Done | AsyncStorage key @BellamyBook:webAppUrl |
| Expo push (chat/call) | ✅ Ready | Token registration + worker delivery; user gets notifications when app is in background |
| Deep linking from push | 📋 Later | Open app and navigate to chat/call when user taps notification |
| EAS Build (IPA/APK) | 📋 Later | Production binaries and store submission |
Stack: Expo ~54, React 19, React Native 0.81, react-native-webview, @react-native-async-storage/async-storage, expo-notifications, expo-device.
Architecture
User device
│
▼
┌─────────────────────────────────────┐
│ Bellamy Book Mobile (Expo / RN) │
│ • URL entry (first time / after │
│ “Remove URL”) │
│ • WebView → your frontend URL │
│ • Settings (change/remove URL) │
│ • Expo push token → inject into │
│ WebView for API registration │
└─────────────────────────────────────┘
│
│ Loads
▼
┌─────────────────────────────────────┐
│ Self-hosted frontend │
│ (e.g. https://app.yoursite.com) │
│ • Same React app as desktop │
│ • Chat, calls, feed in WebView │
│ • Listens for EXPO_PUSH_TOKEN and │
│ registers with API │
└─────────────────────────────────────┘
The mobile app does not call the backend API directly; all API calls (auth, chat, push subscription, etc.) are made by the frontend running inside the WebView. The app only stores the frontend URL and provides the Expo push token to the WebView.
Project Structure
The mobile app lives under Src/mobile/:
Src/mobile/
├── App.js # Root: load URL from storage → Entry | WebView | Settings
├── index.js # Expo entry
├── app.json # Expo config (name, slug, icons, scheme)
├── metro.config.js # Metro config
├── polyfill-node18.js # Array#toReversed for Node 18 (used by start script)
├── package.json
├── assets/ # Icons, splash (logo.svg; PNGs generated from it)
└── src/
├── constants/storageKeys.js # AsyncStorage key(s)
├── services/
│ ├── urlStorage.js # get/set/remove saved URL
│ └── pushNotifications.js # permission + Expo push token
├── theme/colors.js
├── utils/urlValidation.js # Normalize & validate URL
└── screens/
├── UrlEntryScreen.js # First-time / change URL form
├── WebViewScreen.js # WebView + header + settings; injects push token
└── SettingsScreen.js # Show URL, Change, Remove, Back
Expo Push Integration
- On WebView mount, the app calls
registerForPushNotificationsAsync()(insrc/services/pushNotifications.js) to request notification permission and obtain an Expo push token. - When the token is available, WebViewScreen injects it into the WebView via
window.postMessage({ type: 'EXPO_PUSH_TOKEN', token: '...' }, '*'). - The frontend (in the browser or inside the WebView) listens for this message and registers the token with the API (
POST /api/push-subscriptions/expo) so the backend can send chat and call notifications to this device. - The ExpoPushNotificationWorker consumes RabbitMQ messages and sends push via Expo’s service when someone sends a chat message or starts a call.
Expo push is ready: token registration and delivery via ExpoPushNotificationWorker are implemented; users receive chat and call notifications when the app is in the background. For full flow and API details, see Web Push and Expo Push. Later: deep linking when the user taps a notification (e.g. open app and go to the conversation or call screen) and EAS Build for production IPA/APK.
Run & Build
Prerequisites
- Node 18+ (Node 20+ recommended; Node 18 needs the polyfill applied by the start script)
- npm or yarn
- Expo Go on device, or iOS/Android simulator
Install and start
cd Src/mobile
npm install
npm start
- Node 18: The
npm startscript preloadspolyfill-node18.jsso Metro works (toReversedpolyfill). - Choose port if prompted (e.g. 8083 when 8081 is in use).
- Scan QR with Expo Go, or press
i/afor iOS/Android simulator.
First launch
- App shows URL entry.
- Enter your Bellamy Book frontend URL (e.g.
https://your-app.example.comorhttp://localhost:5173for dev). - Tap Continue → URL is saved and WebView loads.
- Use the app; tap ⚙️ in the header to open Settings (change URL, remove URL, or go back to app).
Other scripts
| Script | Command | Description |
|---|---|---|
| iOS | npm run ios | Start and open iOS simulator |
| Android | npm run android | Start and open Android emulator |
| Web | npm run web | Start for web (Expo web) |
| Icons | npm run generate-icons | Regenerate app icon/splash from assets/logo.svg (same as frontend logo) |
Configuration
- Frontend URL: Stored in AsyncStorage (
@BellamyBook:webAppUrl). Set on first launch or in Settings. - Expo push: Requires
EXPO_PUBLIC_PROJECT_IDin app config (e.g.app.json/ EAS) forexpo-notificationsto resolve the push token. For local dev with Expo Go, the default project is used.
Troubleshooting
- Port in use: When starting, choose “yes” to use another port (e.g. 8083).
configs.toReversed is not a function: Usenpm start(which preloads the Node 18 polyfill), or upgrade to Node 20+.- WebView “Connection Error”: Check URL, network, and that the frontend is reachable (HTTPS in production; for local dev you may need
http://and correct host, e.g. machine IP or localhost depending on device). - Expo push token not received in frontend: Ensure the WebView has loaded and the frontend listens for
EXPO_PUSH_TOKENviawindow.addEventListener('message', ...). The app injects the token after the WebView loads; if the user denies notification permission, no token is sent.
Related
- Web Push and Expo Push – Backend workers, API endpoints, and flow for chat/call notifications.
- Messaging Feature – Chat and call behavior (used inside the WebView).
- Notifications Feature – In-app and real-time notifications.