用 Group Activities 协调媒体体验
Coordinate media experiences with Group Activities
2021年6月8日
一句话判断
Group Activities 框架是 SharePlay 的底层引擎——它让多个用户通过 FaceTime 同步播放媒体内容,你的 App 负责提供内容,系统负责同步和通信。
这场 Session 讲了什么
Session 详细介绍了 Group Activities 框架的技术实现,这是 iOS 15 中 SharePlay 功能的开发者接口。SharePlay 允许用户在 FaceTime 通话中一起看视频、听音乐、或共享屏幕。Group Activities 是支撑这个功能的消息同步层。
架构上,Group Activities 通过 Group Session 维护参与者状态,通过 $.playbackState 等同步属性协调所有参与者的播放位置和状态。当一个参与者暂停视频,所有其他参与者的视频也会暂停。当主持人跳转到某个时间点,所有人的播放位置都会同步跳转。
Session 覆盖了三种场景:自定义媒体同步(视频和音频)、通用数据同步(白板、游戏等),以及如何处理参与者的加入和离开。还讨论了延迟补偿策略——不同参与者的网络延迟不同,框架会自动调整缓冲来保证体验同步。
值得深挖的点
延迟补偿与播放同步
多个参与者通过 FaceTime 连接,每个人的网络延迟不同。如果只是简单地广播”在 3:45 播放”,网络慢的人会晚几秒开始看。Group Activities 使用了延迟补偿算法——它会估算所有参与者的最大延迟,让所有人等待这个延迟后再开始播放。这保证了真正的同时观看体验,代价是所有人都有一定的初始延迟。
Group Session 的生命周期
Group Session 有明确的生命周期:创建 -> 等待参与者 -> 活跃 -> 结束。参与者可以在任何阶段加入或离开。你的 App 需要监听 .$participants 的变化来更新 UI(比如显示当前参与者列表)。当 FaceTime 通话结束时,Group Session 自动进入结束状态,你的 App 应该保存当前状态并恢复正常播放模式。
代码片段
创建和加入 Group Session
import GroupActivities
// 定义一个媒体 Group Activity
struct MovieWatchingActivity: GroupActivity {
var metadata: GroupActivityMetadata {
GroupActivityMetadata(title: "一起看电影")
}
}
// 发起者:创建并开始 activity
let activity = MovieWatchingActivity()
do {
let session = try await activity.activate()
// 监听 session 事件
configureSession(session)
} catch {
print("无法启动 Group Activity: \(error)")
}
同步播放状态
func configureSession(_ session: GroupSession<MovieWatchingActivity>) {
// 监听播放状态的同步
Task {
for await state in session.$playbackState.removeDuplicates() {
switch state {
case .playing:
player.play()
case .paused:
player.pause()
@unknown default:
break
}
}
}
// 当本地播放状态变化时,广播给其他参与者
Task {
for await reason in player.publisher(reason: .playbackState) {
session.playbackState = player.timeControlStatus == .playing ? .playing : .paused
}
}
}
处理参与者变化
// 监听参与者加入和离开
Task {
for await participants in session.$participants.removeDuplicates() {
// 更新 UI 显示参与者列表
participantCount = participants.count
// 参与者列表包含每个参与者的唯一标识
for participant in participants {
print("参与者: \(participant.id)")
}
}
}
// 当参与者离开到只剩一人时,自动结束 session
Task {
let count = await session.$participants.first { $0.count <= 1 }
if count != nil {
session.end()
// 切换回单人播放模式
}
}
最佳实践
新项目: 如果你的 App 有视频或音频播放功能,强烈建议集成 Group Activities。这是 iOS 15 的核心新特性之一,Apple 会在系统中大力推广 SharePlay。先实现基本的播放同步,再逐步添加自定义交互。
已有项目: 评估你的媒体播放架构是否使用了 AVPlayer。Group Activities 与 AVPlayer 的集成最简单——只需要几行代码就能启用同步播放。如果使用自定义播放器,需要手动实现状态同步逻辑,工作量会大很多。
还有什么值得关注
- Group Activities 支持”准备阶段”——发起者可以先选好内容,等参与者到齐后再开始播放。
- 在模拟器中无法测试 Group Activities,需要两台真机或使用 Xcode 的 Network Link Conditioner 模拟。
- 用户可以选择”仅同步不同时观看”,即只保持播放进度一致但不强制完全同步。