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

相关推荐
风骏时光牛马6 分钟前
大模型落地实践中的技术选型思路与方案对比
前端
IT_陈寒33 分钟前
Vite打包时的静态资源坑,我帮你踩过了
前端·人工智能·后端
默_笙2 小时前
🔥 让 AI 帮我写完整个 Next.js 博客:框架就是 AI 的"上下文 buff"
前端·javascript
牧艺2 小时前
登录页还在用渐变?我一口气做了 5 个能摸的背景动效:吹蒲公英、滴墨染水、点熔岩闷裂
前端·canvas·交互设计
陆枫Larry2 小时前
状态机简介
前端
陆枫Larry3 小时前
一次登录问题排查:接口没错,错的是旧业务逻辑
前端
小小小小宇3 小时前
大模型打分与采样原理,以及 Pi Agent 核心原理
前端
一位正在转型AI全栈的前端工程师3 小时前
AI 全栈学习之旅 -Week 5:RAG 知识库问答系统:从零到生产级部署的全栈实践总结
前端·python
光影少年4 小时前
react navite 安卓iOS 打包、签名、环境区分
前端·react native·react.js
coderCN4 小时前
Nodejs 第三十四章 数据库(表达式和函数、子查询和连表)
前端·node.js