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 SDKs in place.
This is a strategic guide more than a tactical one — most apps that get this far DON’T need to migrate. Read the “Should you migrate” section 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 support | @mushi-mushi/capacitor + @mushi-mushi/web 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: 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 during the migration
You’ll have two Mushi SDKs running side by side for the migration window:
- The existing iOS (
@mushi-mushi/ios) and / or Android (@mushi-mushi/android) SDKs, mounted in the native shell. - 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 and apiKey. Reports from each
land in the same inbox; the SDK tag on the report (ios, android,
capacitor, react-native) lets you tell them apart on the dashboard.
// Native iOS — stays as-is during the migration
import Mushi from "MushiMushi"
Mushi.shared.configure(projectId: "YOUR_PROJECT_ID", apiKey: "YOUR_PUBLIC_KEY")// 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 SDK; the JS one carries on alone.
Verification
- Both SDKs land reports under the same project.
- The dashboard SDK-tag filter shows reports from both surfaces during the migration window.
- Crash rate on the hybrid surfaces ≤ 1.2 × the native surface’s rate (perfect parity is unrealistic in week 1; should approach 1.0 × within 4 weeks).
References
- Capacitor docs
- React Native docs
@mushi-mushi/iosand@mushi-mushi/androidreference@mushi-mushi/capacitorand@mushi-mushi/react-nativereference