Skip to main content

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 WebBrowserComponent uses 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
The 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

All built-in Songbird instruments/effects (4OSC, Sampler, DrumMachine, STK, 303, Reverb, Delay, etc.) are pure C++ and work on iOS.

Phase 1: Get It to Compile (~1-2 days)

1. CMake iOS Toolchain (~2-4 hours)

Add iOS platform detection to CMakeLists.txt:
Disable VST3 on iOS:

2. Main.cpp Platform Guards (~1 hour)

The following are macOS-only and need #if JUCE_MAC guards:
  • DocumentWindow with native title bar
  • MenuBarModel / setMacMainMenu
  • setUsingNativeTitleBar, setResizable
On iOS, use a simple full-screen 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_IOS out 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.)
  • EffectPanel plugin parameter UIs
  • LoadingScreen, 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 panels
  • ArrangementView → horizontal scroll optimized for touch, simpler track headers
  • MixerPanel → full-screen vertical mixer instead of bottom strip
  • MidiEditor → touch gesture support for piano roll
  • Transport → compact bar at top/bottom
  • SettingsPanel → full-screen on iOS

Approach

Detect platform in React via a query param or CSS media query, then conditionally render App.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

Open the generated Xcode project in build-ios/ to deploy to device/simulator.