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

FormatiOSNotes
AUv3Apple’s native format. JUCE can host AUv3 on iOS. Large ecosystem (Moog, FabFilter, Arturia, etc.)
VST3Not available on iOS. Disable via JUCE_PLUGINHOST_VST3=0
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:
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
    set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE INTERNAL "")
    set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE INTERNAL "")
endif()
Disable VST3 on iOS:
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
    target_compile_definitions(SongbirdPlayer PRIVATE
        JUCE_PLUGINHOST_AU=1
        JUCE_PLUGINHOST_VST3=0)
else()
    target_compile_definitions(SongbirdPlayer PRIVATE
        JUCE_PLUGINHOST_AU=1
        JUCE_PLUGINHOST_VST3=1)
endif()

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

# macOS (current)
cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build

# iOS (future)
cmake -B build-ios -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_BUILD_TYPE=Debug
cmake --build build-ios
Open the generated Xcode project in build-ios/ to deploy to device/simulator.