Highlight
Apple 在 iOS 15 引入 SharePlay 和 Group Activities,让开发者可以把 FaceTime 通话中的媒体播放和自定义协作体验接入系统级会话、同步播放和端到端加密的数据通道。
核心内容
你做了一个视频 App。两个用户想一起看同一段视频,最原始的做法是语音倒计时:三、二、一,播放。有人暂停,有人拖动进度条,其他人都要手动跟上。
如果你自己实现同步,事情会很快变复杂。你要知道谁在同一个房间里,要传递播放、暂停、跳转这些状态,还要处理通话、音量、画中画和多设备切换。媒体内容本身也不能通过通话重新传一遍,否则画质、版权和带宽都会出问题。
SharePlay 把这个场景放进 FaceTime 和 Messages。用户先进入一个系统会话,然后在你的 App 里启动一项 Group Activity(群组活动)。系统负责邀请、加入、离开和跨设备感知。你的 App 负责定义要共享的活动。
对媒体 App 来说,Group Activities 和 AVFoundation(音视频基础框架)配合工作。播放内容仍然从你的 App 和服务器取,系统只同步播放状态。用户按下播放、暂停或拖动进度,组内其他设备跟着同步。
对自定义协作 App 来说,GroupSession(群组会话)提供一个端到端加密通道。你可以用它传递“画了一笔”“切换到第 3 页”这类状态。它不适合传大文件,适合传保持用户同步所需的小消息。
详细内容
定义一个可以被 SharePlay 启动的活动
(07:24)
GroupActivity(群组活动)是框架的核心对象。它表示一件可以和 FaceTime 通话成员一起做的事。
在媒体 App 中,它可以保存当前要播放的内容 URL。在绘图 App 中,它可以保存大家要进入的画布信息。演讲中明确说,应用先创建一个实现 GroupActivity 协议的对象,再调用 prepareForActivation。
import Foundation
import GroupActivities
struct MovieActivity: GroupActivity {
let contentURL: URL
var metadata: GroupActivityMetadata {
var metadata = GroupActivityMetadata()
metadata.title = "Movie Night"
metadata.type = .watchTogether
return metadata
}
}
关键点:
import Foundation提供URL类型。import GroupActivities引入 SharePlay 背后的框架。MovieActivity遵守GroupActivity,表示 App 支持共享的一项活动。contentURL保存这次活动要播放的内容位置,对应演讲中“GroupActivity 持有共享体验所需信息”的描述。metadata给系统展示活动信息。metadata.type = .watchTogether表示这是一个一起观看的媒体体验。
启动活动前先让用户确认
(07:48)
用户在 FaceTime 通话中打开你的 App,点下播放按钮后,App 不应该直接把所有人拉进活动。演讲说,prepareForActivation 会让用户选择“和 FaceTime 中所有人共享”或“只在本地继续”。
确认后,App 再调用 activate,告诉系统要启动共享体验。
import Foundation
import GroupActivities
func startMovieNight(contentURL: URL) async throws {
let activity = MovieActivity(contentURL: contentURL)
let result = await activity.prepareForActivation()
if result == .activationPreferred {
try await activity.activate()
}
}
关键点:
MovieActivity(contentURL:)创建本次要共享的活动。prepareForActivation()触发系统确认流程,避免用户被突然带入共享体验。result == .activationPreferred表示用户选择和群组共享。activate()开始活动,随后系统会向参与设备分发对应的 GroupSession。
监听 GroupSession,再加入会话
(12:44)
活动启动后,发起设备和接收设备都要监听传入的会话。演讲说,应用需要遍历 GroupSession 上的 AsyncSequence。拿到会话后,先做准备工作,再调用 join。
准备工作取决于 App 类型。绘图 App 可以先加载画布资源。媒体 App 可以先准备播放器,并把播放器的协调器接到会话上。
import AVFoundation
import GroupActivities
func observeMovieSessions(player: AVPlayer) async {
for await session in MovieActivity.sessions() {
player.playbackCoordinator.coordinateWithSession(session)
session.join()
}
}
关键点:
MovieActivity.sessions()返回传入会话的异步序列。for await持续等待系统交给 App 的 GroupSession。player.playbackCoordinator是 AVPlayer 的播放协调器。coordinateWithSession(session)把 AVFoundation 的同步播放接入 GroupSession。session.join()加入会话,系统随后建立端到端加密通道。
用 GroupSession 传同步状态,不传媒体内容
(10:21)
GroupSession 代表正在参与共享体验的群组。它能访问参与者,也能和框架中的其他 API 配合,在设备之间收发数据。
这个通道有边界。演讲中特别说明,它不用于交换大量数据。共享听歌时,不要用它传歌曲文件。AVFoundation 使用它交换播放、暂停、跳转这些命令,让各端保持同一播放状态。
import GroupActivities
func joinDrawingSession(session: GroupSession<DrawingActivity>) {
let participants = session.activeParticipants
for participant in participants {
print(participant.id)
}
session.join()
}
关键点:
GroupSession<DrawingActivity>表示一次绘图活动的群组会话。activeParticipants读取当前参与共享体验的用户集合。- 循环中的
participant.id可用于识别参与者。 session.join()让当前设备正式进入共享体验。- 这个通道适合传绘图操作、页面位置、播放状态这类同步信息。
媒体播放事件可以交给系统展示
(15:28)
用户一起看片时,组内成员需要知道发生了什么。谁暂停了,谁跳过了一段,谁开始播放了下一首。Group Activities 支持发布事件,让系统显示提示。
演讲说,如果使用 AVPlayer 或 AVDelegatingPlaybackCoordinator,媒体播放事件可以自动获得这套能力。没有使用这两者的 App,仍然可以通过框架发布事件。
import AVFoundation
import GroupActivities
func configureSharedPlayback(player: AVPlayer, session: GroupSession<MovieActivity>) {
player.playbackCoordinator.coordinateWithSession(session)
session.join()
}
关键点:
AVPlayer负责播放 App 自己提供的媒体内容。GroupSession<MovieActivity>代表当前 SharePlay 群组。coordinateWithSession(session)让播放器通过 GroupSession 同步播放状态。session.join()建立参与关系后,播放、暂停和跳转会在群组内同步。- 使用 AVPlayer 时,播放事件提示由系统处理。
核心启发
-
做什么:给长视频 App 加“一起看”按钮。 为什么值得做:演讲说明,SharePlay 会让 FaceTime 中的用户直接从你的 App 启动共享媒体体验,播放状态由 AVFoundation 同步。 怎么开始:定义保存视频 URL 的
GroupActivity,播放按钮里调用prepareForActivation()和activate(),监听MovieActivity.sessions()后把AVPlayer.playbackCoordinator接到会话。 -
做什么:给播客 App 做远程共同收听。 为什么值得做:音频内容也属于共享媒体播放场景,系统可以处理智能音量,用户讲话时降低内容音量。 怎么开始:为单集节目建立
GroupActivity,用AVPlayer播放音频,加入 GroupSession 后用播放协调器同步播放、暂停和跳转。 -
做什么:给白板 App 做 FaceTime 共同画图。 为什么值得做:演讲把 draw-together 作为自定义体验示例,GroupSession 提供端到端加密的数据通道。 怎么开始:让活动对象保存画布 ID;进入会话后加载画布资源;用 GroupSession 的消息能力传递笔画、撤销、清空等小状态。
-
做什么:给在线课程 App 做“同学一起看课”。 为什么值得做:课程视频仍从你的服务器播放,SharePlay 只同步播放状态,不重新传输媒体。 怎么开始:把课时 URL 放入 GroupActivity;加入会话后协调 AVPlayer;在章节切换时更新本地播放器状态。
-
做什么:给 Web 配套服务规划 Safari 共享体验。 为什么值得做:演讲说明 Group Activities 在 macOS 上支持 WebKit,可以把 SharePlay 扩展到网站。 怎么开始:先阅读 “Coordinate media playback in Safari with Group Activities”,把 App 端活动模型和网页端媒体播放状态对应起来。
关联 Session
- Design for Group Activities — 从产品和交互角度设计 SharePlay 体验,决定什么内容适合群组共享。
- Coordinate media experiences with Group Activities — 详细讲媒体 App 如何接入同步播放、画中画和播放协调器。
- Build custom experiences with Group Activities — 讲自定义协作体验和 GroupSessionMessenger,适合白板、游戏和共同编辑场景。
- Coordinate media playback in Safari with Group Activities — 讲 Safari 和配套 App 如何一起支持 SharePlay 网页媒体播放。
评论
GitHub Issues · utterances