Support external cameras in your iPadOS app
Media & Web 进阶 20m

在 iPadOS 应用中支持外接摄像头

Support external cameras in your iPadOS app

2023年6月5日

在 Apple 官方观看视频

一句话判断

iPadOS 17 让你的应用可以使用 Apple Studio Display 等外接摄像头——配合 Stage Manager 多屏扩展,外接摄像头的发现、连接/断开处理、视频旋转和麦克风支持都有完整的 API 覆盖。

这场 Session 讲了什么

Camera Software 团队的 Nikolas Gelo 详细介绍了 iPadOS 17 中外接摄像头的支持。Stage Manager 让 iPad 可以扩展到多个屏幕,iPadOS 17 则让应用能使用这些外接显示器上内置的摄像头(如 Apple Studio Display 的摄像头),或者通过 USB 连接的网络摄像头。

外接摄像头通过 AVFoundation 的 AVCapture 框架使用。如果你的应用已经在用内置摄像头,只需要少量改动就能支持外接摄像头。外接摄像头的设备类型是 .external,位置是 .unspecified(因为它们可以独立于 iPad 移动)。

Session 以 AVCam 示例应用为基础,演示了完整的改造过程:发现外接摄像头、优先使用外接摄像头、处理连接/断开事件、处理视频旋转、使用外接摄像头自带的麦克风。

外接摄像头还支持系统级的 Portrait Blur 和 Studio Light 视频效果(通过控制中心开启)。部分非摄像头设备(如 HDMI 切换器)如果符合 USB Video Class(UVC)规范,也可以被识别为外接摄像头。

值得深挖的点

自动摄像头选择 API:iPadOS 17 引入了与 macOS Ventura 的 Continuity Camera 类似的自动摄像头选择 API。系统会根据当前情况选择最佳可用摄像头——外接摄像头优先于内置摄像头。你的应用不需要手动管理摄像头切换逻辑。

连接/断开事件的处理:与内置摄像头不同,外接摄像头可以随时被拔掉。应用必须监听 isConnected 属性的 KVO 变化,或者观察 AVCaptureDevice 的通知。当外接摄像头断开时,应该自动切换到内置摄像头。同一设备重新连接后会生成新的 AVCaptureDevice 实例。

视频旋转的复杂性:外接摄像头的视频方向可能与 iPad 的物理方向不匹配。AVCaptureVideoPreviewLayer 默认会镜像外接摄像头画面(适合 Apple Studio Display 这种面向用户的使用场景),但可以禁用。Session 专门用了一个章节来解释视频旋转的细节。

外接麦克风支持:有些外接摄像头内置麦克风(如 Apple Studio Display),这些麦克风也通过 AVFoundation 可用。你的应用可以同时使用外接摄像头的视频和音频。

代码片段

// 发现外接摄像头
let discoverySession = AVCaptureDevice.DiscoverySession(
    deviceTypes: [.builtInWideAngleCamera, .external],  // 包含外接类型
    mediaType: .video,
    position: .unspecified
)

// 优先使用外接摄像头
let externalCamera = discoverySession.devices.first { $0.deviceType == .external }
let camera = externalCamera ?? AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)

// 设置捕获会话
let input = try AVCaptureDeviceInput(device: camera!)
session.addInput(input)
// 监听外接摄像头的连接和断开
// 方式 1: KVO 观察
observation = camera.observe(\.isConnected) { device, change in
    if !device.isConnected {
        // 切换到内置摄像头
        switchToBuiltInCamera()
    }
}

// 方式 2: 通知
NotificationCenter.default.addObserver(
    forName: .AVCaptureDeviceWasConnected,
    object: nil, queue: nil
) { notification in
    if let device = notification.object as? AVCaptureDevice,
       device.deviceType == .external {
        // 外接摄像头已连接,询问是否切换
        offerSwitchToExternalCamera(device)
    }
}
// 自动摄像头选择(推荐方式)
// 让系统自动选择最佳摄像头
let session = AVCaptureSession()
session.automaticallyConfiguresCaptureDeviceForWideColor = true

// iPadOS 会优先选择外接摄像头
// 当外接摄像头断开时自动切换到内置摄像头

最佳实践

  • 优先使用自动摄像头选择 API:让系统管理摄像头选择和切换,比手动处理更可靠。系统会考虑外接摄像头的可用性。
  • 一定要处理断开事件:外接摄像头随时可能被拔掉。不处理断开会导致预览画面冻结。
  • 使用 .external 设备类型:macOS 开发者注意,.externalUnknown 在 iPadOS 上已被废弃,统一使用 .external
  • 注意线程同步:摄像头连接/断开的通知在后台队列发送,确保与 AVCaptureSession 队列和主线程同步。
  • 镜像行为按需配置:Preview Layer 默认镜像外接摄像头,适合自拍场景。如果需要真实方向,禁用镜像。

还有什么值得关注

  • 外接摄像头支持 Center Stage(人物居中),在 FaceTime 等应用中自动保持用户在画面中心。
  • USB Video Class(UVC)是标准协议,市面上大多数 USB 网络摄像头都兼容。甚至 HDMI 切换器等非摄像头设备也能作为视频源使用。
  • Portrait Blur 和 Studio Light 是系统级效果,你的应用不需要自己实现,用户从控制中心开启即可。
  • 有 USB-C 接口的 iPad 才支持外接摄像头——这是硬件限制。
  • Session 提到可以下载改造后的 AVCam 示例代码作为参考实现。
WWDC 2023