2026 SwiftAudio & Video
WWDC26 · 21 min · Swift / Audio & Video
Integrate MusicKit into your app
Bring the power of Apple Music into your app using MusicKit. We’ll cover authorization, subscription-status checks, music selection, playback control, and cross-storefront song sharing. Learn how to use the new Music Picker to let people browse the Apple Music catalog and their personal libraries. We’ll also break down the differences between SystemMusicPlayer and ApplicationMusicPlayer, and show you how to observe playback state.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 8 snippets
Presents the Apple Music subscription offer
var showSubscriptionOffer = false
let options = MusicSubscriptionOffer.Options(
messageIdentifier: .playMusic
)
var musicSubsriptionButton: some View {
Button("Subscribe to Apple Music", systemImage: "music.note") {
showSubscriptionOffer = true
}
.musicSubscriptionOffer(isPresented: $showSubscriptionOffer, options: options)
} Adds subscription button to main view
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
}
}
} Add .musicPicker() modifier
var showMusicPicker = false
var selectedSong: Song? = nil
var musicPickerButton: some View {
Button("Pick some Music", systemImage: "music.note.list") {
showMusicPicker = true
}
.musicPicker(isPresented: $showMusicPicker, selection: $selectedSong)
}
var body: some View {
VStack {
if let subscription, subscription.canBecomeSubscriber {
musicSubscriptionButton
}
musicPickerButton
}
} Artwork
var queue = ApplicationMusicPlayer.shared.queue
var body: some View {
VStack {
if let artwork = queue.currentEntry?.artwork {
ArtworkImage(artwork, width: 200, height: 200)
} else {
// Placeholder artwork
RoundedRectangle(cornerRadius: 16)
.fill(.quaternary)
.frame(width: 200, height: 200)
}
}
} Current entry info
var queue = ApplicationMusicPlayer.shared.queue
var body: some View {
VStack {
// ...
if let currentSong = queue.currentEntry {
Text(currentSong.title)
.font(.title3.bold())
if let subtitle = currentSong.subtitle {
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
}
} Playback controls (play, pause)
let player = ApplicationMusicPlayer.shared
var state = ApplicationMusicPlayer.shared.state
var isPlaying: Bool {
state.playbackStatus == .playing
}
var playPause: some View {
Button (
isPlaying ? "Pause": "Play",
systemImage: isplaying ? "pause.fill" : "play.fill"
) {
if isPlaying {
player.pause()
} else {
Task {
try await player.play()
}
}
}
} Playback controls (next, previous)
let player = ApplicationMusicPlayer.shared
var controls: some View {
HStack {
Button("Back", systemImage: "backward.fill") {
Task {
try await player.skipToPreviousEntry()
}
}
// ...
Button("Next", systemImage: "forward.fill") {
Task {
try await player.skipToNextEntry()
}
}
}
} Music catalog resource request
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)
} Resources
Related sessions
-
26 min -
18 min -
13 min