将 MusicKit 整合到你的 App 中
Integrate MusicKit into your app
2026年6月10日
一句话判断
✅ MusicKit 终于把授权、选歌、播放和订阅转化打磨成了一套极其顺滑的 SwiftUI 原生体验,非音乐类 App 接入 Apple Music 的门槛降到了历史最低。
这场 Session 讲了什么
这场 Session 最值得关注的一件事是:Apple 把 MusicKit 从一个“给纯音乐 App 用的底层 API”变成了“任何 App 都能轻松调用的 SwiftUI 插件”。以前你要在 App 里加个“健身时听 Apple Music”的功能,得自己写授权逻辑、判断订阅状态、手搓选歌列表、处理播放队列,现在全被 .musicPicker 和 .musicSubscriptionOffer 这两个 View Modifier 包圆了。
Apple 这次明确划分了 SystemMusicPlayer(系统播放器)和 ApplicationMusicPlayer(应用内播放器)的边界,并补齐了异步状态监听的短板。这对健身、冥想、游戏或者社交类 App 影响最大,你不再需要为了加个 BGM 功能去重写半个 App,几行代码就能拉起原生的选歌和订阅 UI,甚至还能通过 Apple Services Performance Partner Program 拿订阅佣金。
值得深挖的点
.musicPicker 与订阅转化的商业闭环
Apple 这次主推的 .musicPicker 和 .musicSubscriptionOffer 表面上是 UI 组件,背后其实是 Apple Music 拉新的商业阳谋。以前开发者不愿意接 Apple Music,因为非订阅用户只能听本地库,体验割裂,开发者还得自己写引导订阅的 UI。现在 Apple 直接提供了原生的订阅弹窗,通过 MusicSubscriptionOffer.Options 配置 messageIdentifier(比如 .playMusic),用户不用离开你的 App 就能完成订阅。
这里的 trade-off 很明显:你失去了对选歌和订阅 UI 的绝对控制权,必须用 Apple 的原生样式。但换来的是极高的用户信任度、免审核的 UI 以及实打实的佣金收入。对于非纯音乐类 App 来说,用原生组件绝对比自己手搓一套半吊子 UI 转化率高得多。配合 MusicSubscription.subscriptionUpdates 这个 AsyncSequence,你可以实时监听用户在弹窗里完成订阅的动作,无缝衔接播放逻辑,体验非常丝滑。
SystemMusicPlayer vs ApplicationMusicPlayer 的生死抉择
Session 里花了不少篇幅讲这两个播放器,很多新手在这里栽过跟头。SystemMusicPlayer 是系统的“遥控器”,它控制的是系统的 Music App,App 退到后台或者被杀进程,音乐照样播,锁屏控制中心也能完美接管。但代价是,你只能往队列里塞东西,拿不到完整的队列内容,也做不了复杂的队列操作。
ApplicationMusicPlayer 则是你的 App 自己在发声。你可以完全读写队列、监听每一首歌的播放进度。但坑在于,如果你用它,必须在 Xcode 的 Signing & Capabilities 里勾选 Background Modes 下的 “Audio, AirPlay, and Picture in Picture”,否则 App 一退到后台音乐就断了。另外,Session 里提到的 prepareToPlay() 是个容易被忽略的神仙 API,在用户点击播放前预先缓冲音频资产,能显著消除点击播放按钮后那让人烦躁的半秒钟延迟。
代码片段
1. 优雅处理订阅状态与转化 UI
场景:在主页展示订阅按钮,仅对未订阅用户显示,并监听订阅状态变化。
@State var subscription: MusicSubscription?
@State var showSubscriptionOffer = false
// 配置订阅弹窗选项,指定场景为播放音乐
let options = MusicSubscriptionOffer.Options(messageIdentifier: .playMusic)
var body: some View {
VStack {
// 只有当用户有资格订阅时才显示按钮
if let subscription, subscription.canBecomeSubscriber {
Button("订阅 Apple Music") {
showSubscriptionOffer = true
}
// 挂载原生订阅弹窗
.musicSubscriptionOffer(isPresented: $showSubscriptionOffer, options: options)
}
}
// 使用 AsyncSequence 实时监听订阅状态变化
.task {
self.subscription = try? await MusicSubscription.current
for await updatedSubscription in MusicSubscription.subscriptionUpdates {
self.subscription = updatedSubscription
}
}
}
坑:别忘了在 Xcode 的 Info.plist 里配置 NSAppleMusicUsageDescription,否则请求授权时会直接 Crash。
2. 使用原生音乐选择器
场景:让用户从 Apple Music 目录或本地资料库中挑选多首歌曲。
@State var showMusicPicker = false
// 使用数组支持多选,如果是单选则用 Song?
@State var selectedSongs: [Song] = []
var body: some View {
Button("选择 workout 音乐") {
showMusicPicker = true
}
// 呼出原生音乐选择器
.musicPicker(isPresented: $showMusicPicker, selection: $selectedSongs)
}
坑:.musicPicker 不需要用户有 Apple Music 订阅也能用,但未订阅用户只能看到并选择他们本地资料库(Local Library)里的歌。
3. 应用内播放控制与状态观察
场景:使用 ApplicationMusicPlayer 播放选中的歌曲,并构建播放/暂停控制 UI。
let player = ApplicationMusicPlayer.shared
@State var state = ApplicationMusicPlayer.shared.state
var isPlaying: Bool {
state.playbackStatus == .playing
}
var playPauseButton: some View {
Button(isPlaying ? "暂停" : "播放", systemImage: isPlaying ? "pause.fill" : "play.fill") {
if isPlaying {
player.pause()
} else {
Task {
// 播放前预缓冲,减少首帧延迟
try await player.prepareToPlay()
try await player.play()
}
}
}
}
坑:使用 ApplicationMusicPlayer 必须在 Xcode 开启 Background Modes -> Audio,否则切到后台立刻静音。
最佳实践
对于已有项目,如果你之前用 MPMediaPickerController 或者自己写了一套 Apple Music API 的请求和选歌逻辑,强烈建议迁移到 .musicPicker。这能帮你砍掉成百上千行的 UI 和数据解析代码,把精力放回业务本身。
新项目接入时,优先明确你的 App 是“音乐播放器”还是“需要 BGM 的工具”。如果是后者(比如健身、番茄钟),无脑选择 ApplicationMusicPlayer,自己掌控队列和播放时机;如果是前者(比如独立的音乐客户端),使用 SystemMusicPlayer 能帮你省去处理锁屏控制中心和后台音频中断的麻烦。
实战中最容易踩的坑是网络延迟导致的播放卡顿。在构建播放队列时,尽量使用容器类型(如 Album 或 Playlist)的特殊队列初始化方法,MusicKit 会在底层做延迟加载(Lazy loading),这比把几百首 Song 塞进数组里再传给 Player 要快得多。
还有什么值得关注
- 跨区内容等效:
MusicCatalogResourceRequest新增了.findEquivalents选项,当请求的特定歌曲在用户所在区服不可用时,自动返回等效的替代版本,避免开天窗。 - 异步状态监听:
MusicSubscription.subscriptionUpdates和播放器的状态都全面拥抱了 Swift Concurrency,用for await监听状态变化比以前的 Combine 或 Delegate 模式清爽太多。 - Artwork 渲染优化:
ArtworkImage组件现在能更好地处理占位图和圆角,配合.quaternary颜色做骨架屏过渡非常自然。