iPhone Duo Camera Development Guide

Use AVCaptureDeviceDirectionCoordinator for facing relative to a view, RotationCoordinator to keep preview level across Duo poses, plus the virtual front camera and CameraCaptureAccessory.

Last updated

Quick answer

Use the virtual front camera (AVCaptureDevice at position .front) for shared-capability capture that auto-switches the outer vs under-display inner camera; use AVCaptureDeviceDirectionCoordinator (AVKit) when you need facing relative to a view — AVCaptureDevice.position is hardware location, not “facing the user”; and use AVCaptureDevice.RotationCoordinator so preview and capture stay level as Duo poses and displays change. Put supplementary UI on the outer display with CameraCaptureAccessory via SwiftUI .sceneAccessory() (or UIKit UISceneAccessory.cameraCapture) while capture stays full screen on the inner display. Size the preview layer to the current view bounds, and don't lock orientation at launch.

Adaptive viewfinder

Camera apps built with AVCaptureVideoPreviewLayer should size the preview layer to the current view bounds rather than a fixed aspect ratio tied to a specific device. On Duo, the available capture surface changes as the device folds and unfolds, and the preview should resize along with it.

Virtual front camera

The virtual front camera is an AVCaptureDevice at position .front that auto-switches between the outer camera and the under-display inner camera as the device opens or closes.

  • Shared capabilities are enough (typically 1080p/60, no depth) → use position .front.
  • Need 4K/120 or a specific sensor → use .builtInOuterUltraWideCamera / .builtInInnerUltraWideCamera.
  • Need facing relative to a view → AVCaptureDeviceDirectionCoordinator (AVKit). AVCaptureDevice.position is hardware location, not “facing the user”.

Direction coordinator

On Duo, AVCaptureDevice.position is the camera's hardware location, not whether it faces the user. Choose a camera by the direction it faces relative to a view with Choosing a camera by the direction it faces and AVCaptureDeviceDirectionCoordinator (AVKit, main actor).

Create the coordinator with a view, the device types you care about, and a changeHandler. The handler receives an AVCaptureDeviceDirectionMap with forwardFacingDeviceDescriptors and backwardFacingDeviceDescriptors. Forward-facing means the same direction as the view, not .front position.

  • Create one coordinator per view if you use both displays (scene accessories).
  • Include rear cameras in deviceTypes — they can face the user when Duo is flipped open.
  • The virtual front camera is not reported. Specify .builtInOuterUltraWideCamera and .builtInInnerUltraWideCamera.
  • Pass AVCaptureDeviceDescriptor to a capture actor. Don't call AVFoundation from the change handler.
  • Mirror using the map, not position. Disable automaticallyAdjustsVideoMirroring before setting isVideoMirrored.
DirectionCoordinator.swift
directionCoordinator = AVCaptureDeviceDirectionCoordinator(
    view: view,
    deviceTypes: [
        .builtInOuterUltraWideCamera,
        .builtInInnerUltraWideCamera,
        .builtInDualWideCamera,
    ],
    changeHandler: { [weak self] map in
        self?.updateCameraSession(map)
    }
)

Camera capture accessory

Put supplementary UI on the OUTER display while the camera stays full screen on the INNER display, only when the app is full screen with an active camera session. The system controls availability — closing the device withdraws the accessory. It is not a duplicate of the full Camera UI.

CaptureAccessory.swift
ContentView()
    .sceneAccessory {
        CameraCaptureAccessory(isEnabled: true) {
            AccessoryControls()
        }
        .onAvailabilityChange { isAvailable in
            updateAccessoryUI(isAvailable)
        }
    }

UIKit: call UISceneAccessory.cameraCapture(sceneConfiguration:userInfo:) then register and unregister as the session starts and stops.

Outer display preview

A camera app can mirror the viewfinder to the outer display so subjects can see themselves while the photographer uses the inner display — useful for selfies taken with the rear camera. This uses the same multi-scene approach described in the Multiple Displays guide. For capture-session chrome on the outer display, prefer CameraCaptureAccessory rather than a second full camera UI.

Device rotation

Keep the preview and stills level with Supporting device rotation in your camera app. Use AVCaptureDevice.RotationCoordinator (AVCaptureDeviceRotationCoordinator). Recreate it when switching cameras; Duo display moves also change the angle.

