Native iOS / Android → Hybrid
Weeks High riskWhen (and how) to wrap an existing pure-native iOS / Android app with Capacitor or React Native, keeping the platform Mushi Mushi SDKs in place.
This is a strategic guide more than a tactical one. Many apps that get this far don’t need to migrate, so read “Should you migrate?” first.
Should you migrate?
Migrate if two or more of these are true:
- ☐ You’re shipping the same feature twice in Swift and Kotlin and the parity work is eating > 30 % of your engineering time.
- ☐ You have an existing web app whose UI you’d like to share with mobile.
- ☐ Your app’s core surface is forms / lists / chat / dashboards (high JS affinity); not games, AR, video editors, or audio DSP.
- ☐ You’re losing native engineers and can hire React engineers more easily.
DON’T migrate if:
- Your app’s value is performance-bound native (camera, GL, audio, VPN).
- Your team is happy and ships steadily on native.
- You can’t afford a 6–12 month parallel-track migration.
If you proceed, the realistic outcome is hybrid: most of your screens in JS, a handful of performance-critical surfaces left in Swift / Kotlin, bridged to JS via TurboModules (RN) or Capacitor plugins.
Pick a target shell
| Capacitor | React Native | |
|---|---|---|
| Reuse web codebase | Yes (it IS the web app, in a WebView) | Mostly — RN uses React but not DOM components |
| Native fidelity | WebView ceiling | ~Native, with effort |
| Migration size | Smaller (you can wrap a static export) | Larger (every screen is rewritten) |
| Team profile | Web devs only | React devs + some native fluency |
| Mushi Mushi support | @mushi-mushi/capacitor + mushi-mushi for the WebView | @mushi-mushi/react-native |
Pick Capacitor if you already have a strong web product and just need a native shell. Pick React Native if you want to ship native UX from JS and you don’t have a meaningful web app.
Migration checklist
- Step 01Audit native surfaces: what stays native?
- Step 02Run a 2-week spike on the most complex screen
- Step 03Pick the shell: Capacitor or React Native
- Step 04Port the design system
- Step 05Pilot one user-facing flow end-to-end
- Step 06Wire Mushi Mushi: keep the native SDK AND add the JS one
- Step 07Roll out screen-by-screen behind a feature flag
- Step 08Sunset native screens once their hybrid versions are stable
Mushi Mushi during the migration
You’ll have two Mushi Mushi SDKs running side by side for the migration window:
- The existing native iOS (
MushiMushi, Swift) and / or Android (dev.mushimushi:mushi-android, Kotlin) SDKs, mounted in the native shell. Both are 0.4.0 previews: they are not on CocoaPods trunk, SwiftPM tags or Maven Central yet, so they are built from source as their SDK pages describe. - The shell-specific JS SDK —
@mushi-mushi/capacitor(for Capacitor shells) or@mushi-mushi/react-native(for RN shells).
Both must use the same projectId. Reports from each land in the same
inbox, and each report records which SDK sent it, so you can filter
Reports by SDK.
// Native iOS — stays as-is during the migration
import MushiMushi
Mushi.shared.configure(with: MushiConfig(
projectId: "YOUR_PROJECT_ID",
apiKey: "YOUR_PUBLIC_KEY",
endpoint: "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api"
))// JS shell — added on top
import { Mushi } from '@mushi-mushi/capacitor'
await Mushi.configure({ projectId: 'YOUR_PROJECT_ID', apiKey: 'YOUR_PUBLIC_KEY' })When the migration completes and you remove the native shell entirely, you also remove the native Mushi Mushi SDK; the JS one carries on alone.
Verification
- Both SDKs land reports under the same project.
- Filtering Reports by SDK shows reports from both surfaces during the migration window.
- The crash rate on the hybrid surfaces moves toward the native surface’s rate over the first weeks. Set your own threshold before you start.
References
- Capacitor docs
- React Native docs
- Mushi Mushi iOS SDK and Mushi Mushi Android SDK reference
@mushi-mushi/capacitorand@mushi-mushi/react-nativereference