function adapt
This commit is contained in:
+31
-54
@@ -1,71 +1,48 @@
|
||||
# iOS App (Xcode host)
|
||||
|
||||
Kotlin Multiplatform Compose UI runs inside a native iOS shell. Sources here are **Xcode-ready scaffolding**; building requires **macOS + Xcode**.
|
||||
Kotlin Multiplatform Compose UI runs inside a native iOS shell.
|
||||
|
||||
## 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)
|
||||
## Open in Xcode
|
||||
|
||||
```bash
|
||||
cd LoveLiveMusicPlayerKMP
|
||||
./gradlew :composeApp:linkDebugFrameworkIosSimulatorArm64
|
||||
# or iosArm64 for device
|
||||
cd iosApp
|
||||
./setup.sh # needs xcodegen (`brew install xcodegen`)
|
||||
open iosApp.xcodeproj
|
||||
```
|
||||
|
||||
1. Open Xcode → **File → New → Project → App** (or add targets to an existing workspace).
|
||||
2. Set bundle ID **`top.zhushenwudi.llmp`** (main app).
|
||||
3. Copy `iosApp/iosApp/*` into the app target; add `WidgetExtension/*` as a Widget Extension target (`top.zhushenwudi.llmp.widget`).
|
||||
4. Link the Gradle-produced **`ComposeApp.framework`** (and embedded **`Shared.framework`** if split).
|
||||
5. Signing: enable App Groups `group.top.zhushenwudi.llmp` on **both** app + widget targets (`iosApp.entitlements`, `WidgetExtension.entitlements`).
|
||||
6. CarPlay: entitlements include `com.apple.developer.carplay-audio` and `com.apple.developer.playable-content` — **requires Apple Developer approval** before TestFlight/App Store CarPlay works.
|
||||
7. Add **`black.mp4`** (minimal black video) to the app bundle for PiP — copy from Flutter `ios/Runner` if present, or generate a 1-frame H.264 clip.
|
||||
8. Copy widget image assets from Flutter `ios/HomeWidgetExample/Assets.xcassets` (`logo`, `cd_white`, `cd_black`, favorites).
|
||||
1. 选择模拟器或真机
|
||||
2. 签名已与 Flutter Runner **Manual** 对齐(见下表);模拟器会走本地签名
|
||||
3. Run(⌘R)——预编译脚本会自动跑 `:composeApp:embedAndSignAppleFrameworkForXcode`
|
||||
|
||||
Entry point:
|
||||
## Bundle ID / App Group / 签名(与 Flutter 一致)
|
||||
|
||||
```swift
|
||||
MainViewControllerKt.MainViewController() // ComposeApp framework
|
||||
```
|
||||
| | Value |
|
||||
|---|---|
|
||||
| App | `com.zhushenwudi.lovelivemusicplayer` |
|
||||
| Widget | `com.zhushenwudi.lovelivemusicplayer.HomeWidgetExample` |
|
||||
| App Group | `group.com.zhushenwudi.lovelivemusicplayer` |
|
||||
| Team | `V73L9LHPCA` |
|
||||
| Version | `1.7.4` (build `74`) |
|
||||
| Debug profile | `LLMP-M-DEVELOP` / `LLMP-M-DEVELOP-WIDGET` |
|
||||
| Release profile | `LLMP-M-RELEASE` / `LLMP-M-RELEASE-WIDGET` |
|
||||
| Profile (AdHoc) | `LLMP-M-AD-HOC` / `LLMP-M-AD-HOC-WIDGET` |
|
||||
|
||||
`MainViewController.kt` calls `installIosPlatformServices()` on startup.
|
||||
最低系统:App **iOS 18.0**,Widget **iOS 17.0**。
|
||||
|
||||
## Targets & layout
|
||||
## 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)
|
||||
project.yml — XcodeGen 源配置(改完跑 ./setup.sh)
|
||||
setup.sh
|
||||
iosApp.xcodeproj — 用这个打开
|
||||
iosApp/ — 主 App(UIKit + SwiftUI host)
|
||||
WidgetExtension/ — 桌面小组件 + 资源
|
||||
```
|
||||
|
||||
## Kotlin ↔ Swift bridge (remaining macOS work)
|
||||
## Notes
|
||||
|
||||
| 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.
|
||||
- CarPlay entitlements 已挂在主 App(需账号侧已批准该 Bundle ID)。
|
||||
- PiP 用的 `black.mp4` 已在 `iosApp/pip/`。
|
||||
- SQLDelight 需要链接 `-lsqlite3`(已写在 `project.yml`)。
|
||||
- 日常运行请选 **iosApp** scheme。若选 **WidgetExtension**,Xcode 会回到主屏刷新小组件(调试 Widget 才用)。
|
||||
|
||||
Reference in New Issue
Block a user