大多数浏览器和
Developer App 均支持流媒体播放。
-
借助 MusicKit 探索更多内容
了解如何利用 MusicKit 对您的 App 进行优化和个性化。我们将向您介绍 MusicKit 框架的最新新增功能,探索如何通过请求、元数据等将音乐内容整合到您的 App。
资源
相关视频
WWDC22
WWDC21
-
下载
♪ ♪
David Ho: 大家好 欢迎来到 WWDC 我是 David 今天我想向您介绍的是 如何用 MusicKit 探索更多内容 MusicKit 框架于 2021 年推出 提供了一组 API 用于在 Swift 中 访问和播放本机音乐 此框架使您的 App 能够 轻松地与 Apple Music 整合 并提供对整个 Apple Music 目录的访问 今天 我要介绍的是 我们对 MusicKit 所做的 一些主要改进 我将从一些附加内容开始 通过新的音乐项目类型 新的请求和新的元数据 从 Apple Music 目录中获得更多信息
之后 我将讨论如何获取个性化内容 以便为每个用户提供定制的体验 接下来 我将介绍 Apple Music 目录以外的内容 今年 通过加入用户曲库中的音乐 您可以将 App 提升到 一个全新的水平 最后 我将讨论如何主动与曲库交互 例如向曲库或播放列表中添加项目 以及创建和编辑播放列表 让我们深入研究添加的目录内容 最初发布的 MusicKit 引入了一个新的音乐模型层 包括歌曲 专辑 和播放列表等核心类型 今年 我们增加了两种新类型 让 MusicKit 更容易发现新音乐 Curator 和 Radio Show
除此之外 MusicKit 现在还可以让您 构建出色的 UI 来搜索目录 访问排行榜以获取 最受欢迎的歌曲 专辑等 并获取新的属性 例如更高质量的音频元数据 如支持 Dolby Atmos 的 Spatial Audio 让我们从 curator 和广播节目开始 这是发现音乐的 极好资源 在这里 我们来看一个 Curator 的例子 Nike 其他 curator 的例子还有 Shazam 和 Dr. Dre 的 Beats 在这里 我们可以很容易找到 这位 curator 生成的所有播放列表 此功能允许人们快速访问 他们喜欢的播放列表 查找新歌或重新访问旧的个人收藏 现在 让我们深入了解 更多的技术细节 Curators 拥有多种属性 这个新的 Curator 类型的 一些主要属性包括名称 URL 插图和种类 种类属性是一个 enum 可以是“编辑”或“外部” 指示给定的 curator 是 Apple curator 还是第三方 curator curator 也有一个播放列表关系 展示 curator 制作的播放列表 真正服务于我们刚才看到的 音乐发现概念
接下来 我们来看看广播节目类型 像 Zane Lowe 的 New Music Daily 和 Brooke Reese 的 Pop Hits Radio 这样的广播节目 是通过经验丰富的专业人士 发现新音乐的另一种方式 与 Curator 类型非常相似 广播节目也有播放列表关系 以查找广播节目的音乐功能 正如这两种新类型 与播放列表的关系一样 我们也公开了 Playlist 类型上的 两种新关系 即反向逻辑的“Curator” 和“RadioShow” 给定一个播放列表 我们可以很容易地获得 生成所述播放列表的实体的结构
MusicKit 允许在目录中 搜索多种类型的内容 我们添加了对新项目类型的支持 比如 curator 和广播节目 列表还在继续增长 因此 构建良好的 UI 变得越来越具有挑战性 所以今年我们通过最匹配结果和建议 让您的搜索变得更容易 让我们来看看这些增强 给 UI 带来的效用 当键入搜索内容时 您可能会得到强大的 与音乐相关的 以及自动完成的相关支持 这就是建议发挥作用的地方 提供人们可能试图达到的条件 您甚至可以更进一步显示最匹配结果 以便快速访问人们正在搜索的内容 为了获得最好的结果 您可能并不关心项目的类型 而是想要专注于相关性 这就是最匹配结果的力量 现在 让我们从 Top Results 开始 看一下实施起来会是什么样子 这里是我们创建 目录搜索请求的现有方法 需要一个搜索词 和您想要表示的项目类型 响应包括按请求的类型分类的集合 这意味着有多个 特定于类型的结果列表 尽管这很好 但我们还是想公开一个 与类型无关的最相关的结果列表 请求这些信息就像 添加一行代码一样简单 这里 我们将请求的 includeTopResults 属性设置为 true 并在响应中填充一个新属性 这个新属性被命名为 topResults 它包含任何请求类型的项目 下面是 print statement 的输出 我们可以看到 返回的最匹配结果 是一个合集中的 歌曲 艺术家和专辑的混合 并根据相关性排序 现在 我将向您展示 如何用 Suggestions 帮助人们更快地到达 他们的搜索目的地 只需创建一个带有字符串项的 建议请求 调用响应后 您将得到建议响应 响应中包含了一系列 Suggestions 每个建议都包括一个 适合您的 UI 的显示词 以及一个搜索词 当人们选择一个建议时 您可以通过使用搜索词 执行搜索请求来获取相应的结果
目录排行榜是了解 最新最流行歌曲的好方法 MusicKit 提供各种类型的图表 来查看流行趋势 所提供的图表类型是排行榜 例如热门歌曲或热门专辑 它们对应于最常播放的音乐 城市排行榜和每日前 100 名 您还可以指定所请求的排行榜 按特定的类型进行筛选 通过代码检索这些排行榜非常简单 目录排行榜请求遵循目录搜索请求中 已经使用的既定模式 首先 初始化排行榜请求 然后 您可以指定 您喜欢的排行榜类型 默认情况下 这将获取播放次数最多的内容 但也可以获得 每日全球排行榜和城市排行榜 最后 您只需指定 您希望排行榜包含的类型 就是这样了 当我们访问响应中的第一个 播放列表排行榜时 我们会得到 MusicCatalogChart 它代表每天的全球排行榜 其播放列表包括 “TOP 100:Global” 和 “Top 100: USA” 如果您过去一直用 MusicDataRequest 获取目录排行榜 那么现在您不需要这样做了 因为 MusicKit 将为您完成这项工作 它在项目集合中内置了分页支持 在 2021 年 我们推出了具有真正多维声音 和清晰度的突破性音频体验 支持 Dolby Atmos 的 Spatial Audio 这种身临其境的体验 已经可用于数千首歌曲 现在您可以访问这些数据 MusicKit 通过 Audio Variants 公开歌曲或专辑的可用音频资源 因此现在 您可以将此信息转发给其他人 Audio Variants 的示例包括 前面提到的 支持 Dolby Atmos 和 Lossless Audio的 Spatial Audio 等
除了 Audio Variants 之外 我们还 公开了一个新的 boolean 属性 即 Apple Digital Master 它是受支持的最高质量的 master 由于这些元数据是在项目级别公开的 Audio Variants 非常适合细节视图 允许您实现这样的 UI 我们这里有一张专辑的详细视图 在这里 我们可以看到 基于前面提到的 Audio Variants 属性的相应徽章 让用户知道他们将获得 怎样的音频质量 在这种情况下 空间⾳频和无损音频 可用于该特定专辑 现在让我们看看 如何编写代码来实现这一点 加载 Audio Variants 就像加载任何其他扩展属性一样 使用加载 audioVariants 扩展属性的方法 获取现有的专辑或歌曲 在本例中是专辑 现在 detailedAlbum 已经填充了 audioVariants 属性 这里我们可以看到 Audio Variants 属性 它是一个数组 其元素是 AudioVariant 使用这些值 您可以在 UI 中指定 该特定元素的 可用音频资源 就像我们前面看到的那样 现在 效果很好 但您可能不仅仅希望 在顶层或细节视图上 显示这些音频徽章 这就是为什么我们还要更进一步 为音乐播放器提供动态音频版本 访问活动的 audioVariant 允许对 当前播放项的音频质量 进行可视化指示 例如此视图中的 Dolby Atmos MusicKit 播放器 API 会根据用户设置 和网络条件自动选择正确的音频质量 要从播放器访问活动特征 首先 我们访问观察对象中 ApplicationMusicPlayer 的播放状态 然后 我们可以直接从播放状态 访问活动的 audioVariant 现在 我们只需检查 audioVariant 属性 看看它是否是 dolbyAtmos 如果是 则添加额外的 UI 因为播放状态是观察到的对象 所以只要当前播放的项目发生更改 此视图就会自动更新 从而确保您的视图始终是最新的 现在我们已经了解了一些目录添加 让我们深入了解个性化内容 个性化内容是特定于订阅者的数据 为 App 中的每个用户 提供独特的定制体验 通常 个性化内容需要 特殊的身份验证 和用户令牌 但在 MusicKit 框架中 我们已将其全部自动化 因此您无需处理任何麻烦 我们为开发人员提供的个性化内容是 访问最近播放的项目 和个人推荐 最近播放的内容 是个人音乐消费体验的宝贵数据 它可以使您快速方便地访问 他们喜欢的音乐项目 当听新音乐时 它允许人们回头 去查阅他们的听歌历史 要获取最近播放的容器 如专辑 播放列表 和电台 您可以创建 最近播放的容器请求 请注意 如果您要播放 播放列表或专辑中的歌曲 就需要检索容器类型 在响应中 您会发现最近播放的音乐项目 您可以轻松地访问标题 副标题和插图 您还可以获取最近播放的 更具体类型的项目 如歌曲或电台 这里 我们创建一个最近播放的请求 通过由尖括号指示的 泛型参数指定歌曲类型 我们的响应现在只包含 我们播放的歌曲 现在 谈谈个人推荐 个人推荐可以让您的 App 体验 更加亲密和吸引人 因为它们是基于用户的曲库 和听歌历史产生的 推荐会按照主题整齐排列 按照流派 艺术家 收藏 如“为您而做”等进行分组 要获取个人推荐 只需创建个人推荐请求即可 响应是一系列推荐 当我们记录第一个推荐时 我们可以看到这个特定的元素 代表“为您而做”的推荐 推荐包含 ID 标题和 nextRefreshDate nextRefreshDate 表示刷新此推荐 以获得最新建议的日期和时间 播放列表属性包含 “为我而做”的所有播放列表 让我们看看另一个推荐的例子 在这里 我们将打印 推荐响应的第二个元素 我听了一大堆另类音乐 这个推荐包含了 不同类型的混合 在这个例子中为专辑和播放列表 它们被分组在一个单独的项目集合中 这些项目是按照相关性排序的 类似于目录搜索的最匹配结果 现在 让我们更进一步谈谈如何通过 将用户曲库中的内容整合到 App 中 来创造更多与音乐相关的体验 今年 MusicKit 允许 App 通过两种请求 从曲库中提取项目 曲库请求 和曲库分段请求 搜索用户曲库中的内容 并专门从曲库中 加载扩展属性和关系 在我们看到技术细节之前 让我们看看如何使用曲库内容 来增强 App 我一直在开发一款名为 Music Marathon 的健身 App 它将跟踪您的户外跑步情况 通过在项目中加入 MusicKit 人们可以直接通过该 App 播放音乐 而无需在 Apple Music App 和这个 App 之间切换 我们开始一次新的训练 寻找音乐内容
我们在这里看到一些 从个人推荐请求中 检索到的推荐播放列表 以便人们快速访问我们认为 他们会喜欢的播放列表 转到“曲库”选项卡 我们可以看到它是一个空视图 如果能看到我所有的 个人播放列表就太好了 所以让我们来写这个特性吧 我已经设置了一些 UI 来处理 这个视图的基本内容 现在我想从曲库中加载播放列表 首先 我会向曲库申请
在泛型参数中指定播放列表 以表明我们需要用户曲库中的 播放列表
我把它存储在一个局部变量里 将其命名为“请求”
接下来 我将接受这个请求 并调用响应函数
此方法为异步抛出方法 让我们添加尝试和等待的关键字 并再次将其存储在响应变量中
然后 我将更新状态对象 以接收此响应
现在要做的就是更新列表 这样我们就可以在 UI 中 看到播放列表了 我将使用 ForEach 迭代响应中的项
并检索 MusicItemCollection 中的 每个播放列表
现在我们已经有了播放列表 我将把它们传递到 我已经制作的 PlaylistCell 中
现在如果我们重新运行
然后导航回到 App 我们可以在曲库里看到 我所有的个人播放列表 现在 我可以选择听个人推荐 Apple Music 目录中的内容 以及我自己的个人曲库 现在我们已经了解了 访问曲库内容有多么容易 让我们看看曲库请求还能做些什么 音乐曲库请求是一个强大的 API 可以从用户的曲库中获取项目 在 iOS 上 与其他从音乐目录中 获取内容的请求不同 MusicLibraryRequest 实际上 不会从网络加载数据 相反 它将从存储在设备上的 用户曲库副本中加载项目 这个请求的基本内容只要求您指定 想要的音乐项目类型 此项目类型通过 MusicLibraryRequest 的 泛型参数传递 您可以对请求应用各种 过滤器和排序选项 以便对调用进行微调 使其与您的需求相匹配 此请求还能够获取已经下载的内容 支持完全脱机体验 让我们从简单的基本请求开始 就像我们在 Music Marathon App 中写的那样 但这次我们请求的是曲库中的专辑 专辑类型通过泛型参数来指定 要执行请求 请调用响应函数 看看输出 我们有一个 MusicLibraryResponse 其中的项目是用户音乐曲库中 找到的所有专辑的 MusicItemCollection 在这里 我们注意到 这些专辑与您从我们的 各种目录请求中得到的专辑结构相同 并且具有相同的功能 而在本例中 我们将获取曲库中的每个专辑 我们知道在某些情况下 您只需要专辑的一个特定子集 这就是为什么 MusicLibraryRequest 还可以让您更具体地 说明要从曲库中提取哪些项目 我们以之前写的同样的请求为例 并添加一个过滤器 这里 我们希望加载 isCompilation 属性为 true 的 所有专辑 当您调用过滤器方法时 Xcode 的自动完成功能 只会为您请求的项目类型 提供特定的关键路径 现在 响应中只有编译过的专辑 但这并不是 MusicLibraryRequest 所能提供的全部功能 您可以链接多个过滤器 为您提供更精确的请求 如果我们想要 某一特定流派的所有汇编呢 我们可以向请求添加另一个过滤器 例如 这里有一个名为 “Dance”的流派实例 您可以根据流派的关系进行过滤 以将结果限制为仅显示 包含此特定流派的编辑 现在我们的响应只包含舞蹈汇编 如果只包括已经下载的舞蹈汇编如何 为此 只需将请求中的 includeOnlyDownloadedContent 设置为 true 就是这样了 响应是相同的 MusicLibraryResponse 但项目现在只包含下载的元素 正如您所看到的 音乐曲库请求功能非常强大 并解锁了定制 MusicDataRequest 无法实现的新功能 但 MusicKit 提供了更多 从用户曲库中获取数据的选项 来看看 Library Sectioned Request 分段请求能够获取按段分组的项目 因此 分段请求接受 两个不同的泛型参数 第一个表示段类型 第二个表示项类型 曲库分段请求支持 与常规曲库请求相同的功能 例如您可以应用于段或项的 各种过滤和排序方法 以下是如何使用曲库分段请求 来获取所有按其流派分段的专辑 分段响应包含一个名为 “段”的属性 其中每个元素 对应于请求的第一个泛型参数 在本例中为 Genre 每个流派不仅公开了自己的属性 而且还包含一个 专辑集合 可通过项属性访问 这些项目对应于第二个泛型参数 在这里突出显示 专辑的类型是 Alternative 正如前面提到的 过滤和排序功能 也可以用于这个分段请求 假设我们想要相同的专辑 按流派进行分类 但这些专辑是按艺术家的名字排序的 我们添加一个排序过滤器 通过在专辑上指定 artistName keyPath 并说明 我们希望这些是升序的 对响应进行排序 请注意 该方法是排序项 因为我们指定了 要应用于项目而不是段的排序 如果我们想要指定段 可以使用一组 filterSections 和 sortSection 方法 让我们来看看新的响应结果
我们现在可以看到我们的专辑 是按艺术家名字的字母顺序排列的 而不是按标题 曲库请求和曲库分段请求都非常强大 但是您可能还想通过 添加用户曲库中的 搜索结果来补充您的音乐搜索 UI 我们添加了一个新的结构化请求 它的操作与目录搜索几乎相同 但它不是从目录中加载结果 而是在用户的曲库中找到相关的项目 与对应的目录一样 曲库搜索请求 只需要一个搜索词和一个类型数组 现在我们已经了解了 从用户曲库中检索项目的不同方法 那么加载扩展属性和关系怎么样 您可能知道 MusicKit 的初始版本 引入了 with 方法 以一种简单的方式从 Apple Music API 加载这些属性 今年 我们增加了 Current with 方法 还引入了一个首选源参数 对于 Apple Music 目录 和用户曲库中均可用的 扩展属性和关系 此首选源指示从何处 加载数据 对于只存在于目录或曲库中的属性 无论首选源是什么 它们都将被提取 以确保不会忽略任何内容 此外 无论初始项目来自何处 无论是目录请求 曲库请求 还是其他地方 都可以使用此功能 它都很管用
这里我们了解了已知的 接收音乐项关系的方法 我们正在加载一张专辑的曲目 当我们显示输出时 可以看到该专辑的所有曲目 但是 通过新添加的 preferredSource 属性 我们可以指定希望从曲库中 获取这种关系 现在 我们的输出只包含 在曲库中找到的专辑的曲目 现在 您可以通过各种方式 从用户的曲库中获取项目 但只有允许用户通过 MusicKit 直接与曲库交互才有意义 让我们回到我的示例 App Music Marathon 看看这个曲库提供的一些功能 在我训练的时候 我想浏览一下 我的个人推荐
当我浏览这些曲目时 发现这些歌曲中 有一首非常适合我的训练播放列表 如果按住其中一个单元格 就会弹出一个快捷菜单 允许我将这首歌添加到播放列表中 当我们按下它时 我所有的播放列表再次弹出 我们来编写代码 将选定的曲目 添加到我选择的播放列表中 我已经将所选项目通过管道 传输到 AddToPlaylistCell 单元 所以我们所要做的就是 通过共享实例访问 MusicLibrary
我们将调用“add”方法 指定我们选择的曲目 和要添加到哪个播放列表
这个方法也是一个异步抛出函数 所以我们再次添加 尝试和等待的关键字
最后 我们通过将 isShowingPlaylistPicker 绑定变量 设置为 false 来关闭选取器
现在 如果我们重新运行 并向播放列表中添加一首曲目 并选择其中一个播放列表 我们应该会看到添加了此项目 导航回 App 中的曲库选项卡 我们可以看到歌曲现在已添加到 我们的训练播放列表中 向播放列表中添加项目就是这么简单 让我们看看这个曲库提供的 其他一些功能 与曲库交互的各种其他方式包括 向曲库添加内容 创建播放列表 以及编辑播放列表的元数据 和曲目列表 向用户的音乐库添加内容 可以让人们在 Apple Music App 的 曲库选项卡中找到 特定的歌曲或专辑 以及在设置中打开 Sync Library 时 在所有设备之间进行同步 在您的 App 中直接 提供此功能可以避免人们 在 Apple Music App 和您的 App 之间切换 这样他们就可以 继续关注您提供的内容 此外 通过将添加 和新引入的曲库请求集成在一起 您的 App 可以立即 从这些结果中受益 让用户轻松访问他们喜欢的内容 即使有了这种强大的服务 您可能还是想创造特殊的音乐体验 因此今年 我们将播放列表的 创建和编辑引入 MusicKit 现在 您可以代表用户创建播放列表 我们还可以将歌曲 甚至整个专辑等项目 添加到用户曲库中的 任何符合条件的播放列表中 创建播放列表非常适合 将人们喜欢的内容分组 或者根据情绪设置 App 通过向现有的播放列表添加内容 您可以使用 MusicKit 提供的 各种音乐发现工具 来直接影响用户 您现在还可以编辑已创建的播放列表 可以编辑曲目列表和元数据 以确保 一切都符合您的需要 这些就是您可以在 App 中 与用户曲库交互的方式 总而言之 MusicKit 今年 进行了一些重大升级 轻松将我们针对新类型属性的 目录增强功能 和搜索增强功能整合到现有 App 中 以获得更好的体验
集成曲库内容和功能 以解锁全新的功能 并让用户控制自己的体验
使用 MusicKit 可以增强 多种不同类型的 App 健身 App 游戏 社交媒体 App 地图 App 等 都可以从播放或分享音乐中受益 欲了解更多信息 请查看更多相关讲座 深入研究 Swift 了解该语言的新增功能 以充分利用 MusicKit 和其他 Apple 框架 查看2021年的 MusicKit 讲座 学习如何设置 App 来使用框架 启动回放 并提供订阅优惠 如果您有兴趣在 Android 或 web 上 与 Apple Music 集成 我们还有一个讲座 讨论了如何直接使用 Apple Music API
希望您喜欢我们的讲座 并通过我们的开发者论坛 保持更新和参与 感谢观看 请享受您的 WWDC 2022 之旅吧
-
-
4:20 - Existing catalog search request
// Loading catalog search top results var searchRequest = MusicCatalogSearchRequest( term: "Hello", types: [ Artist.self, Album.self, Song.self ] ) let searchResponse = try await searchRequest.response() print("\(searchResponse)")
-
4:44 - Loading catalog search top results
// Loading catalog search top results var searchRequest = MusicCatalogSearchRequest( term: "Hello", types: [ Artist.self, Album.self, Song.self ] ) searchRequest.includeTopResults = true let searchResponse = try await searchRequest.response() print("\(searchResponse.topResults)")
-
5:09 - Loading search suggestions
// Loading suggestions let request = MusicCatalogSearchSuggestionsRequest(term: "shaz") let response = try await request.response() print("\(response)")
-
6:30 - Loading catalog top charts
// Loading catalog top charts. let request = MusicCatalogChartsRequest( kinds: [.dailyGlobalTop, .mostPlayed, .cityTop], types: [Song.self, Playlist.self] ) let response = try await request.response() print("\(response.playlistCharts.first)")
-
8:10 - Loading audio variants
// Loading audio variants let album = … let detailedAlbum = try await album.with(.audioVariants) print("\(detailedAlbum.debugDescription)")
-
9:09 - Showing currently playing audio variants
// Showing currently playing audio variants @ObservedObject var musicPlayerQueue = ApplicationMusicPlayer.shared.queue @ObservedObject var musicPlayerState = ApplicationMusicPlayer.shared.state var body: some View { if let currentEntry = musicPlayerQueue.currentEntry { VStack { MyPlayerEntryView(currentEntry) if musicPlayerState.audioVariant == .dolbyAtmos { Image("dolby-atmos-badge") } } } }
-
10:28 - Loading recently played containers
// Loading recently played containers let request = MusicRecentlyPlayedContainerRequest() let response = try await request.response() print("\(response)")
-
10:41 - Loading recently played songs
// Loading recently played songs let request = MusicRecentlyPlayedRequest<Song>() let response = try await request.response() print("\(response)")
-
11:21 - Loading personal recommendations and printing first recommendation
// Loading personal recommendations let request = MusicPersonalRecommendationsRequest() let response = try await request.response() print("\(response.recommendations.first)")
-
11:51 - Loading personal recommendations and printing second recommendation
// Loading personal recommendations let request = MusicPersonalRecommendationsRequest() let response = try await request.response() print("\(response.recommendations[1])")
-
13:36 - Loading library playlists
@MainActor private func loadLibraryPlaylists() async throws { let request = MusicLibraryRequest<Playlist>() let response = try await request.response() self.response = response }
-
14:23 - Displaying library playlists
List { Section(header: Text("Library Playlists").fontWeight(.semibold)) { ForEach(response.items) { playlist in PlaylistCell(playlist) } } }
-
15:47 - Fetching all albums in the library
// Fetching all albums in the library let request = MusicLibraryRequest<Album>() let response = try await request.response() print("\(response)")
-
16:38 - Fetching all compilations in the library
// Fetching all compilations in the library var request = MusicLibraryRequest<Album>() request.filter(matching: \.isCompilation, equalTo: true) let response = try await request.response() print("\(response)")
-
17:08 - Fetching all dance compilations in the library
// Fetching all dance compilations in the library var request = MusicLibraryRequest<Album>() request.filter(matching: \.isCompilation, equalTo: true) request.filter(matching: \.genres, contains: danceGenre) let response = try await request.response() print("\(response)")
-
17:29 - Fetching all downloaded dance compilations in the library
// Fetching all downloaded dance compilations in the library 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() print("\(response)")
-
18:29 - Fetching all albums sectioned by genre
// Fetching all albums sectioned by genre var request = MusicLibrarySectionedRequest<Genre, Album>() let response = try await request.response() print("\(response)")
-
19:04 - Fetching all albums sectioned by genre sorted by artist name
// Fetching all albums sectioned by genre sorted by artist name var request = MusicLibrarySectionedRequest<Genre, Album>() request.sortItems(by: \.artistName, ascending: true) let response = try await request.response() print("\(response)")
-
20:58 - Fetching relationships using the with method without a preferred source
// Fetching relationships using the with method let album = … let detailedAlbum = try await album.with(.tracks) print("\(album.tracks)")
-
21:11 - Fetching relationships using the with method and a preferred source
// Fetching relationships using the with method let album = … let detailedAlbum = try await album.with(.tracks, preferredSource: .library) print("\(album.tracks)")
-
22:09 - Adding a track to a playlist
Task { try await MusicLibrary.shared(add: selectedTrack, to: playlist) isShowingPlaylistPicker = false }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。