Read the current angles before starting KVO — KVO only notifies later changes. Preview angle and capture angle can differ. After adopting the rotation coordinator, disable camera sensor orientation correction (Apple says this correction is on for all Duo front cameras).

RotationCoordinator.swift
let coordinator = AVCaptureDevice.RotationCoordinator(
    device: device, previewLayer: previewLayer
)
previewLayer.connection?.videoRotationAngle =
    coordinator.videoRotationAngleForHorizonLevelPreview
photoOutput.connection(with: .video)?.videoRotationAngle =
    coordinator.videoRotationAngleForHorizonLevelCapture

Common mistake

Don't lock capture orientation to the device's physical orientation at launch, and don't treat .front as “facing the user”. Read rotation from AVCaptureDevice.RotationCoordinator and facing from AVCaptureDeviceDirectionCoordinator.

Frequently asked questions

What is the virtual front camera on iPhone Duo?

It is an AVCaptureDevice at position .front that auto-switches between the outer and under-display inner camera as the device opens or closes. It exposes shared capabilities only — typically 1080p/60, no depth. Need 4K/120 or a specific sensor → use .builtInOuterUltraWideCamera or .builtInInnerUltraWideCamera. AVCaptureDevice.position is hardware location, not “facing the user”; use AVCaptureDeviceDirectionCoordinator (AVKit) for facing relative to a view.

What to use instead of assuming front camera faces the user?

Use AVCaptureDeviceDirectionCoordinator (AVKit, main actor) with a view, deviceTypes, and a changeHandler. AVCaptureDevice.position is hardware location, not “facing the user”. The handler receives an AVCaptureDeviceDirectionMap with forwardFacingDeviceDescriptors and backwardFacingDeviceDescriptors — forward-facing means the same direction as the view, not .front. Create one coordinator per view if you use both displays. Include rear cameras in deviceTypes because they can face the user when Duo is flipped open. The virtual front camera is not reported — specify .builtInOuterUltraWideCamera and .builtInInnerUltraWideCamera. Pass AVCaptureDeviceDescriptor to a capture actor; don’t call AVFoundation from the change handler. Mirror using the map, not position, and disable automaticallyAdjustsVideoMirroring before setting isVideoMirrored.

How do I put camera UI on the outer display with CameraCaptureAccessory?

Put supplementary UI on the OUTER display while the camera stays full screen on the INNER display, only when you are full screen with an active camera session. In SwiftUI use .sceneAccessory { CameraCaptureAccessory(isEnabled:) { ... }.onAvailabilityChange { } }. In UIKit call UISceneAccessory.cameraCapture(sceneConfiguration:userInfo:) then register and unregister. The system controls availability (closing the device withdraws it). It is not a duplicate of the full Camera UI.

Can I mirror the camera viewfinder to the outer display?

Yes. A camera app can mirror the viewfinder to iPhone Duo's outer display so subjects can see themselves while the photographer uses the inner display, using the same multi-scene approach as any other outer-display feature.

How to keep preview level across Duo poses/displays?

Use AVCaptureDevice.RotationCoordinator (AVCaptureDeviceRotationCoordinator). Recreate it when switching cameras; Duo display moves also change the angle. Read videoRotationAngleForHorizonLevelPreview and videoRotationAngleForHorizonLevelCapture before starting KVO — KVO only notifies later changes. Preview and capture angles can differ. After adopting the rotation coordinator, disable camera sensor orientation correction (Apple says this correction is on for all Duo front cameras). Don’t lock orientation at launch.

Should I lock capture orientation to the device orientation at launch?

No — don’t lock it at launch. Use AVCaptureDevice.RotationCoordinator, read the current preview and capture angles before starting KVO, and apply them to the preview layer and photo output. Duo poses and display moves change the angle more often than on a typical iPhone. Don’t mistake .front for user-facing either — that is what AVCaptureDeviceDirectionCoordinator is for.

How should the camera viewfinder resize on iPhone Duo?

Size AVCaptureVideoPreviewLayer to the current view bounds rather than a fixed aspect ratio tied to a specific device, so the preview resizes correctly as the device folds and unfolds.

Apps using Duo Camera