MusicKit provides Swift-native APIs to browse the Apple Music catalog and personal library via a unified music picker, and play selected songs using ApplicationMusicPlayer. iOS 27 surfaces these capabilities through new SwiftUI view modifiers like .musicPicker and the subscription offer UI.
โข New .musicPicker SwiftUI view modifier unifies catalog and library browsing in a single picker UI, replacing older manual MusicCatalogSearchRequest + MPMediaPickerController patterns.
โข MusicSubscriptionOffer view modifier added for in-app Apple Music subscription upsell flow with configurable messageIdentifier and affiliate partner options.
โข ApplicationMusicPlayer.queue is now a fully observable SwiftUI class, enabling direct use in SwiftUI views without manual Combine subscriptions.
โข ArtworkImage SwiftUI view officially part of the integration flow for displaying now-playing artwork from MusicKit items.
โข The .musicPicker view modifier gives users a single unified interface to search both the Apple Music catalog and their personal library, drastically reducing the code needed to let users select music.
โข ApplicationMusicPlayer gives full read/write queue access with observable SwiftUI-compatible state, making it straightforward to build custom playback UIs with artwork, skip controls, and play/pause.
โข The .musicSubscriptionOffer view modifier lets you upsell Apple Music subscriptions in-app (with potential affiliate commissions) without ever leaving your app.
Demonstrates selecting multiple songs via the new .musicPicker modifier and playing them with ApplicationMusicPlayer, showing live artwork and playback controls.
import SwiftUIimport MusicKitโimport MediaPlayerโimport StoreKitโ// Pre-iOS 27: separate catalog search + MPMediaPickerControllerโstruct OldWorkoutMusicView: UIViewControllerRepresentable {โ func makeUIViewController(context: Context) -> MPMediaPickerController {โ let picker = MPMediaPickerController(mediaTypes: .music)โ picker.allowsPickingMultipleItems = trueโ picker.delegate = context.coordinatorโ return picker+struct WorkoutPlayerView: View {+ @State private var isPickerPresented = false+ @State private var selectedSongs: [Song] = []+ @State private var isSubscriptionOfferPresented = false+ @State private var isSubscribed = false++ private let player = ApplicationMusicPlayer.shared++ var currentEntry: ApplicationMusicPlayer.Queue.Entry? {+ player.queue.currentEntry}โ func updateUIViewController(_ uiViewController: MPMediaPickerController, context: Context) {}โ func makeCoordinator() -> Coordinator { Coordinator() }โ class Coordinator: NSObject, MPMediaPickerControllerDelegate {โ func mediaPicker(_ mediaPicker: MPMediaPickerController,โ didPickMediaItems mediaItemCollection: MPMediaItemCollection) {โ // Had to bridge MPMediaItems to MusicKit manually via persistentIDโ let ids = mediaItemCollection.items.compactMap { $0.value(forProperty: MPMediaItemPropertyPersistentID) as? UInt64 }โ Task {โ // Manually construct a MusicLibraryRequest to resolve itemsโ var request = MusicLibraryRequest<Song>()โ // No direct multi-pick view modifier existed; UIKit bridging requiredโ let response = try? await request.response()โ // Then manually set the system player queueโ let player = SystemMusicPlayer.sharedโ // SystemMusicPlayer had limited queue write accessโ try? await player.play()+ var isPlaying: Bool {+ player.state.playbackStatus == .playing+ }++ var body: some View {+ VStack(spacing: 20) {+ // Artwork for currently playing item+ if let song = currentEntry?.item,+ case let .song(s) = song,+ let artwork = s.artwork {+ ArtworkImage(artwork, width: 280)+ .cornerRadius(12)+ } else {+ RoundedRectangle(cornerRadius: 12)+ .fill(Color.secondary.opacity(0.3))+ .frame(width: 280, height: 280)+ .overlay(Image(systemName: "music.note").font(.largeTitle))}โ mediaPicker.dismiss(animated: true)++ // Song info+ VStack(spacing: 4) {+ Text(currentEntry?.title ?? "No song selected")+ .font(.headline)+ Text(currentEntry?.subtitle ?? "")+ .font(.subheadline)+ .foregroundStyle(.secondary)+ }++ // Playback controls+ HStack(spacing: 40) {+ Button { Task { try? await player.skipToPreviousEntry() } } label: {+ Image(systemName: "backward.fill").font(.title2)+ }+ Button {+ Task {+ if isPlaying { player.pause() }+ else { try? await player.play() }+ }+ } label: {+ Image(systemName: isPlaying ? "pause.fill" : "play.fill")+ .font(.title)+ }+ Button { Task { try? await player.skipToNextEntry() } } label: {+ Image(systemName: "forward.fill").font(.title2)+ }+ }++ // Open music picker+ Button("Choose Workout Songs") {+ isPickerPresented = true+ }+ .buttonStyle(.borderedProminent)+ .musicPicker(isPresented: $isPickerPresented, selection: $selectedSongs) { songs in+ Task {+ player.queue = ApplicationMusicPlayer.Queue(for: songs)+ try? await player.prepareToPlay()+ try? await player.play()+ }+ }++ // Subscription offer for non-subscribers+ if !isSubscribed {+ Button("Subscribe to Apple Music") {+ isSubscriptionOfferPresented = true+ }+ .musicSubscriptionOffer(+ isPresented: $isSubscriptionOfferPresented,+ options: MusicSubscriptionOffer.Options(messageIdentifier: .playMusic)+ )+ }}โ func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {โ mediaPicker.dismiss(animated: true)+ .padding()+ .task {+ let status = await MusicAuthorization.request()+ guard status == .authorized else { return }+ let subscription = try? await MusicSubscription.current+ isSubscribed = subscription?.canPlayCatalogContent ?? false}}}โ// Subscription offer required leaving the app to the App Storeโstruct OldSubscribeView: View {โ var body: some View {โ Link("Subscribe to Apple Music",โ destination: URL(string: "https://music.apple.com/subscribe")!)โ }+#Preview {+ WorkoutPlayerView()}
LiveCommunicationKit is the modern replacement for CXProvider that delivers rich, native conversation UIs integrated with the Lock Screen, Dynamic Island, Phone app Recents, and Siri. It provides a unified lifecycle model for audio and video conversations with a single delegate-driven action pipeline.
USDKit is a new first-party Swift framework introduced in iOS/macOS 27 that brings native USD scene creation, composition, modification, and export capabilities to Apple platform apps, with deep RealityKit and Spatial Preview integration.
iOS 27 adds sectioned queries, codable model attributes, ResultsObserver for non-SwiftUI change observation, and HistoryObserver for reacting to persistent history changes in SwiftData.
In-depth guide
iOS 26 โ iOS 27 Migration Guide โAutomatic developer token generation requires the MusicKit entitlement checked under the App ID on the developer portal and the correct Apple ID signed into Xcode. The Media Library capability with a usage description string must be added in the Signing & Capabilities tab or the permission alert will not appear. ApplicationMusicPlayer requires the Audio Background Mode capability to continue playback when the app is backgrounded. prepareToPlay() should be called before play() to reduce audio latency.
Apple Music catalog access requires an active Apple Music subscription; without one, only purchased or synced library content is accessible. MusicKit capability must be enabled in the Apple Developer portal App ID settings.
The NowPlaying framework introduces a first-class Swift API for surfacing app media in system-wide now-playing surfaces โ Lock Screen, Control Center, Dynamic Island, StandBy, CarPlay, Apple Watch, and Apple TV โ via a declarative MediaSessionRepresentable protocol. It also supports remote media sessions (for controlling external speakers/TVs) and Media Sharing Extensions for routing media to third-party devices.