MusicKit provides a unified Swift framework for accessing Apple Music catalog and personal libraries, now featuring a .musicPicker SwiftUI view modifier for unified catalog+library browsing and ApplicationMusicPlayer for full in-app playback control.
โข New .musicPicker SwiftUI view modifier provides a unified catalog+library picker, replacing the need to build custom MusicKit search UIs.
โข .musicSubscriptionOffer view modifier enables in-app Apple Music subscription prompts with configurable message identifiers.
โข Automatic developer token generation is now supported via the App ID MusicKit checkbox, removing manual token management.
โข ArtworkImage SwiftUI view and observable ApplicationMusicPlayer.queue make it straightforward to bind now-playing artwork and controls directly in SwiftUI.
โข The new .musicPicker view modifier unifies Apple Music catalog and personal library selection in a single, ready-made UI โ no custom search screens needed.
โข ApplicationMusicPlayer gives full read/write queue access, playback state observation, and artwork display via ArtworkImage โ all compatible with Swift concurrency and SwiftUI.
โข The .musicSubscriptionOffer modifier lets developers present in-app Apple Music subscription flows without leaving the app, with potential for affiliate commissions.
Demonstrates requesting MusicKit authorization, presenting the music picker for multi-song selection, and playing the selected songs with playback controls using ApplicationMusicPlayer.
import SwiftUIimport MusicKitโ// Pre-iOS 27: No .musicPicker modifier; developers had to buildโ// their own search UI using MusicCatalogSearchRequest manually.โ@MainActorโstruct LegacyWorkoutMusicView: View {โ @State private var searchText = ""โ @State private var songs: [Song] = []โ @State private var selectedSong: Song?+struct WorkoutMusicView: View {+ @State private var authStatus: MusicAuthorization.Status = .notDetermined+ @State private var showPicker = false+ @State private var selectedSongs: [Song] = []+ @State private var isSubscribed = false+ @State private var showSubscriptionOffer = false+ private let player = ApplicationMusicPlayer.shared+var body: some View {โ VStack {โ TextField("Search songs", text: $searchText)โ .textFieldStyle(.roundedBorder)โ .padding()โ .onSubmit { Task { await searchSongs() } }+ VStack(spacing: 20) {+ // Now-playing artwork+ if let entry = player.queue.currentEntry,+ let artwork = entry.artwork {+ ArtworkImage(artwork, width: 200, height: 200)+ .cornerRadius(12)+ Text(entry.title)+ .font(.headline)+ Text(entry.subtitle ?? "")+ .font(.subheadline)+ .foregroundStyle(.secondary)+ } else {+ RoundedRectangle(cornerRadius: 12)+ .fill(Color.secondary.opacity(0.2))+ .frame(width: 200, height: 200)+ .overlay(Image(systemName: "music.note").font(.largeTitle))+ }โ List(songs, id: \.id) { song inโ Button(song.title) {โ selectedSong = songโ Task { await playSong(song) }+ // Playback controls+ HStack(spacing: 40) {+ Button { Task { try? await player.skipToPreviousEntry() } } label: {+ Image(systemName: "backward.fill").font(.title2)}+ Button {+ Task {+ if player.state.playbackStatus == .playing {+ player.pause()+ } else {+ try? await player.play()+ }+ }+ } label: {+ Image(systemName: player.state.playbackStatus == .playing ? "pause.fill" : "play.fill")+ .font(.title)+ }+ Button { Task { try? await player.skipToNextEntry() } } label: {+ Image(systemName: "forward.fill").font(.title2)+ }}โ if let song = selectedSong {โ Text("Now playing: \(song.title)")โ .padding()+ Divider()++ // Open music picker+ Button("Pick Workout Songs") {+ showPicker = true}+ .buttonStyle(.borderedProminent)+ .musicPicker(+ isPresented: $showPicker,+ selection: $selectedSongs+ )++ if !isSubscribed {+ Button("Subscribe to Apple Music") {+ showSubscriptionOffer = true+ }+ .musicSubscriptionOffer(+ isPresented: $showSubscriptionOffer,+ options: MusicSubscriptionOffer.Options(+ messageIdentifier: .playMusic+ )+ )+ }}+ .padding().task {โ _ = await MusicAuthorization.request()+ authStatus = await MusicAuthorization.request()+ guard authStatus == .authorized else { return }+ // Load subscription status and observe changes+ for await subscription in MusicSubscription.subscriptionUpdates {+ isSubscribed = subscription.canPlayCatalogContent+ }}โ }โโ func searchSongs() async {โ var request = MusicCatalogSearchRequest(โ term: searchText,โ types: [Song.self]โ )โ request.limit = 20โ if let response = try? await request.response() {โ songs = Array(response.songs)+ .onChange(of: selectedSongs) { _, songs in+ guard !songs.isEmpty else { return }+ Task {+ player.queue = ApplicationMusicPlayer.Queue(for: songs)+ try? await player.play()+ }}}โโ func playSong(_ song: Song) async {โ ApplicationMusicPlayer.shared.queue = ApplicationMusicPlayer.Queue(for: [song])โ try? await ApplicationMusicPlayer.shared.play()โ }}#Preview {โ LegacyWorkoutMusicView()+ WorkoutMusicView()}
You must add the Media Library capability in Xcode's Signing & Capabilities tab and provide a usage description string. The music picker shows only library content for non-subscribers. For background audio with ApplicationMusicPlayer, the Audio Background Mode capability must also be enabled. MusicAuthorization.request() must be called before any MusicKit API usage.
Apple Music subscription required for full catalog access; purchased/synced music works without subscription. Developer token must be registered in the Apple Developer portal with MusicKit capability enabled.
More iOS 27 APIs land every week.
Get notified when new capabilities are published โ no noise, just signal.