大多数浏览器和
Developer App 均支持流媒体播放。
-
Apple TVOS 上的正在播放和遥控命令
Apple TVOS 上的许多 app 都离不开统一、直观的媒体播放控制,而正确使用和配置 MPNowPlayingInfoCenter 和 MPRemoteCommandCenter 是提供出色用户体验的关键所在。更深入地探索这些框架,并学习如何确保顺畅的体验,不管您使用 Siri、Siri Remote 还是 iOS Remote app 来控制 app。
资源
-
下载
欢迎参加tvOS上的Now Playing 和远程命令演讲 我是tvOS的工程师Justin Voss 在本场演讲中我们将 谈谈如何给观众提供 出色的元数据和播放体验
首先是提供 Now Playing信息 关于内容的正确和完整的元数据 可以帮助观众了解 他们正在观看的内容 通过tvOS和iOS上的各种界面
你的元数据显示在不同的地方 对于视频内容 AVPlayerViewController 沿屏幕顶部显示元数据 对于视频和音频内容 iOS版TV Remote应用 会显示元数据和播放控件 对于音频内容 元数据显示在屏幕的角标中 并且作为全屏 当用户设备闲置时 让我们看一些截图来更好地理解它们 在这里你可以说 我们正在观看 WWDC去年的一场演讲 因为屏幕上的元数据 清晰地表达了这个信息 这是一个使用内嵌 AVPlayerViewController来显示 视频内容的示例
这是同一场演讲 但显示在iOS版的 TV Remote应用中 你还可以看到播放控件 我们稍后再讲 对于音频内容 当信息发生变更时 听众会在屏幕上看到一则通知 其中包含更新了的元数据 在这里你可以看到 如果我们正在听那场演讲的音频版 会是什么样子 如果用户放下遥控器 tvOS将自动 以全屏视图播放元数据 那会凸显整个艺术图像 我希望我说服了你们 提供全部信息 是值得你们花那么多时间的 让我们看看有几种实现方式 你有几种选择 那么它取决于你在应用中所使用的技术
使用TVML的可以通过 MediaItem JavaScript对象添加元数据 它针对Now Playing 信息有一些属性 包括标题、副标题和描述 你可以提供艺术图片的URL 和关于内容评级的信息 比如PG-13或R 无论内容是否明确
在这个代码示例中 你可以看到我 正在创建一个MediaItem对象 包含一个视频的URL 并且在这个对象上配置标题和描述 并提供了一个艺术图像的URL 如果你使用AVKit来播放你的内容 你应该使用AV元数据项类 来提供Now Playing信息 对于你想要提供的每一项元数据 比如标题或艺术图像等等 你可以创建一个AV可变元数据项 并给它配置一些属性 你要提供一个标识符 告诉AVKit这代表哪些元数据 所以我们可以区分对象代表的是标题 还是描述 你要提供元数据的值 可以是字符串或原始数据字节 你应该设置extendedLanguageTag 来指定元数据用于哪种语言 除非你有理由 否则我们强烈建议你使用“und”值 它代表未定义 只有当用户的区域设置 与元数据的区域设置相匹配时 属性才能可见 那么比如说 如果你有一部美国拍的电影 你提供它的标题时可能尝试 将语言标签设置为英语 因为它本来就是英语的 但如果你那么做了 德国的观众就看不到任何标题 因为元数据语言与他们的语言不匹配 但如果你使用了标签und 则每个人都能看到元数据 无论语言设置是什么
有时你需要给我们一点暗示 关于如何阐述你所提供的值 如果你提供了一个艺术图片 你就给我们提供图片的原生字节作为值 然后使用dataType来告诉我们 它是JPEG或PNG格式
请参看代码示例来了解具体信息
你看一下代码 我创建了一个 AV playerItem 并赋予了它一个标题和描述 在第一个代码块中 我创建了一个 AVMutableMetadataItem 来代表标题
首先我把标识符设为 AVMetadataCommon IdentifierTitle 那样AVKit就知道这个项是标题
然后我把真实值设为一个字符串 AV元数据项API要求值 为NS对象类型 所以要把切换字符串 转换为NSString
最后我把extendedLanguageTag 设为und 因为演讲的标题应该是全世界都一样
在第二个代码块中 我做了同样的工作 来分配描述 除了提供一个不同的值以外 你可以在这行看到 我把标识符设为AVMetadata CommonIdentifierDescription 所以AVKit就知道如何诠释这个项
在最后一行 我把元数据项的一个数组分配 给AV playerItem的 附加元数据属性
如果你想把发布日期 作为元数据项提供 你可以把发布日期的格式 调整为指定格式的字符串 代码示例显示了如何实现
在这里 我创建了日期 对象为任意日期 我创建了一个日期格式器 并提供了指定日期格式的字符串 就是这行
要创建元数据项 我使用了标识符AVMetadata CommonIdentifierCreationDate 然后我使用了日期格式器 来把日期对象转换为格式化的字符串 并把字符串转为NSString 在AVPlayerViewController中 观众可以看到视频的发布年份 随着其他Now Playing信息
这是一个如何给内容 提供图片元数据的示例 你可以看到我要做的第一件事就是 获取作为数据对象的图片 我通过从我的应用捆绑包中的 JPEG中加载图像实现 但你可以从任意源中获取
要创建元数据项 首先我需要指定我的标识符 在本例中应该是 AVMetadataCommonIdentifierArtwork
接下来我要提供艺术图像数据自身 并将Swift数据对象 转换为NSData
要表明是哪种格式的图像 我需要设置dataType属性 因为我知道这张图像是一个JPEG 我就提供了一个常数值来表明
为了给你提供一个可视化参考 关于项会显示在屏幕上哪个位置 请看AVPlayerViewController的截图 还配有一些注释 颜色编码显示每个元数据标识符 显示在哪儿 艺术图像显示在这里
然后有标题、创建日期和描述
这是TV Remote应用的截图 你可以看到Remote应用 显示的元数据 与AVPlayerViewController不一样 它显示了同样的艺术图像和标题
但没有显示描述 而是显示了艺术家和专辑名称
你可以看到要使用的AV基础标识符
好的 这就是AVKit的相关信息 如果你使用其它技术来显示视频 比如Video Toolbox 或仅播放音频内容 你需要另一种方式来提供信息 在那些情况下 你可以使用 MPNowPlayingInfoCenter 它是一个单例对象 有一个字典属性 你可以写入你自己的元数据 有一个标题键、专辑名称键、 艺术图像键… 除了你所期待的元数据之外 你还可以明确指定内容是视频还是音频 你可以提供关于持续时长 和用户的播放位置的信息
你的设定将不会作为原始字节提供 而是作为MPMediaItemArtwork对象 我们稍后再谈这个
你有责任更新这个字典 如果播放状态发生改变 你不需要每秒或每分钟都更新它 而是应该当发生某些事件时更新它 我们建议你当播放项改变时更新它 如果关于播放项的元数据发生改变 比如标题或艺术家姓名 如果用户试图寻找一个新位置 或如果播放速率发生改变 最后如果播放开始或停止
让我们看一些代码
在第一个代码块中 我创建了代表我的艺术图像的对象 这个MPMediaItemArtwork类 在代码块中提供了图像尺寸 我们稍后会调用指定图像尺寸 这个MPMediaItemArtwork类 在代码块中提供了图像尺寸 我们稍后会调用指定图像尺寸 这个代码块返回一个UIImage对象 非常符合这个尺寸 然后传递给代码块 你的应用可能已经下载了 同一个图像的不同尺寸 比如说小图像、中图像和大图像 当我们调用这个代码块时 获取我们所提供的尺寸 并返回最符合所要求尺寸的图像 我们不鼓励你们执行 消耗很大的图像尺寸调整操作 只需要返回你所拥有的图像即可
在第二个代码块中 我给MPNowPlayingInfoCenter 提供了我的全部元数据 这只是一个常见的Swift词典 拥有由框架提供的键 并且我提供我的值为 常规Swift类型 有两个属性我想特别提一下 分别是ElapsedPlaybackTime 和PlaybackDuration 你应该提供这两个键 因此tvOS知道内容有多长 以及用户当前在哪儿 随着各种事件的发生 要更新ElapsedPlaybackTime 以匹配用户所在位置 在tvOS上 这个API没有 AVPlayerViewController 但我可以给你展示元数据 在TV Remote应用中 看起来是什么样子 你可以在屏幕上看到每一个属性 相较于AVKit版它们看起来很熟悉 请注意在这个版本中 你可以控制拖动条 你的应用要提供ElapsedPlaybackTime 和持续时长 从而保证其显示正确
让我们换个话题 谈谈你的应用如何处理外部播放命令 应用有自己的控件 用户可以在播放时与其交互 但用户可能想控制你的应用 从iOS上的 TV Remote应用中 或者如果他们正在听tvOS上的应用 中的背景音频 可能会按下Siri遥控上的播放暂停 按钮暂停应用 当它处于后台时 要支持这些交互 一定要确保你的应用可以处理远程命令
你可以通过一个叫作 MPRemoteCommandCenter的API实现 你可以通过一个叫作 MPRemoteCommandCenter的API实现 它是一个单例对象 你应用可以支持的 每个命令都有一个属性
对于你想要支持的每个命令 你可以注册一对 目标行动或回调代码块 当执行命令时调用 如果你提供了目标行动或代码块 那么应该支持命令 如果你想提供一个命令处理器 但需要表示它不可用 你可以把它标记为禁用
那个方法或代码块 必须返回一个enum值 以表明你的应用是否成功执行了命令 这里所说的成功的定义是广义定义 如果用户播放在播放列表中的 最后一首曲子 并请求跳过下一首曲子 你的应用可以选择结束播放 这就被认为是成功处理了命令 所以你应该返回成功值
有些命令比如播放和暂停非常简单 如果暂停命令处理器被调用 你的应用应该如何做是很明确的 其它命令更灵活 接受来自你应用的参数 并可以给你的处理器返回一个参数 比如MPSkipIntervalCommand用于 允许用户向前进或向后退几秒钟 应用可以有 允许用户跳过多少秒的偏好设置 跳过命令对象可以让你配置偏好 当用户执行这个命令时 将会调用带有对象参数的处理器 对象是类型 MPSkipIntervalCommandEvent 并且有一个间隔属性 告诉应用 跳过多少秒 这可以与之前提供的跳过偏好不一样
请看一个例子 请看应用如何实施命令
你可以看到在第一行我希望 用户向后跳的间隔是10秒 所以我在SkipBackwardCommand 对象上 分配了偏好间隔属性
然后我要提供我的处理器代码块 从技术角度来说 每个命令处理器都将 通用类型MPRemoteCommandEvent 作为参数接收 但我需要把它转换为 MPSkipIntervalCommandEvent 以便获取它的间隔属性
然后我会执行命令 在这里我正在通过一个 AVPlayer播放我的内容 因为AVPlayer使用 CMTime结构表达时间 这也是我需要计算 我的播放位置的方式 你可以看到我获取了 播放器的当前位置 然后创建了一个新CMTime结构 带有跳过间隔 我从当前时间中减去了间隔
我要求播放器寻找那个时间点 并从处理器中返回成功
当播放器完成寻找那个时间点 将调用我的结束处理器 那是我要更新 Now Playing信息的地方 如果我们修改播放状态 比如寻找新时间点 我们需要发布新信息以更新已播放时间 我调用了一个叫作 updateNowPlaying的函数 我会在下一张幻灯片中给你展示
你可以看到我是如何更新 Now Playing信息的 与演讲最开始所展示的例子 一模一样 但我希望指出一个细节 你可以看到我使用了 AVPlayer的当前时间属性 来给已经过去的已播放时间属性 提供一个精确的值 在这种情况下 因为AVPlayer要返回一个CMTime 但MPNowPlayingInfoCenter 要求的是一个浮点型的值 这是已播放的秒数 我需要使用CMTimeGetSeconds函数 来转换值 这就是关于用远程命令 和Now Playing信息 为用户提供出色体验的全部内容 你可以访问这里显示的这个URL 查看相关文档和相关演讲
谢谢观看 -
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。