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 的停止按钮暴力杀进程,这样能极大降低该特性的卡死概率。

相关推荐
小林ixn7 分钟前
前端卡顿终结者:用 useRef 把 Web Worker 请进 React 项目
前端·react.js·前端框架
sunly_7 分钟前
React 三个重要概念:Ref、Props、State 详解
前端·javascript·react.js
weixin_431600448 分钟前
前端对接 SSE 的两种常见方式
前端·后端·学习·ai·sse·nest.js
Mh14 分钟前
如何使用GSAP实现一个 `pinned` 滚动楼层叙事?
前端·javascript·css
用户938515635079 小时前
从零在浏览器里跑 DeepSeek-R1:WebGPU + Transformer.js 全链路实战
前端·设计模式·typescript
CodeSheep9 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
鱼樱前端10 小时前
用 AI 做内容变收入
前端·人工智能·ai编程
浮生望10 小时前
React + TypeScript 组件设计进阶:从类型约束到无状态组件的三次进化
前端
90后的晨仔10 小时前
Mac 开发 uni-app 终极方案:让安卓模拟器彻底脱离 Android Studio 独立运行
前端·vue.js
90后的晨仔10 小时前
别再搞混了!uni-app 中 node_modules 和 uni_modules 到底是什么关系?
前端