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

相关推荐
浮江雾7 小时前
Flutter第十节-----Flutter布局与组件全解析
android·开发语言·前端·学习·flutter·入门
xcLeigh7 小时前
Doubao-Seed-Evolving大模型接入教程|搭建全品类提示词+AI工具导航网页
前端·人工智能·python·ai·html·ai开发·豆包
巴勒个啦8 小时前
Vue 3.6 Vapor Mode 实战:我把一个 Vue3 项目的渲染性能提升了 4 倍
前端·angular.js
不简说8 小时前
# JS 代码技巧 vol.7 — 20 个浏览器 API 实战,自带 API 能干的事别自己封装
前端·javascript·面试
CodexDave9 小时前
数据库连接池耗尽:排查顺序与三层兜底
服务器·前端·数据库·git·云原生·容器·kubernetes
Hilaku9 小时前
为什么 Cloudflare 能做到毫秒级冷启动,而其它云厂商却不行?
前端·javascript·程序员
2301_794461579 小时前
JavaScript 基础知识点详解
前端·javascript·html
HjhIron9 小时前
在浏览器中跑DeepSeek-R1:用React+WebGPU实现端侧AI推理
前端·ai编程