ローソンデジタルイノベーション テックブログ

ローソンデジタルイノベーション(LDI)の技術ブログです

iOSエンジニアの挑戦:iPhone端末カメラ問題の解決

はじめに

iOSエンジニアの譚です。 今回は開発中に遭遇したiPhone端末のカメラピント問題とその対応について紹介させていただきます。

開発環境

  • Xcode 15
  • iOS 17
  • iPhone 12 Pro Max, iPhone 15, iPhone 15 Pro Max

ピント問題とその対応

今回発生した問題は以下の二つになります。

  • デフォルトで起動された広角カメラのピントが合わない問題
  • システムAPIより起動された超広角カメラのバーコードが読み取りづらい問題

その1: デフォルトで起動された広角カメラのピントが合わない問題

発生した問題

現在ローソンアプリではQRコードとバーコードをスキャンする機能が搭載しております。 そこで、iPhone 15 Pro Maxでコードを読み取る際に、カメラを被写体に近づくとピントが合わない問題が発見されました。

iPhone 15 Proのピント合わせなかったカメラプレビュー
ピント合わないプレビュー

問題に対する調査

調査を行い、カメラデバイスの指定に問題があることがわかりました。 今までのiPhoneでカメラを起動する指定は以下になります。

AVCaptureDevice.default(for: .builtInWideAngleCamera)

現在販売中のiPhoneでは、この指定方法に失敗することがなく、デフォルトのカメラデバイス(広角)が起動されます。 しかし、iPhone 14 Proから(Maxも含む)広角カメラの焦点距離が長くなり、被写体に広角カメラを近づくとピントが合わせなくなります。バーコードやQRコードを読み取る時に、解析できない画像データになってしまいました。

調査結果による対応

そこで、Appleエンジニアさんのご提案の通りに、カメラデバイスの起動指定をできるだけ端末に一番合わせるものを選択するように修正を行いました。

        // できるだけ機能が豊富なカメラタイプを指定したい。
        if let device = AVCaptureDevice
            .default(.builtInTripleCamera, for: .video, position: .back) {
            captureDevice = device
        } else if let device = AVCaptureDevice
            .default(.builtInDualWideCamera, for: .video, position: .back) {
            captureDevice = device
        } else if let device = AVCaptureDevice
            .default(.builtInDualCamera, for: .video, position: .back) {
            captureDevice = device
        } else {
            // フォールバックとして、デフォルトのバックカメラを使う
            captureDevice = AVCaptureDevice.default(for: .builtInWideAngleCamera, position: .back)
        }

iPhone 15 Proのピント合わせたカメラプレビュー
修正後ピントが合わせたプレビュー

その2: システムAPIより起動された超広角カメラのバーコードが読み取りづらい問題

その1の対応で問題が解決したと思いましたが、修正したことで別の問題が発生することが分かりました。

iPhone 12 Pro Max / デュアルカメラ(超広角+広角)ではバーコードが読み取りづらくなる問題

iPhone 12 Pro MaxはbuiltInTripleCameraで起動するようになります。builtInTripleCameraで起動したカメラは超広角カメラになっていますが、iPhone 12 Pro Maxの超広角カメラには後継デバイスで搭載しているマクロモード機能がないため、被写体に近づいてもくっきりとする画像になっていません。

iPhone 15のような超広角カメラ+広角カメラのデュアルカメラ端末は、builtInDualWideCameraでカメラを起動します。これも、builtInTripleCameraで起動されたカメラデバイスと同じくシステムより超広角カメラを利用するようになっています。現時点、販売中のデュアルカメラ端末の超広角カメラはiPhone 12 Pro Maxと同様にマクロモードにサポートしていないため、被写体に近づいても、画像が綺麗に映りません。

問題の対応

上記の問題に対して、デフォルトのbuiltInWideAngleCameraにフォールバックするように対応しました。 コード上は以下のイメージです。

        if let device = AVCaptureDevice
            .default(.builtInTripleCamera, for: .video, position: .back) {
            captureDevice = matchAppropriateDevice(from: device)
        } else if let device = AVCaptureDevice
            .default(.builtInDualCamera, for: .video, position: .back) {
            captureDevice = device
        } else {
             // フォールバックとして、デフォルトのバックカメラ(広角)を使う
            captureDevice = AVCaptureDevice.default(for: .builtInWideAngleCamera, position: .back)
        }

    private func matchAppropriateDevice(from device: AVCaptureDevice) -> AVCaptureDevice {
        let machineName = // 起動中の端末種類を取得しておく

        // フォールバックすべき端末一覧
        let machinesShouldUseDefaultWideAngleCamera = [
            "iPhone13,3", // iPhone 12 Pro
            "iPhone13,4", // iPhone 12 Pro Max
        ]
        if machinesShouldUseDefaultWideAngleCamera.contains(machineName),
           let wideAngleCameraDevice = device.constituentDevices.first(where: { $0.deviceType == .builtInWideAngleCamera }) {
            // wide angle(広角)デバイスに切り替える。
            return wideAngleCameraDevice
        } else {
            return device
        }
    }

最後に

アプリ側でiPhone端末のカメラを利用する際は、いままでデバイスタイプを気にする必要はありませんでした。

しかし、近年ではカメラ性能がアップしたデバイスに搭載され、カメラがうまく動作しないケースも発生するように なってきたため、カメラデバイスタイプの指定が必要になってきました。

どのタイプを指定すべきかに関して、特定なパターンがなく、調査・テストをしながら確認するしかないと思われます。