SharePlay 的新变化
What's new in SharePlay
2022年6月6日
一句话判断
从应用内直接发起 SharePlay、消息载荷翻四倍、不可靠消息模式——SharePlay 正在从”能用来同步播放”进化为”能用来做实时协作”。
这场 Session 讲了什么
SharePlay 在 iOS 15.4 和 iOS 16 中获得了三项重要更新:
从应用内发起 SharePlay:过去用户必须先在 FaceTime 通话中才能启动 SharePlay 活动。现在用户可以在应用内直接发起——通过 Share Sheet 中的 SharePlay 按钮,或使用新的 GroupActivitySharingController 在应用内放置一个启动按钮。用户点击后系统弹出 People Picker,选择联系人后自动发起 FaceTime 并启动 Group Session。
GroupSessionMessenger 载荷扩大:消息载荷从原来的 64KB 提升到 256KB,是原来的四倍。这意味着你不需要再手动拆分大消息。
不可靠消息模式(Unreliable Messaging):新增 MessageReliability 选项,让你选择消息的传输方式。可靠模式(默认)保证消息送达但可能延迟;不可靠模式使用 UDP,延迟更低但不保证送达。
值得深挖的点
不可靠消息模式的适用场景是这次 Session 最有价值的讨论。用实时协作绘画应用 DrawTogether 举例:当用户在屏幕上画画时,GestureRecognizer 每帧都产生新的坐标点。用可靠消息发送这些点意味着每帧都在等待确认,一旦丢包重传就会导致画面卡顿或延迟。切换到不可靠消息后,即使某些点丢失了,下一帧的新点会覆盖旧状态,画面始终保持流畅。
Staged GroupActivity 概念值得注意。当用户从应用内发起 SharePlay 时,活动进入”暂存”状态——FaceTime 已拨出但还没人接听。此时 GroupActivity 已经创建但不活跃,等对方接受通话后才真正激活 GroupSession。这个状态转换需要开发者正确处理。
Share Sheet 的零适配方案意味着如果你的应用已经声明了 SharePlay 权限,系统会自动在 Share Sheet 中添加 SharePlay 按钮。但 Session 也提醒这种方式的用户体验不是最优的——用户需要重新回到应用才能选择要分享的内容。
代码片段
在应用内发起 SharePlay:
// 方式一:使用 GroupActivitySharingController
// 在 SwiftUI 中包装为 UIViewControllerRepresentable
struct SharingControllerWrapper: UIViewControllerRepresentable {
let activity: DrawActivity
func makeUIViewController(context: Context) -> GroupActivitySharingController {
return GroupActivitySharingController(activity: activity)
}
func updateUIViewController(
_ uiViewController: GroupActivitySharingController,
context: Context
) {}
}
// 在视图中使用
Button("开始 SharePlay") {
isSharingPresented = true
}
.sheet(isPresented: $isSharingPresented) {
SharingControllerWrapper(activity: drawActivity)
}
使用不可靠消息:
// 创建指定可靠性的 Messenger
let messenger = GroupSessionMessenger(
session: session,
deliveryMode: .unreliable // 关键:使用不可靠模式
)
// 在 GestureRecognizer 回调中发送绘图点
func handleGestureUpdate(_ point: CGPoint) {
let message = DrawMessage(point: point)
Task {
// 不可靠发送,不等待确认,低延迟
try? await messenger.send(message)
}
}
控制 Share Sheet 中的 SharePlay 显示:
let activityVC = UIActivityViewController(
activityItems: [itemProvider],
applicationActivities: nil
)
// 不在 Share Sheet 中突出显示 SharePlay
activityVC.allowsPromptingActivity = false
// 或者完全排除 SharePlay
activityVC.excludedActivityTypes = [.groupActivity]
最佳实践
- 实时交互用不可靠消息:绘画位置、游戏状态同步等需要低延迟的场景,丢几个包比延迟好
- 关键操作用可靠消息:开始/暂停播放、状态确认等必须送达的消息,继续用默认的可靠模式
- 256KB 载荷够用但不滥用:虽然载荷变大了,但大消息仍然会占用更多带宽,尤其是多人会话时
- 处理 Staged 状态:应用内发起的 SharePlay 可能停留在暂存状态,UI 要给出合理的等待反馈
- 提供应用内启动入口:不要只依赖 Share Sheet,在应用内放置 SharePlay 按钮的转化率更高
还有什么值得关注
- 不可靠消息基于 UDP,适合多人实时游戏和协作绘图类应用
- 256KB 的载荷上限对于传输小型 JSON 状态已经足够,但不要用来传输图片或音频数据
GroupActivitySharingController是 UIViewController,SwiftUI 项目需要包装- SharePlay 的零适配方案适合快速验证,正式产品建议用完整 API