探索 ReplayKit 滚动录制片段
Discover rolling clips with ReplayKit
2021年6月11日
一句话判断
Rolling Clips 是 ReplayKit 的”回溯录制”功能 —— 游戏不需要一直录屏,只在精彩瞬间发生时回捞过去几秒的画面,存储和性能开销都降了一个数量级,但实现细节比想象中复杂。
这场 Session 讲了什么
Session 介绍了 ReplayKit 在 iOS 15 中的新功能:Rolling Clips(滚动片段录制)。传统 ReplayKit 需要用户手动开始/停止录制,整个过程中视频数据持续写入磁盘。Rolling Clips 改变了这个模型 —— 它始终在后台缓冲最近 N 秒的画面(不写入磁盘),当用户触发”保存”时,把缓冲区的内容导出为视频片段。
工作流程:app 启动 Rolling Clips -> 系统在内存中保持一个环形缓冲区(默认 15 秒)-> 精彩时刻发生 -> 用户点击保存或 app 自动触发 -> 缓冲区内容被编码为视频文件 -> 保存到相册或分享。
这个功能特别适合游戏场景:击杀、进球、Boss 击败等瞬间,玩家不需要提前录制,事后回捞即可。
值得深挖的点
环形缓冲区的内存管理。Rolling Clips 把视频帧保持在内存中,不写入磁盘。缓冲区大小取决于分辨率和帧率:1080p 60fps 的 15 秒片段大约需要 150-200MB 内存。在设备内存紧张时(如打开了很多 app),系统可能会静默停止 Rolling Clips 而不通知你。你需要监听 RPScreenRecorder 的状态变化来处理这种情况。
自动触发的时机选择。Session 建议两种触发模式:手动触发(用户按按钮保存)和自动触发(游戏逻辑检测到精彩瞬间)。自动触发的挑战在于”精彩”的定义 —— 击杀数、连击、Boss 血量变化等游戏事件都可以作为触发条件。但要注意误触发:如果每次小事件都保存,用户相册里会堆满无意义的短片段。
代码片段
启动 Rolling Clips 录制:
import ReplayKit
class ClipRecorder: NSObject, RPScreenRecorderDelegate {
let recorder = RPScreenRecorder.shared()
func startRollingClip() {
guard recorder.isAvailable else {
print("ReplayKit 不可用")
return
}
recorder.delegate = self
// 启动 Rolling Clips 模式
recorder.startClipBuffering(
captureHandler: { sampleBuffer, bufferType, error in
if let error = error {
print("缓冲错误: \(error)")
return
}
// sampleBuffer 会自动进入环形缓冲区
},
completionHandler: { error in
if let error = error {
print("启动 Rolling Clips 失败: \(error)")
} else {
print("Rolling Clips 已启动,持续缓冲中...")
}
}
)
}
}
保存缓冲区内容为视频片段:
import ReplayKit
extension ClipRecorder {
// 用户触发或游戏自动触发保存
func saveClip() {
// 导出最近 15 秒的缓冲内容
recorder.exportClip(
to: getOutputURL(),
completionHandler: { error in
if let error = error {
print("导出失败: \(error)")
return
}
print("精彩片段已保存")
// 可选:保存到相册
self.saveToPhotoLibrary()
}
)
}
private func getOutputURL() -> URL {
let tempDir = FileManager.default.temporaryDirectory
let fileName = "clip_\(Int(Date().timeIntervalSince1970)).mp4"
return tempDir.appendingPathComponent(fileName)
}
}
游戏事件触发的自动保存:
// 在游戏逻辑中检测精彩时刻
func onPlayerAchievement(_ achievement: GameAchievement) {
switch achievement.type {
case .killStreak where achievement.count >= 5:
// 五连杀!自动保存最近片段
clipRecorder.saveClip()
showClipSavedNotification("五连击杀已保存!")
case .bossDefeated:
clipRecorder.saveClip()
showClipSavedNotification("Boss 击败片段已保存!")
case .levelCompleted where achievement.time < 60:
// 速通成就
clipRecorder.saveClip()
showClipSavedNotification("速通记录已保存!")
default:
break
}
}
最佳实践
- 缓冲时长根据游戏类型调整。格斗/射击游戏 15 秒足够(击杀瞬间很短);MOBA/RPG 建议延长到 30 秒(团战/ Boss 战时间更长)。
- 在低端设备上主动禁用 Rolling Clips。如果可用内存低于 1GB,启动缓冲可能导致系统杀 app。用
ProcessInfo.processInfo.physicalMemory检查设备能力。 - 给用户一个明显的”正在录制”指示器。虽然 Rolling Clips 不写磁盘,但用户需要知道”随时可以回捞”这个功能的存在。在 HUD 上放一个小图标,比埋在设置菜单里有效。
还有什么值得关注
- Rolling Clips 支持同时录制麦克风和系统音频。
- 导出的视频片段可以添加 app 的水印或 Logo overlay。
RPScreenRecorder的isClipBufferingAvailable属性可以检测设备是否支持此功能。