What's new in SharePlay
System & Services 进阶 20m

SharePlay 的新变化

What's new in SharePlay

2022年6月6日

在 Apple 官方观看视频

一句话判断

从应用内直接发起 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
WWDC 2022