mcpField
M
musickit

musickit

github.com/dpearson2699開発1.2k3.2k 回インストール13 週間前に更新
リポジトリ

musickit について

MusicKit は、Apple プラットフォームの開発者向けに、Apple Music カタログの検索、アプリ内再生、サブスクリプション確認、再生情報の設定を解説する Swift スキルガイドです。認証、キュー、ロック画面表示、リモート操作も扱います。

主な機能

  1. 01Apple Music カタログの検索
  2. 02音楽の認証とサブスクリプション確認
  3. 03アプリ内再生とキューの管理
  4. 04再生中のトラック情報の公開
  5. 05リモート再生操作への対応

活用シーン

  1. 01アプリ内で曲やアルバムを検索
  2. 02サブスクリプションに応じたカタログ再生
  3. 03再生キューの作成と更新
  4. 04ロック画面での曲情報表示と操作対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill musickit

インストール後、Claude Code で/musickitを入力して読み込まれたか確認します。

同梱ファイルevals/evals.jsonreferences/musickit-patterns.md

詳細

MusicKit

Apple Music カタログを検索し、ApplicationMusicPlayer で再生を管理し、サブスクリプションを確認し、MPNowPlayingInfoCenter と MPRemoteCommandCenter を介して「再生中」のメタデータを公開します。

目次

ワークフロー

  1. コードをデバッグする前に、MusicKit App Service、バンドル識別子、目的を説明する文字列、バックグラウンドオーディオモードを確認します。
  2. 認証をリクエストし、認証済みでないすべての状態を明示的にモデル化します。
  3. 再生をキューに追加する前に、カタログコンテンツを検索または読み込み、MusicSubscription.current を確認します。
  4. アプリにスコープされた再生には ApplicationMusicPlayer を選び、アプリがそれらの領域を所有する場合にのみ、「再生中」の情報とリモートコマンドを設定します。
  5. 認証済み、拒否済み、未サブスクリプション、オフライン、キュー追加失敗、中断、トラック変更の各状態をテストします。最小の失敗レイヤーを修正し、テスト用状態を元に戻して、同じ状態の組み合わせを再実行します。

セットアップ

プロジェクトの設定
  1. MusicKit が開発者トークンを自動生成できるよう、Apple Developer ポータルでアプリの明示的なバンドル ID に対して MusicKit App Service を有効にします。
  2. アプリがユーザーのメディアライブラリにアクセスする理由を説明する NSAppleMusicUsageDescription を Info.plist に追加します。
  3. バックグラウンド再生を行うには、UIBackgroundModes に audio バックグラウンドモードを追加します。
インポート
import MusicKit       // Catalog, auth, playback
import MediaPlayer    // MPRemoteCommandCenter, MPNowPlayingInfoCenter

認証

ユーザーのミュージックデータへのアクセスや Apple Music コンテンツの再生を行う前に、許可をリクエストします。必要に応じて request() が Apple の同意ダイアログを表示します。プロンプトを表示せずに現在の設定を読み取るには、currentStatus を使用します。

func requestMusicAccess() async -> MusicAuthorization.Status {
    let status = await MusicAuthorization.request()
    switch status {
    case .authorized:
        // Full access to MusicKit APIs
        break
    case .denied, .restricted:
        // Show guidance to enable in Settings
        break
    case .notDetermined:
        break
    @unknown default:
        break
    }
    return status
}

// Check current status without prompting
let current = MusicAuthorization.currentStatus

カタログ検索

MusicCatalogSearchRequest を使用して Apple Music カタログを検索します。カタログ検索では Apple Music のリソースを取得できますが、サブスクリプション対象のカタログコンテンツの再生は、引き続き MusicSubscription.current.canPlayCatalogContent で制御する必要があります。

func searchCatalog(term: String) async throws -> MusicItemCollection<Song> {
    var request = MusicCatalogSearchRequest(term: term, types: [Song.self])
    request.limit = 25

    let response = try await request.response()
    return response.songs
}
検索結果の表示
for song in songs {
    print("\(song.title) by \(song.artistName)")
    if let artwork = song.artwork {
        let url = artwork.url(width: 300, height: 300)
        // Load artwork from url
    }
}

サブスクリプションの確認

再生機能を提供する前に、ユーザーが有効な Apple Music サブスクリプションに登録しているか確認します。

func checkSubscription() async throws -> Bool {
    let subscription = try await MusicSubscription.current
    return subscription.canPlayCatalogContent
}

// Observe subscription changes
func observeSubscription() async {
    for await subscription in MusicSubscription.subscriptionUpdates {
        if subscription.canPlayCatalogContent {
            // Enable full playback UI
        } else {
            // Show subscription offer
        }
    }
}
Apple Music の提供

ユーザーがサブスクリプションに登録していない場合は、Apple Music のサブスクリプション案内シートを表示します。まず canBecomeSubscriber を確認し、シートにコンテキストに応じたメタデータや読み込みエラーの処理が必要な場合は、MusicSubscriptionOffer.Options または onLoadCompletion を渡します。

import MusicKit
import SwiftUI

struct MusicOfferView: View {
    @State private var showOffer = false

    var body: some View {
        Button("Subscribe to Apple Music") {
            Task {
                let subscription = try? await MusicSubscription.current
                showOffer = subscription?.canBecomeSubscriber == true
            }
        }
        .musicSubscriptionOffer(
            isPresented: $showOffer,
            options: .default,
            onLoadCompletion: { error in
                if let error {
                    // Surface loading errors in app UI or diagnostics.
                    print(error)
                }
            }
        )
    }
}

ApplicationMusicPlayer での再生

