iPhone摄像头 在开发/调试过程中强行停止 App,导致 `AVCaptureSession` 没有被正常释放

这是在开发连续互通摄像头(Continuity Camera)时非常典型的问题。根本原因通常是因为在开发/调试过程中强行停止 App(例如在 Xcode 中直接 Stop),导致 AVCaptureSession 没有被正常释放。

macOS 底层的媒体服务和发现服务(Bonjour/Rapport)会误以为之前的会话仍在进行中,从而锁死了设备通道。这不仅阻止了新的连接,也导致手机和电脑的系统层不再弹出连接提示。

完全可以避免重启 MacBook。你可以通过以下几个层面的方法来恢复连接并避免后续复发。

一、 立即恢复连接(无需重启 Mac)

既然你在做开发,最快捷的方式是通过终端清理卡死的后台守护进程(Daemons)或重置网络栈。

1. 杀掉卡死的底层守护进程(推荐) 连续互通摄像头强依赖两个核心进程:rapportd(负责设备发现和握手)以及 avconferenced(负责视频流传输)。打开终端执行以下命令强制重启它们:

Bash

复制代码
sudo killall rapportd avconferenced

执行后等待几秒钟,系统会自动重启这两个进程,通常这样就能重新唤醒手机的连接提示。

2. 重置 AWDL (Apple Wireless Direct Link) 状态 连续互通依赖 Wi-Fi 和蓝牙建立的 P2P 直连。有时底层的网络栈卡死了,你可以通过断开并重新连接来重置:

  • Mac 端:关闭 Wi-Fi 和蓝牙,等待 3 秒后再打开。
  • iPhone 端:进入"设置" -> "通用" -> "隔空播放与接力"(AirPlay & Handoff),将"连续互通摄像头"开关关闭再重新打开。

二、 代码层面的预防机制

为了避免每次 Debug 运行后都要手动清进程,你需要在代码中做好状态的清理工作。连续互通摄像头的虚拟设备状态极其脆弱。

1. 确保释放 AVCaptureSession 绝大多数的卡死都是因为没有显式调用 stopRunning()。你需要确保在 App 退出、进入后台、或者切换摄像头时,正确结束会话并移除输入源:

Swift

scss 复制代码
// 在 deinit, applicationWillTerminate 或进入后台的生命周期方法中执行
if captureSession.isRunning {
    captureSession.stopRunning()
}
// 移除对应的连续互通摄像头 Input
if let currentInput = videoDeviceInput {
    captureSession.removeInput(currentInput)
}

2. 监听系统的中断事件(Interruption) 连续互通摄像头可能会因为网络波动或用户拿起手机退出锁屏而中断。务必监听 AVCaptureSessionWasInterrupted 通知,并在中断结束时妥善处理,否则很容易变成僵尸会话:

Swift

swift 复制代码
NotificationCenter.default.addObserver(
    self,
    selector: #selector(sessionWasInterrupted),
    name: .AVCaptureSessionWasInterrupted,
    object: captureSession
)

@objc func sessionWasInterrupted(notification: NSNotification) {
    guard let userInfoValue = notification.userInfo?[AVCaptureSessionInterruptionReasonKey] as AnyObject?,
          let reasonIntegerValue = userInfoValue.integerValue,
          let reason = AVCaptureSession.InterruptionReason(rawValue: reasonIntegerValue) else {
        return
    }
    
    print("Capture session interrupted. Reason: (reason)")
    // 如果是因为视频设备不可用,准备好清理 UI 和释放资源
}

3. 正确的设备监听与选择 不要在启动时硬编码去抓取特定的连续互通摄像头,而是应该使用 AVCaptureDevice.DiscoverySession 动态监听设备列表的增减。当设备断开时(比如手机屏幕解锁了),你的 App 应该立刻收到回调并做出 removeInput 处理,这样系统才不会认为你的 App 还在强占通道。

下次如果在 Xcode 中需要重新编译,尽量先让你的 App 正常退出(或触发 stopRunning),而不是直接点击 Xcode 的停止按钮暴力杀进程,这样能极大降低该特性的卡死概率。

相关推荐
Csvn9 小时前
WASM
前端
修己xj10 小时前
我用 AI 给自己写了一个 Markdown 编辑器,然后把它开源了
前端
FRing0310 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
幸运小猿10 小时前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
moshuying12 小时前
网购能买Token了!
前端
h_654321012 小时前
echarts实现柱状图加一条横线
前端·echarts
风骏时光牛马12 小时前
生成一个后端标题,只需要一个标题,不需要其他的任何文本。
前端
子非鱼@Itfuture12 小时前
关于前后端联调中登录状态/登录信息失效?
java·前端
郭小李12 小时前
openFeign入门
java·开发语言·前端
馒头不想说话12 小时前
AI当运营,帮你省人力
前端