Integrate MusicKit into your app
App Store & Distribution 进阶 21m

将 MusicKit 整合到你的 App 中

Integrate MusicKit into your app

2026年6月10日

在 Apple 官方观看视频

一句话判断

✅ 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 颜色做骨架屏过渡非常自然。
MusicKit SwiftUI SystemMusicPlayer MusicPicker Apple Music