iOS Build — Feasibility & Plan
Last updated: 2026-03-20
Architecture Summary
Songbird’s architecture is already well-suited for iOS:- Audio engine (JUCE + Tracktion Engine) → first-class iOS support
- UI (React in WKWebView) → JUCE’s
WebBrowserComponentuses WKWebView on both macOS and iOS - Bridge (
window.__JUCE__native functions + events) → platform-agnostic, works identically on iOS - Data layer (Zustand stores,
bridge.ts) → 100% reusable
WKWebViewImpl in juce_WebBrowserComponent_mac.mm already handles iOS (UIViewComponent) vs macOS (NSViewComponent). The resource provider, native functions, and event bridge all work identically.
Plugin Hosting
| Format | iOS | Notes |
|---|---|---|
| AUv3 | ✅ | Apple’s native format. JUCE can host AUv3 on iOS. Large ecosystem (Moog, FabFilter, Arturia, etc.) |
| VST3 | ❌ | Not available on iOS. Disable via JUCE_PLUGINHOST_VST3=0 |
Phase 1: Get It to Compile (~1-2 days)
1. CMake iOS Toolchain (~2-4 hours)
Add iOS platform detection toCMakeLists.txt:
2. Main.cpp Platform Guards (~1 hour)
The following are macOS-only and need#if JUCE_MAC guards:
DocumentWindowwith native title barMenuBarModel/setMacMainMenusetUsingNativeTitleBar,setResizable
Component instead.
3. OpenSSL (~2-4 hours)
Linked for Lyria/Gemini WebSocket features. Options:- Cross-compile OpenSSL for iOS (well-documented process)
- Swap to Apple
Security.framework/Network.framework #if JUCE_IOSout Lyria features initially
4. libgit2 (~1-2 hours)
Used for git-based undo/redo. Compiles for iOS but:- FetchContent may need tweaked flags
- Must operate within iOS app sandbox container
- Could stub out initially and use a simpler undo stack
5. Sandbox Worker (~30 min)
PluginSandboxWorker spawns child processes — not allowed on iOS. Disable via #if JUCE_IOS.
6. Remaining Compile Fixes (~2-4 hours)
Expect a handful of additional#if JUCE_MAC / #if JUCE_IOS guards.
Result: App launches on iPad with the full desktop React UI in WKWebView. Functional but desktop-sized layout.
Phase 2: Mobile UI (~2-3 weeks)
Reusable As-Is
- All
atoms/components (Button, Knob, Slider, Switch, RotaryKnob, etc.) EffectPanelplugin parameter UIsLoadingScreen,GenerateModal,ExportProgressModal- Full data layer (
store.ts,bridge.ts,meters.ts,plugins.ts)
Needs Mobile Layout
App.tsx→ tab-based or swipe navigation instead of side panelsArrangementView→ horizontal scroll optimized for touch, simpler track headersMixerPanel→ full-screen vertical mixer instead of bottom stripMidiEditor→ touch gesture support for piano rollTransport→ compact bar at top/bottomSettingsPanel→ full-screen on iOS
Approach
Detect platform in React via a query param or CSS media query, then conditionally renderApp.tsx vs App.ios.tsx. The same Vite build serves both — just swap the top-level shell component. All stores, bridges, and atoms are shared.
Build Command
build-ios/ to deploy to device/simulator.