Loading
BLOG 開発者ブログ

2024年12月13日

Apple Vision Pro(visionOS 2)でEnterprise APIのQRコードスキャンを試してみた

custom_gesture

はじめに

こんにちは。
モバイルソリューショングループのide.tです。

この記事は アイソルート Advent Calendar 2024 13日目の記事です。

Apple Vision Pro(visionOS 2) Enterprise APIのQRコードスキャンについて書きました。
コードはApple公式のサンプルコードを参考に実装しました。以下では実装したコードと動かしてみた動画をお見せします。

目次

  1. Enterprise APIについて
  2. QRコードスキャンのコード
  3. 実機で試してみた動画
  4. さいごに

1. Enterprise APIとは

Apple Vision Pro向けのEnterprise APIとは企業向けのアプリに特化した機能がまとめられた機能群です。
今回の記事で紹介している現実世界のQRコードを読み取る機能はEnterprise APIに含まれる機能を利用する必要があります。
Enterprise APIを利用するには企業アカウントであることとアカウントホルダーがAppleに申請してライセンスファイルを受け取る必要があります。

2. QRコードスキャンのコード

以下が実装したコードです。簡単に解説します。
最初にARKitSessionを初期化し、worldSensingパーミッションを有効にすることでQRコードを検出できるようになります。
その後、BarcodeDetectionProvider()を有効にしARKit SessionにBarcodeDetectionProviderを設定して実行することでメインカメラに映ったQRコードの検出とデコードが実行されるようになります。


import SwiftUI
import RealityKit
import ARKit
import Combine

struct ImmersiveView: View {
    @State private var arkitSession = ARKitSession()
    @State private var root = Entity()
    @State private var fadeCompleteSubscriptions: Set = []

    var body: some View {
        RealityView { content in
            content.add(root)
        }
        .task {
            // Check if barcode detection is supported; otherwise handle this case.
            guard BarcodeDetectionProvider.isSupported else { return }

            await arkitSession.queryAuthorization(for: [.worldSensing])
            // Specify the symbologies you want to detect.
            let barcodeDetection = BarcodeDetectionProvider(symbologies: [.code128, .qr])


            do {
                try await arkitSession.run([barcodeDetection])
                for await update in barcodeDetection.anchorUpdates where update.event == .added {

                    let anchor = update.anchor
                    // Play an animation to indicate the system detected a barcode.
                    playAnimation(for: anchor)

                    // open web site
                    openURL(anchor.payloadString ?? "")

                    // Use the anchor's decoded contents and symbology to take action.
                    print(
                         """
                         Payload: \(anchor.payloadString ?? "")
                         Symbology: \(anchor.symbology)
                         """)
                }
            } catch {
                // Handle the error.
                print(error)
            }
        }
    }

    // Define this function in ImmersiveView.
    func playAnimation(for anchor: BarcodeAnchor) {
        guard let scene = root.scene else { return }

        // Create a plane sized to match the barcode.
        let extent = anchor.extent
        let entity = ModelEntity(mesh: .generatePlane(width: extent.x, depth: extent.z), materials: [UnlitMaterial(color: .green)])
        entity.components.set(OpacityComponent(opacity: 0))

        // Position the plane over the barcode.
        entity.transform = Transform(matrix: anchor.originFromAnchorTransform)
        root.addChild(entity)

        // Fade the plane in and out.
        do {
            let duration = 0.5
            let fadeIn = try AnimationResource.generate(with: FromToByAnimation(
                from: 0,
                to: 1.0,
                duration: duration,
                isAdditive: true,
                bindTarget: .opacity)
            )
            let fadeOut = try AnimationResource.generate(with: FromToByAnimation(
                from: 1.0,
                to: 0,
                duration: duration,
                isAdditive: true,
                bindTarget: .opacity))

            let fadeAnimation = try AnimationResource.sequence(with: [fadeIn, fadeOut])

            _ = scene.subscribe(to: AnimationEvents.PlaybackCompleted.self, on: entity, { _ in
                // Remove the plane after the animation completes.
                entity.removeFromParent()
            }).store(in: &fadeCompleteSubscriptions)

            entity.playAnimation(fadeAnimation)
        } catch {
            // Handle the error.
        }
    }

    func openURL(_ urlString: String) {
        guard let url = URL(string: urlString) else {
            print("Invalid URL")
            return
        }

        Task {
            if await UIApplication.shared.canOpenURL(url) {
                await UIApplication.shared.open(url, options: [:])
            } else {
                print("Cannot open URL")
            }
        }
    }
}  
  

3. 実機で試してみた動画

以下は上記のコードを実機で試してみた動画です。
QRコードを読み取ると読み取り成功を示す緑の四角が描画され、後ろに弊社のコーポレートサイトが表示されました。
メインカメラに映ったQRコードを自動で読み取りwebサイトの表示まで行う実装になっています。

4. さいごに

本記事を閲覧いただきありがとうございます。Enterprise API限定ではありますが、Apple Vision Proを装着して視線を向けるだけで現実のQRコードを読み取ることができるので色々な場面で便利に使える機能ではないでしょうか。例えばお店で品物の情報をQRコードから読み取って素早く取得したり、工場で機械の点検をQRコードを読み取るだけで行えたりなどアイデアが膨らみますね!Enterprise APIを用いたアプリは現状Apple Storeで一般公開することはできないのですが、ビジネスの分野でより有効にApple Vision Proを活用する方向に発展していくのではと予想しています。

idetaのブログ