这是 iPhone Duo 六支苹果官方 Tech Talks 视频的最后一篇,前面五篇分别讲了设计原则、适配准备、导航栏、自适应布局和多屏场景。这一篇看相机。

相机应用在 iPhone Duo 上要处理的变量比别的 App 都多:设备多了一颗前置摄像头、屏幕能开能合还能翻面、预览要在两块屏幕之间来回跑。苹果在《Build a great camera experience for iPhone Duo》里把这些情况一次讲完了。

双前置摄像头:一颗在外面,一颗在屏幕下面

iPhone Duo 是第一款有两颗前置摄像头的 iPhone。两颗都是方形传感器,都是超广角。

外面那颗在设备外侧,就是你合上设备时能看到的那颗,拍照和视频质量都不错。打开设备,内屏上还有一颗,这是 iPhone 上第一颗屏下摄像头。

外屏超广角摄像头

取流的方式和其他 iPhone 一样,用 AVCaptureDeviceDiscoverySession 找前置摄像头,请求 position.front,配合 wide 或 ultrawide 设备类型。区别在于,在 iPhone Duo 上这么找出来的是一颗「虚拟前置摄像头」。

虚拟前置摄像头:切换交给系统

虚拟前置摄像头是一个新的 AVCaptureDevice。它的作用是在外屏和内屏两颗物理摄像头之间自动切换:设备打开时用内屏那颗,合上时切到外屏那颗。

相机应用在内屏取景,虚拟前置摄像头自动切换

方便是有代价的:用虚拟摄像头时,你只能访问两颗物理摄像头共有的能力,也就是最高 1080p 分辨率和 60fps。另外景深功能只在单独访问某一颗摄像头时可用。

如果你只是要一个能用的前置摄像头,虚拟这颗就够了,一行额外的代码都不用写。

单独访问每颗摄像头

想要全部能力,就用两颗摄像头各自的 AVCaptureDevice 类型:外屏的是 built-in outer ultrawide,内屏的是 built-in inner ultrawide。

两者的规格不一样。内屏超广角最高 1080p、60fps;外屏超广角最高能到 4K、120fps。差距不小,如果你在做录像类功能,值得按屏幕分别处理。

前置摄像头能力对比:虚拟摄像头只能取交集

代价是切换要自己做。用单独摄像头时,用户开合设备导致摄像头换了,App 得自己负责切过去。

摄像头方向在 Duo 上是真的复杂

AVCaptureDeviceposition 属性一直以来只有两种取值:back 或 front。iPhone 上从来没有歧义,前置就是对着你的那颗。

到了 iPhone Duo,这个前提没了。内外两颗前置摄像头的 position 都是 front,但屏幕可以朝相反的方向,前置摄像头并不总是对着你。

具体来说有几种情况:你在看内屏,视频流却来自外屏的前置摄像头,此时前置是背对你的;你从外屏前置取流的时候合上设备,同一颗摄像头转过来正对你;设备打开状态下把它翻过来,后置摄像头就变成了自拍镜头,App 和后摄都对着你。

position 解释不了这些,于是有了 AVCaptureDeviceDirectionCoordinator

AVCaptureDevicePosition 在 iPhone Duo 上的语义变化

方向协调器需要三样东西

创建协调器要提供:App 的 UIView、要监视的设备类型、一个变更处理程序。

协调器报告的是相对于这个视图的位置。视图在外屏时,外屏前置摄像头报为 forward-facing,后置报为 backward-facing。设备展开、视图移到内屏后,处理程序被调用:外屏前置和后置都变成 backward,内屏前置变成 forward。如果在展开状态下把设备翻转、再把相机 App 移到外屏,后置和外屏前置又都成了 forward。

也就是说,「哪个摄像头对着用户」这件事是随姿态实时变化的,App 必须跟着变。

初始化方向协调器

顺带说一句,这个协调器在 AVKit 里也能找到。

两块屏幕可以同时用

相机 App 在 iPhone Duo 上可以同时使用内屏和外屏。典型场景是群组视频通话,或者给小孩拍照时在外屏放点好玩的东西吸引注意力。

做法是每块屏幕一个 UIView,每个视图配一个独立的方向协调器。两个协调器的结论是相反的:外屏那个把后置报为前置,内屏那个把后置报为后置。因为每个协调器只相对自己的视图说话。

这套能力要通过 SceneAccessories API 启用,具体做法在第五篇《iPhone Duo 多屏开发》里。

内外屏各自对应一块显示区域

设备描述符:回调里别直接碰 AVFoundation

方向协调器绑定在视图上,所以它隔离在主 actor。这意味着变更处理程序里不能直接使用 AVFoundation 的 API。

协调器给你的不是 AVCaptureDevice,而是一个 AVCaptureDeviceDescriptor。descriptor 是 AVCaptureDevice 在主 actor 上的安全、可发送表示,包含创建 device 所需的全部信息,可以安全地传给相机 actor。到了那边再调用 AVFoundation 的 API。

方向变化时,处理程序该做什么

用户开合设备时,系统会调用你的处理程序,告诉你当前哪颗摄像头是前置。这时要做三件事:

重新配置 AVCaptureSession,保持从面向用户的那颗摄像头取流;重新考虑镜像策略,比如后置摄像头当自拍镜头用时,预览要镜像才符合直觉;最后用这个时机做相应的 UI 更新。

方向变化后的相机画面

把内屏预览做精致

内屏上用后置摄像头的全视场取流时,预览周围会多出一圈空间。有两种处理方式:把预览偏移到一侧,剩下的空间用来分组摆放控件;或者干脆让预览铺满整块屏幕。

预览在图层里怎么摆,由 AVCaptureVideoPreviewLayervideoGravity 决定。

从超广角前置摄像头取流时,可以利用方形传感器让画面填满屏幕。AVCaptureDevice 上的 dynamicAspectRatio 属性可以在内屏上选择横向宽高比。方形传感器的更多用法,可以看 WWDC26 的《在您的 iOS 应用中支持 Center Stage 前置摄像头》。

配置预览图层:videoGravity 与 dynamicAspectRatio

旋转交给旋转协调器

最后是旋转。采用 AVCaptureDeviceRotationCoordinator,可以保证摄像头预览和拍出来的照片始终是正的。在 iPhone Duo 上,App 在不同屏幕之间移动时它会自动更新,所以旋转行为在内外屏是一致的。

采用旋转协调器之后,记得禁用相机传感器的方向补偿来提升性能。这个补偿在 iPhone Duo 的所有前置摄像头上都是默认开启的。

禁用相机传感器方向补偿以提升性能

小结

相机应用在 iPhone Duo 上的工作量,主要花在「方向」这件事上。硬件上多了两颗前置摄像头,软件上多了一套方向协调机制,而虚拟前置摄像头把最常见的情况封装掉了。

按下面几步走:

  • 用 iOS 27.1 SDK 构建,拿到 iPhone Duo 的完整能力
  • 先想清楚开合设备时你的 App 要怎么切摄像头,能用虚拟前置摄像头就用
  • 需要 4K、120fps 或景深,就换成单独设备类型,并接入方向协调器
  • 处理程序里用 AVCaptureDeviceDescriptor 跨 actor 传参,不要直接碰 AVFoundation
  • 接上旋转协调器,并关闭传感器方向补偿
  • 一定要在真机上开合、翻转着测一遍预览

系列文章

这套教程一共六篇,对应苹果官方的六支 Tech Talks 视频: