ハイライト
MusicKit は SwiftUI 向けに
.musicPicker()と.musicSubscriptionOffer()という2つのネイティブ修飾子を提供します。音楽専用ではない App でも、数行のコードで認可、曲選択、再生制御、購読案内までを一連の体験として組み込めます。
主要内容
以前の Apple Music 連携がなぜ大変だったのか
フィットネス App にバックグラウンド音楽を追加したいとします。以前の流れはこうでした。まずユーザーの許可を求める認可ロジックを書く。次に Apple Music の購読状況を判定する。未購読なら購読を促す UI を自前で作る。購読済みなら曲選択画面を作り、再生キューを扱い、再生状態を監視する。単に BGM 機能を入れたいだけなのに、数千行近いコードを書くこともありました。
Apple が変えたこと
WWDC26 の MusicKit は、この流れを2つの SwiftUI 修飾子とネイティブの音楽ピッカーにまとめました。認可には MusicAuthorization.request()、購読案内には .musicSubscriptionOffer()、曲選択には .musicPicker()、再生制御には ApplicationMusicPlayer.shared を使います。連携作業は「App の半分を作り直す」ものから「いくつかの修飾子を追加する」ものに変わりました。
新機能がどのように課題を解くか
セッションで示されたフィットネス App を例にすると、ユーザーがサイクリングワークアウトを開始するときに「音楽を選ぶ」ボタンをタップし、.musicPicker() で Apple Music カタログまたは個人ライブラリから曲を選べます。未購読のユーザーには購読ボタンを自動的に表示し、タップすると .musicSubscriptionOffer() が出て、App を離れずに購読できます。選んだ曲は ApplicationMusicPlayer で再生され、App 内にアルバムアート、曲情報、再生コントロールを直接表示できます。体験全体がネイティブで、途切れません。
詳細
認可とプロジェクト設定
(01:03) MusicKit を組み込む最初の手順は、Xcode で MusicKit サービスを有効化することです。App ID 登録ページの App Services タブで MusicKit にチェックを入れます。Xcode が開発者トークンを自動生成するため、手動で管理する必要はありません。
(03:12) ユーザー認可は MusicAuthorization.request() でリクエストします。これは非同期メソッドで、認可状態を返します。権限ダイアログでより明確な説明を表示するには、Xcode の Signing & Capabilities に Media Library 機能を追加し、説明テキスト欄に App が音楽ライブラリを使う目的を記入します。
購読案内
(04:46) Apple Music に未購読のユーザーには、.musicSubscriptionOffer() 修飾子を使って App 内で購読案内画面を直接表示できます。ユーザーは Music App や App Store に移動する必要がありません。
@State var showSubscriptionOffer = false
let options = MusicSubscriptionOffer.Options(
messageIdentifier: .playMusic
)
@ViewBuilder
var musicSubscriptionButton: some View {
Button("Apple Music に登録", systemImage: "music.note") {
showSubscriptionOffer = true
}
.musicSubscriptionOffer(isPresented: $showSubscriptionOffer, options: options)
}
重要な点:
MusicSubscriptionOffer.OptionsのmessageIdentifierは、オファー UI に表示される文言とスタイルを決めます。.playMusicは再生シーンに向いています。- 開発者は Apple Services Performance Partner Program を通じて購読コミッションを得られます。
- オファーの表示と非表示は
isPresentedバインディングで制御します。
(05:59) メインビューでは購読状態を監視し、ユーザーが購読可能な場合だけボタンを表示します。
@State var subscription: MusicSubscription?
var body: some View {
VStack {
if let subscription, subscription.canBecomeSubscriber {
musicSubscriptionButton
}
}
.task(id: isAuthorized) {
self.subscription = try? await MusicSubscription.current
for await subscription in MusicSubscription.subscriptionUpdates {
self.subscription = subscription
}
}
}
重要な点:
MusicSubscription.currentは現在の購読状態を取得します。MusicSubscription.subscriptionUpdatesはAsyncSequenceで、購読状態が変わると新しい値を自動的に流します。canBecomeSubscriberは、ユーザーが購読可能かどうか、つまり未購読で、かつ地域が対応しているかを判定します。
音楽ピッカー
(08:48) .musicPicker() は SwiftUI のビュー修飾子で、Apple Music カタログと個人ライブラリを閲覧するネイティブ UI を表示します。単一選択と複数選択の両方に対応し、アルバムやプレイリストも選べます。
@State var showMusicPicker = false
@State var selectedSong: Song? = nil
@ViewBuilder
var musicPickerButton: some View {
Button("音楽を選ぶ", systemImage: "music.note.list") {
showMusicPicker = true
}
.musicPicker(isPresented: $showMusicPicker, selection: $selectedSong)
}
重要な点:
selectionをSong?にバインドすると単一選択、[Song]にバインドすると複数選択になります。- Apple Music に未購読でも使えますが、その場合ユーザーに見えるのは個人ライブラリ内のコンテンツだけです。
- 検索、アルバム詳細ページの閲覧、プレイリスト全体の選択に対応しています。
2種類のプレイヤーの選び方
(10:54) MusicKit は2種類のプレイヤーを提供します。
| 特徴 | SystemMusicPlayer | ApplicationMusicPlayer |
|---|---|---|
| 制御対象 | システムの Music App | App 自身 |
| バックグラウンド再生 | 自動対応 | Audio Background Mode が必要 |
| キューアクセス | 現在の項目のみ読み取り | 完全な読み書き |
| 向いている場面 | 独立した音楽クライアント | フィットネスや瞑想など BGM が必要な App |
ApplicationMusicPlayer のキューは遅延読み込みに対応します。アルバムやプレイリストでキューを初期化すると、プレイヤーは全曲を一度に読み込むのではなく、必要に応じて曲を読み込みます。これにより起動時の遅延を大きく減らせます。
(13:02) prepareToPlay() メソッドは、ユーザーが再生をタップする前に音声アセットを事前バッファし、タップ後の待ち時間をなくせます。
let player = ApplicationMusicPlayer.shared
// 事前にバッファする
Task {
try await player.prepareToPlay()
}
再生制御と状態監視
(14:49) ApplicationMusicPlayer の queue と state はどちらも監視可能なオブジェクトなので、SwiftUI ビュー内で直接使えます。
現在の曲のアルバムアートを表示する例です。
@State var queue = ApplicationMusicPlayer.shared.queue
var body: some View {
VStack {
if let artwork = queue.currentEntry?.artwork {
ArtworkImage(artwork, width: 200, height: 200)
} else {
RoundedRectangle(cornerRadius: 16)
.fill(.quaternary)
.frame(width: 200, height: 200)
}
}
}
重要な点:
ArtworkImageは MusicKit が提供する SwiftUI ビューで、アルバムアートの読み込みと表示を自動で処理します。queue.currentEntry?.artworkは現在再生中の項目のアートワークリソースを取得します。.quaternaryの塗りつぶしをプレースホルダーに使うと、自然な視覚遷移になります。
(15:06) 曲名とサブタイトルの表示です。
if let currentSong = queue.currentEntry {
Text(currentSong.title)
.font(.title3.bold())
if let subtitle = currentSong.subtitle {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
(15:14) 再生と一時停止の制御です。
let player = ApplicationMusicPlayer.shared
@State var state = ApplicationMusicPlayer.shared.state
var isPlaying: Bool {
state.playbackStatus == .playing
}
var playPause: some View {
Button(
isPlaying ? "一時停止" : "再生",
systemImage: isPlaying ? "pause.fill" : "play.fill"
) {
if isPlaying {
player.pause()
} else {
Task {
try await player.play()
}
}
}
}
重要な点:
state.playbackStatusは.playingや.pausedなどの列挙値を返します。player.play()とplayer.pause()はどちらも非同期メソッドなので、Task内で呼び出します。- 再生状態の変化は SwiftUI ビューの更新を自動的に引き起こします。
(15:38) 前の曲と次の曲の制御です。
let player = ApplicationMusicPlayer.shared
var controls: some View {
HStack {
Button("戻る", systemImage: "backward.fill") {
Task {
try await player.skipToPreviousEntry()
}
}
// ...
Button("次へ", systemImage: "forward.fill") {
Task {
try await player.skipToNextEntry()
}
}
}
}
カタログリクエストと地域間の同等項目
(16:26) MusicCatalogResourceRequest は Apple Music カタログから特定のリソースをリクエストするために使います。曲の Artists リレーションなどの関連データや、返される件数の上限を指定できます。
(18:58) 地域間の同等項目は MusicKit の重要な機能です。同じ曲でも Apple Music の地域ごとに異なる ID を持つことがあり、一部の地域では explicit 版の代わりにクリーン版が提供されることもあります。.findEquivalents オプションを使うと、こうした対応付けを自動で処理できます。
func fetchSongs(songIDs: [MusicItemID]) async throws -> (featured: Song?, other: [Song]) {
var request = MusicCatalogResourceRequest<Song>(
matching: \.id, memberOf: songIDs
)
request.options = [.findEquivalents]
let response = try await request.response()
let featuredSongID = songIDs[0]
let featuredSong = response.item(for: featuredSongID)
let others: [Song] = songIDs[1...].compactMap { songID in
return response.item(for: songID)
}
return (featuredSong, others)
}
重要な点:
MusicCatalogResourceRequest<Song>はジェネリックなリクエストで、<Song>が戻り値の型を指定します。matching: \.id, memberOf: songIDsは、リクエスト一覧の曲を ID で照合することを表します。.findEquivalentsは地域間の同等項目検索を有効化し、利用できないリソースを自動的に置き換えます。response.item(for:)は元の ID で結果を取得します。実際に返ったものが同等版でも扱えます。MusicItemCollectionはページングに対応し、hasNextBatchとnextBatch()で後続結果を取得できます。
実践アイデア
1. フィットネス App にワークアウト用 BGM を追加する
ワークアウト開始画面に「音楽を選ぶ」ボタンを追加し、.musicPicker() でユーザーにプレイリストを選ばせます。ApplicationMusicPlayer を使ってワークアウト中にループ再生します。カウントダウン中に prepareToPlay() を呼ぶと、ユーザーが「開始」をタップした瞬間に音楽を鳴らせます。
入り口 API:ApplicationMusicPlayer.shared + .musicPicker()
2. 集中タイマーにホワイトノイズや背景音楽を組み込む
ポモドーロや瞑想 App では、MusicCatalogResourceRequest を使って Apple Music 上の集中用プレイリストやホワイトノイズアルバムを取得し、プリセットとして表示できます。ユーザーは Music App で検索するために離脱せず、タップだけで再生を始められます。
入り口 API:MusicCatalogResourceRequest<Playlist> + ApplicationMusicPlayer
3. ソーシャル App に「今聴いている曲を共有」機能を追加する
queue.currentEntry で現在再生中の曲情報を取得し、ArtworkImage と組み合わせて共有カードを生成します。MusicCatalogResourceRequest の .findEquivalents オプションを使えば、異なる地域のユーザーでも共有された曲リンクを正しく開けます。
入り口 API:queue.currentEntry + MusicCatalogResourceRequest + .findEquivalents
4. ゲーム App で動的に背景音楽を切り替える
戦闘、探索、ストーリーなどのゲーム場面ごとに異なる MusicItemCollection を事前読み込みし、ApplicationMusicPlayer のキュー操作で滑らかに切り替えます。Audio Background Mode を有効にすると、プレイヤーが別の App に切り替えても音楽を継続できます。
入り口 API:ApplicationMusicPlayer.shared.queue + prepareToPlay()
5. 子ども向け App でコンテンツを安全にフィルタリングする
MusicCatalogResourceRequest の .findEquivalents オプションを使うと、ユーザーのアカウント設定で explicit コンテンツが利用できない場合に、MusicKit が自動でクリーン版を返します。App 側でコンテンツレーティングのロジックを維持する必要はありません。
入り口 API:MusicCatalogResourceRequest + .findEquivalents
関連セッション
- 253 - Explore music understanding - Apple Music の音楽理解機能。MusicKit と組み合わせることでスマートな推薦を実現できます
- 312 - What’s new in Now Playing - システムレベルの再生制御と Now Playing インターフェイスの最新アップデート
- 310 - What’s new in Shortcuts - ショートカットを通じて App の音楽関連オートメーションを拡張する方法
- 262 - What’s new in Swift - MusicKit で全面的に使われる Swift Concurrency と SwiftUI の新機能
- 269 - What’s new in SwiftUI -
.musicPicker()や.musicSubscriptionOffer()などの修飾子の SwiftUI 実装詳細
コメント
GitHub Issues · utterances