RPBroadcastSampleHandler在倒计时结束后立即停止——AVAssetWriter在第一帧时崩溃

移动开发 2026-07-12

我需要在我的React Native Expo(bare)iOS项目中,使用ReplayKit的 Broadcast Upload Extension进行屏幕录制的帮助。

当前情况:

我的广播扩展在控制中心的“屏幕录制”下显示正确。

当我选择它时:

  • 三秒-二秒-一秒倒计时开始
  • 录制开始
  • 但它会瞬间停止

因此广播实际上并未正常运行。

因为这个原因:

  • 当我返回应用并调用stopRecording()
  • App Group的 UserDefaults键(lastRecordingPath)为空
  • 未返回视频路径

看起来像是:

  • broadcastStarted被触发
  • 但扩展立即停止
  • 因此broadcastFinished可能会立刻被调用
  • 或扩展在第一帧就崩溃

基于调试,我怀疑崩溃发生在processSampleBuffer收到第一帧视频并调用setupWriter() 时,此时使用以下参数初始化AVAssetWriter:

AVAssetWriter(outputURL: url, fileType: .mp4)

项目结构:

主应用
Broadcast Upload Extension(SampleHandler.swift)
App Group已配置并共享
扩展已正确嵌入(Embed & Sign)
启用自动签名
在物理设备测试(iPhone 11,iOS 18.2)

Bundle IDs:
主应用:com.athelia.app
广播扩展:com.athelia.app.AtheliaBroadcast

扩展在控制中心可见,因此配置似乎是正确的。

主要问题:
录制开始但立即停止。视频路径从未保存到App Group

崩溃日志显示(来自设备上的分析数据):
异常:EXC_CRASH (SIGABRT) -[AVAssetWriterInput markAsFinished] closure #1 in SampleHandler.broadcastFinished() consecutiveCrashCount: 3

来自主应用的日志:没有出现过任何 [EXT] 日志,确认扩展在 broadcastStarted 打印任何内容之前就崩溃了:
触发广播选择器按钮
广播检测轮询1:isActive=false ... 🔍 广播检测轮询20:isActive=false ⚠️ 广播检测超时

SampleHandler.swift:

override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
    let container = FileManager.default.containerURL(
        forSecurityApplicationGroupIdentifier: "group.com.athelia.app"
    )
    let baseURL = container ?? FileManager.default
        .urls(for: .documentDirectory, in: .userDomainMask)[0]
    let url = baseURL.appendingPathComponent("broadcast_\(Int(Date().timeIntervalSince1970)).mp4")
    outputURL = url

    UserDefaults(suiteName: "group.com.athelia.app")?.set(true, forKey: "broadcastIsActive")
}

override func broadcastFinished() {
    guard sessionStarted,
          let writer = assetWriter,
          writer.status == .writing else {
        saveResultAndExit(path: nil)
        return
    }
    videoInput?.markAsFinished()  // guarded — should never crash
    audioInput?.markAsFinished()
    writer.finishWriting { ... }
}

问题: 为什么在倒计时结束后广播扩展会立即停止?是什么原因导致 broadcastFinished 在没有接收到任何帧的情况下,在 broadcastStarted 之后立即被调用?

解决方案

我只有你提供的这些细节,所以基于此。以下是似乎正在发生的情况。

为什么广播会立即停止

崩溃日志指向broadcastFinished() 内的markAsFinished,但这很可能是早期崩溃的结果,而非根本原因。当扩展崩溃时,系统在清理过程中会调用broadcastFinished()。如果随后对从未接收过样本的输入调用markAsFinished(),可能会再次崩溃。因此真正的问题是在处理任何帧之前就已经发生的初始崩溃。

聚焦于找到初始崩溃点

失败很可能出现在以下某个位置:

  1. broadcastStarted – App Group容器为nil,或者输出URL不可写。
  2. processSampleBuffer – 当第一帧到达并执行setupWriter() 时(例如AVAssetWriter初始化失败)。
  3. First sample append – 当你尝试把第一帧缓冲区追加到写入器时。

如何缩小范围

  1. 在broadcastStarted中 – 记录App Group容器是否非nil,以及是否能向输出URL写入测试文件。
  2. 在setupWriter中 – 在创建AVAssetWriter之前记录日志,并将初始化放在do/catch中以记录任何错误。
  3. 在processSampleBuffer中 – 在接收到第一帧视频样本时记录日志,以及在调用append() 时记录。

需要验证的事项

  • App Group – 扩展目标是否具备App Groups功能并使用group.com.athelia.app。如果containerURL(forSecurityApplicationGroupIdentifier:) 返回nil,扩展沙箱中的回退到文档目录可能不可写。
  • AVAssetWriter init – 确保URL有效且可写。记录或处理任何初始化失败。
  • 扩展内存 – 广播扩展有严格的内存限制(约30MB)。大量分配可能导致系统终止扩展。

一旦你知道是哪一步失败,就可以针对修复。如果你能提供日志停止的位置,我们可以进一步缩小范围。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章