3.6 KiB
3.6 KiB
iOS App (Xcode host)
Kotlin Multiplatform Compose UI runs inside a native iOS shell. Sources here are Xcode-ready scaffolding; building requires macOS + Xcode.
App Group migration
| Old (Flutter) | New (KMP) |
|---|---|
group.com.zhushenwudi.lovelivemusicplayer |
group.top.zhushenwudi.llmp |
Kotlin writes widget / PiP / CarPlay keys via WidgetDataWriter (shared/.../IosPlatformHooks.kt). Swift Widget + CarPlay read the same suite.
Build steps (macOS)
cd LoveLiveMusicPlayerKMP
./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64
# or iosArm64 for device
- Open Xcode → File → New → Project → App (or add targets to an existing workspace).
- Set bundle ID
top.zhushenwudi.llmp(main app). - Copy
iosApp/iosApp/*into the app target; addWidgetExtension/*as a Widget Extension target (top.zhushenwudi.llmp.widget). - Link the Gradle-produced
ComposeApp.framework(and embeddedShared.frameworkif split). - Signing: enable App Groups
group.top.zhushenwudi.llmpon both app + widget targets (iosApp.entitlements,WidgetExtension.entitlements). - CarPlay: entitlements include
com.apple.developer.carplay-audioandcom.apple.developer.playable-content— requires Apple Developer approval before TestFlight/App Store CarPlay works. - Add
black.mp4(minimal black video) to the app bundle for PiP — copy from Flutterios/Runnerif present, or generate a 1-frame H.264 clip. - Copy widget image assets from Flutter
ios/HomeWidgetExample/Assets.xcassets(logo,cd_white,cd_black, favorites).
Entry point:
MainViewControllerKt.MainViewController() // ComposeApp framework
MainViewController.kt calls installIosPlatformServices() on startup.
Targets & layout
iosApp/
iosApp/
AppDelegate.swift — lifecycle, widget shutdown, notification wiring
SceneDelegate.swift — UIWindow + PiP notification handlers
ContentView.swift — SwiftUI host for Compose UIViewController
HostBridge.swift — share sheet, deep links, widget/CarPlay → host
Info.plist
iosApp.entitlements
CarPlay/CarPlaySceneDelegate.swift
pip/ — desktop lyric PiP (from Flutter Runner/pip)
WidgetExtension/ — White/Black home widgets (from Flutter HomeWidgetExample)
Kotlin ↔ Swift bridge (remaining macOS work)
| Feature | Kotlin side | Swift side | Gap |
|---|---|---|---|
| Playback | PlayerController.ios.kt AVPlayer + MPRemoteCommandCenter |
— | Done in Kotlin |
| Home widget data | IosHomeWidgetController → UserDefaults |
Widget reads keys | Wire widget tap → Kotlin player (export callback or observe llmpHostTogglePlay) |
| PiP lyrics | IosDesktopLyricController posts notifications |
PipScreenManager |
Done via NotificationCenter |
| Share | IosShareBridge posts llmpShareRequest |
HostBridge.presentShare |
Done |
Deep link llmp:// |
IosDeepLinkHandler |
SceneDelegate + HostBridge |
Handle payload in Kotlin UI layer |
| CarPlay | IosCarPlayHook.refreshCatalog() writes JSON |
CarPlaySceneDelegate |
Play/group/menu callbacks need Kotlin export |
CarPlay note
CarPlaySceneDelegate reads carplay_* JSON from the App Group. Full parity with Flutter flutter_carplay needs exported Kotlin handlers for onPlay(musicId) — until then, NotificationCenter events (llmpHostCarPlayPlay, etc.) are posted for the host to forward.
Permissions
Add usage strings in Xcode as needed (camera for QR, photo library, etc.) — see Flutter ios/Runner/Info.plist for reference.