ApplicationMusicPlayer は Music アプリとは独立して Apple Music コンテンツを再生します。システムプレーヤーの状態には影響しません。

let player = ApplicationMusicPlayer.shared

func playSong(_ song: Song) async throws {
    player.queue = [song]
    try await player.play()
}

func pause() {
    player.pause()
}

func skipToNext() async throws {
    try await player.skipToNextEntry()
}
再生状態の監視
func observePlayback() {
    // player.state is an @Observable property
    let state = player.state
    switch state.playbackStatus {
    case .playing:
        break
    case .paused:
        break
    case .stopped, .interrupted, .seekingForward, .seekingBackward:
        break
    @unknown default:
        break
    }
}

キューの管理

ApplicationMusicPlayer.Queue を使用して再生キューを構築、操作します。

// Initialize with multiple items
func playAlbum(_ album: Album) async throws {
    player.queue = [album]
    try await player.play()
}

// Append songs to the existing queue
func appendToQueue(_ songs: [Song]) async throws {
    try await player.queue.insert(songs, position: .tail)
}

// Insert song to play next
func playNext(_ song: Song) async throws {
    try await player.queue.insert(song, position: .afterCurrentEntry)
}

再生中の情報

MPNowPlayingInfoCenter を更新して、ロック画面、コントロールセンター、CarPlay に現在のトラックのメタデータを表示します。これはカスタムオーディオ(MusicKit 以外のソース)を再生する場合に不可欠です。Apple Music コンテンツについては、ApplicationMusicPlayer が自動的に処理します。

import MediaPlayer

func updateNowPlaying(title: String, artist: String, duration: TimeInterval, elapsed: TimeInterval) {
    var info = [String: Any]()
    info[MPMediaItemPropertyTitle] = title
    info[MPMediaItemPropertyArtist] = artist
    info[MPMediaItemPropertyPlaybackDuration] = duration
    info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsed
    info[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
    info[MPNowPlayingInfoPropertyMediaType] = MPNowPlayingInfoMediaType.audio.rawValue

    MPNowPlayingInfoCenter.default().nowPlayingInfo = info
}

func clearNowPlaying() {
    MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
}
アートワークの追加
func setArtwork(_ image: UIImage) {
    let artwork = MPMediaItemArtwork(boundsSize: image.size) { _ in image }
    var info = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:]
    info[MPMediaItemPropertyArtwork] = artwork
    MPNowPlayingInfoCenter.default().nowPlayingInfo = info
}

リモートコマンドセンター

MPRemoteCommandCenter のハンドラーを登録し、ロック画面のコントロール、AirPods のタップ操作、CarPlay のボタンに応答します。

func setupRemoteCommands() {
    let center = MPRemoteCommandCenter.shared()

    center.playCommand.addTarget { _ in
        resumePlayback()
        return .success
    }

    center.pauseCommand.addTarget { _ in
        pausePlayback()
        return .success
    }

    center.nextTrackCommand.addTarget { _ in
        skipToNext()
        return .success
    }

    center.previousTrackCommand.addTarget { _ in
        skipToPrevious()
        return .success
    }

    // Disable commands you do not support
    center.seekForwardCommand.isEnabled = false
    center.seekBackwardCommand.isEnabled = false
}
スクラブ操作のサポート
func enableScrubbing() {
    let center = MPRemoteCommandCenter.shared()
    center.changePlaybackPositionCommand.addTarget { event in
        guard let positionEvent = event as? MPChangePlaybackPositionCommandEvent else {
            return .commandFailed
        }
        seek(to: positionEvent.positionTime)
        return .success
    }
}

よくある間違い

間違い修正方法
App Service と目的を示す文字列を設定する前に、認証のデバッグを行うまずサービス、バンドル ID、NSAppleMusicUsageDescription を確認します。
サブスクリプションの確認をせずにカタログのコンテンツをキューに追加するcanPlayCatalogContent を確認し、canBecomeSubscriber が true の場合にのみサブスクリプションを案内します。
アプリが所有する再生に SystemMusicPlayer を使うApplicationMusicPlayer を使います。システムプレーヤーを使うと、Music アプリのグローバルキューが変更されます。
「再生中」メタデータを一度だけ公開するトラック、再生時間、再生レート、経過時間が変わるたびに更新します。
サポートされていないリモートコマンドを登録する無効にします。サポート対象のハンドラーは、処理を実行して .success を返す必要があります。

レビューチェックリスト

  • アプリの明示的なバンドル ID に対して MusicKit App Service が有効になっている
  • NSAppleMusicUsageDescription が Info.plist に追加されている
  • MusicKit にアクセスする前に MusicAuthorization.request() が呼び出されている
  • カタログ再生を試みる前にサブスクリプションを確認している
  • サブスクリプションの案内を表示する前に canBecomeSubscriber を確認している
  • ライブラリに書き込む前に hasCloudLibraryEnabled を確認している
  • アプリ内の再生には SystemMusicPlayer ではなく ApplicationMusicPlayer を使用している
  • 音楽をバックグラウンドで再生する場合、バックグラウンドオーディオモードが有効になっている
  • カスタムオーディオの場合、トラックが変わるたびに「再生中」情報を更新している
  • サポート対象のコマンドに対して、リモートコマンドハンドラーが .success を返している
  • サポートされていないリモートコマンドが isEnabled = false で無効になっている
  • ロック画面に表示するアートワークが「再生中」情報に設定されている
  • スクラバーの精度を保つため、再生経過時間が定期的に更新されている
  • ユーザーが Apple Music サブスクリプションに加入していない場合、サブスクリプションを案内している

参考資料

コメント