Highlight
MusicKit 在 2022 年大幅扩展了能力边界:新增 Curator 和 Radio Show 类型、搜索 Top Results 和 Suggestions、排行榜 API、音频质量元数据(Spatial Audio / Lossless),以及最重要的——完整的用户音乐资料库读写能力。
核心内容
目录内容增强
(01:12)
MusicKit 新增了两种内容类型:
Curator(策展人):如 Nike、Shazam、Beats by Dr. Dre 等品牌策展人,以及 Apple 编辑团队。每个 Curator 有 name、url、artwork 和 kind(editorial 或 external)属性,还有 playlists 关系可以获取该策展人创建的所有播放列表。
Radio Show(电台节目):如 “New Music Daily by Zane Lowe”,也有 playlists 关系。
Playlist 类型新增了反向关系:curator 和 radioShow,方便从播放列表追溯到创建者。
搜索体验升级
(03:37)
Top Results:在搜索请求中设置 includeTopResults = true,返回一个跨类型的最相关结果列表,按相关性排序。
var searchRequest = MusicCatalogSearchRequest(
term: "Hello",
types: [Artist.self, Album.self, Song.self]
)
searchRequest.includeTopResults = true
let searchResponse = try await searchRequest.response()
print("\(searchResponse.topResults)")
关键点:
topResults包含所有请求类型的结果,混合在一个集合中- 按相关性排序,不关心具体类型
- 适合搜索界面的首屏展示
Suggestions:提供音乐相关的自动补全建议。
let request = MusicCatalogSearchSuggestionsRequest(term: "shaz")
let response = try await request.response()
关键点:
- 每个 suggestion 有
displayTerm(适合展示)和searchTerm(用于实际搜索) - 用户选择 suggestion 后,用
searchTerm执行正式搜索
排行榜 API
(05:41)
let request = MusicCatalogChartsRequest(
kinds: [.dailyGlobalTop, .mostPlayed, .cityTop],
types: [Song.self, Playlist.self]
)
let response = try await request.response()
print("\(response.playlistCharts.first)")
关键点:
- 支持 Top Songs、Top Albums、城市排行榜、每日全球 Top 100
- 可按音乐类型筛选
- 内置分页支持,不需要手动处理
MusicDataRequest
音频质量元数据
(06:58)
MusicKit 暴露了 audioVariants 属性,让你知道一首歌或专辑支持哪些音频格式:
let album = …
let detailedAlbum = try await album.with(.audioVariants)
print("\(detailedAlbum.debugDescription)")
关键点:
audioVariants是AudioVariant数组- 包含
dolbyAtmos(空间音频)、lossless(无损音频)等 - 新增
isAppleDigitalMaster布尔值,标识最高品质数字母带
当前播放的音频质量也可以获取:
@ObservedObject var musicPlayerState = ApplicationMusicPlayer.shared.state
var body: some View {
if musicPlayerState.audioVariant == .dolbyAtmos {
Image("dolby-atmos-badge")
}
}
用户资料库访问
(12:21)
今年最大的更新:应用可以读取用户的个人音乐资料库。
MusicLibraryRequest:从设备本地加载资料库内容,不走网络。
let request = MusicLibraryRequest<Playlist>()
let response = try await request.response()
关键点:
- 通过泛型参数指定请求的类型(Playlist、Album、Song 等)
- 支持链式过滤和排序
includeDownloadedContentOnly = true只返回已下载内容
过滤示例:
var request = MusicLibraryRequest<Album>()
request.filter(matching: \.isCompilation, equalTo: true)
request.filter(matching: \.genres, contains: danceGenre)
request.includeDownloadedContentOnly = true
let response = try await request.response()
MusicLibrarySectionedRequest:按分组获取资料库内容。
var request = MusicLibrarySectionedRequest<Genre, Album>()
request.sortItems(by: \.artistName, ascending: true)
let response = try await request.response()
关键点:
- 第一个泛型参数是分组类型,第二个是内容类型
sortItems对内容排序,sortSections对分组排序- 每个分组通过
items属性访问其下的内容
资料库写入操作
(22:01)
MusicKit 现在支持修改用户的音乐资料库:
// 添加歌曲到播放列表
Task {
try await MusicLibrary.shared.add(selectedTrack, to: playlist)
isShowingPlaylistPicker = false
}
支持的操作包括:
- 添加内容到资料库
- 创建播放列表
- 编辑播放列表的元数据和曲目列表
- 添加歌曲到现有播放列表
详细内容
完整的搜索界面实现
struct MusicSearchView: View {
@State private var searchTerm = ""
@State private var suggestions: [MusicCatalogSearchSuggestion] = []
@State private var topResults: MusicItemCollection<MusicCatalogSearchable> = []
var body: some View {
NavigationStack {
List {
// 搜索建议
if !suggestions.isEmpty {
Section("Suggestions") {
ForEach(suggestions) { suggestion in
Button(suggestion.displayTerm) {
searchTerm = suggestion.searchTerm
performSearch()
}
}
}
}
// Top Results
if !topResults.isEmpty {
Section("Top Results") {
ForEach(topResults) { item in
switch item {
case let song as Song:
SongRow(song: song)
case let album as Album:
AlbumRow(album: album)
case let artist as Artist:
ArtistRow(artist: artist)
default:
EmptyView()
}
}
}
}
}
.searchable(text: $searchTerm)
.onChange(of: searchTerm) { _ in
loadSuggestions()
}
.onSubmit(of: .search) {
performSearch()
}
}
}
func loadSuggestions() async {
let request = MusicCatalogSearchSuggestionsRequest(term: searchTerm)
let response = try? await request.response()
suggestions = response?.suggestions ?? []
}
func performSearch() async {
var request = MusicCatalogSearchRequest(
term: searchTerm,
types: [Song.self, Album.self, Artist.self]
)
request.includeTopResults = true
let response = try? await request.response()
topResults = response?.topResults ?? []
}
}
关键点:
MusicCatalogSearchSuggestionsRequest提供自动补全建议includeTopResults = true获取跨类型的最相关结果topResults是MusicCatalogSearchable类型的集合,需要用类型转换处理
资料库播放列表展示
struct LibraryPlaylistsView: View {
@State private var playlists: MusicItemCollection<Playlist> = []
var body: some View {
List {
Section(header: Text("Library Playlists").fontWeight(.semibold)) {
ForEach(playlists) { playlist in
PlaylistCell(playlist)
}
}
}
.task {
await loadPlaylists()
}
}
@MainActor
private func loadPlaylists() async throws {
let request = MusicLibraryRequest<Playlist>()
let response = try await request.response()
playlists = response.items
}
}
关键点:
MusicLibraryRequest从设备本地加载,不消耗网络流量- 用
@MainActor确保 UI 更新在主线程执行 - 返回的
Album、Song等类型与目录请求返回的结构相同,能力一致
带过滤的资料库查询
func fetchDanceCompilations() async throws -> MusicItemCollection<Album> {
var request = MusicLibraryRequest<Album>()
// 只返回合辑
request.filter(matching: \.isCompilation, equalTo: true)
// 只返回 Dance 类型
let danceGenre = Genre(id: " dance", name: "Dance")
request.filter(matching: \.genres, contains: danceGenre)
// 只返回已下载的
request.includeDownloadedContentOnly = true
let response = try await request.response()
return response.items
}
关键点:
- 过滤条件可以链式组合
- Xcode 自动补全只显示当前类型支持的 key path
includeDownloadedContentOnly支持离线场景
加载扩展属性时指定来源
// 从目录加载专辑的曲目
let catalogTracks = try await album.with(.tracks)
// 从资料库加载同一专辑的曲目
let libraryTracks = try await album.with(.tracks, preferredSource: .library)
关键点:
preferredSource: .library优先从用户资料库加载- 对于只在目录或只在资料库存在的属性,不受
preferredSource影响 - 无论原始项来自目录请求还是资料库请求,都可以使用这个功能
核心启发
1. 给健身 App 加音乐推荐
- 做什么:在锻炼开始前展示用户的个人推荐播放列表和最近播放内容
- 为什么值得做:MusicKit 的
MusicPersonalRecommendationsRequest和MusicRecentlyPlayedRequest自动处理认证,一行代码就能获取个性化内容 - 怎么开始:用
MusicPersonalRecommendationsRequest()获取推荐,用MusicRecentlyPlayedRequest<Song>()获取最近播放的歌曲
2. 给社交 App 加音乐分享
- 做什么:让用户搜索 Apple Music 目录中的歌曲,分享到聊天或动态
- 为什么值得做:
MusicCatalogSearchRequest的includeTopResults让搜索体验接近原生 Apple Music,用户不需要离开你的应用就能找到想分享的歌曲 - 怎么开始:集成搜索建议 + Top Results,用户选择后获取歌曲的
url属性进行分享
3. 给专注/番茄钟 App 加背景音乐
- 做什么:根据用户资料库中的内容创建专注时段的播放列表
- 为什么值得做:
MusicLibraryRequest可以按类型、已下载状态过滤,配合MusicLibrarySectionedRequest按类型分组展示 - 怎么开始:用
MusicLibrarySectionedRequest<Genre, Song>()按音乐类型分组,让用户按心情选择
4. 给派对/活动 App 加协作播放列表
- 做什么:让活动参与者把歌曲添加到共享播放列表
- 为什么值得做:MusicKit 现在支持创建播放列表和添加歌曲,可以实现”大家一起来选歌”的功能
- 怎么开始:用
MusicLibrary.shared.add(track, to: playlist)把选中的歌曲添加到播放列表,用MusicCatalogSearchRequest让参与者搜索歌曲
关联 Session
- Meet Apple Music API — Apple Music REST API 跨平台接入
- Create a more responsive media app — AVFoundation 媒体应用优化
- What’s new in Swift — Swift 语言年度更新
评论
GitHub Issues · utterances