🕶️

iOSアプリのApple Vision Pro互換モード対応

2024/12/09に公開

これは株式会社TimeTree Advent Calendar 2024の9日目の記事です。

こんにちは。iOSエンジニアのgonseeです。

今年の6月末に日本でもApple Vision Proが発売され話題になりましたね。空間コンピューティング (Spacial Computing) というまったく新しい体験が本来の魅力ですが、iPhoneやiPad向けの既存アプリをそのまま動かすこともできます。

基本的にiOSアプリは何もしなくてもvisionOS上の互換モードで動かすことができるのですが、操作系が大きく異なるので、実際に使ってみると使いにくい点が出てくると思います。TimeTreeもApple Vision Proでの動作確認を行い、問題のあった箇所の修正を行いました。その経験をふまえて互換モードでのApple Vision Pro対応のポイントをまとめてみました。

シミュレーターで起動してみる

まずはXcodeからvisionOSシミュレーターを使ってアプリを起動してみましょう。まだvisionOSシミュレーターを導入していない場合は設定のComponentsからダウンロードします。

余談ですが、visionOSは発表前にxrOSと呼ばれていたようで、ふとした拍子にその名残が現れることがあります。

続いて、ターゲットのSupported Destinationに Apple Vision Pro (Designed for iPhone) が追加されている必要があるので確認しましょう。「Designed for iPhone」はiOSアプリを互換モードで動作させることを示しています。

以上の準備が整えば実行先として「Apple Vision Pro (Designed for iPhone)」が選択できます。

実行すると見知らぬ部屋の真ん中にアプリの画面が浮かび上がります。

Hover Effect対応

シミュレーターでアプリを触ってみるとiPhoneとほぼ同じように操作できると思います。じゃあやることなくない?と思われるかもしれませんが、visionOSはシミュレーターと実機で操作感がまったく異なることに注意が必要です。

シミュレーターはマウスを使って操作しますが、実機では視線とジェスチャーを使います。目で見ている先にマウスポインターのようなものは表示されません。代わりに操作対象のオブジェクトが強調表示されます。これをhover effectと呼びます。

こちらはタブバー上のタブに視線を合わせたときのhover effectです。シミュレーターで見るとわずかな差しか感じられないと思いますが、実機で見ると輝度の違いなのかもう少しはっきりした印象になります。ちょっとしたフィードバックですが、これがないと操作対象が今どこなのかがわからず、途端に操作が難しくなります。

UIButtonやSwiftUIのButtonなど、OS標準のUIを使っている場合hover effectは自動的に有効になります。カスタムのビューにGestureRecognizerでタップ時の挙動を実装している場合などは有効にならないので、自身でhover effectを有効にする必要があります。

UIKitではViewの hoverStyle を設定します。

let imageView = UIImageView()
if #available(iOS 17.0, *) {
    imageView.hoverStyle = UIHoverStyle()
}

UIHoverStyle のイニシャライザには init(effect: some UIHoverEffect, shape: UIShape?) も用意されています。effectには .automatic, .highlight, .lift があって、指定しなければ .automatic になり、システムが適切な効果を選択します。shapeはハイライトする部分の形状を指定することができます。

SwiftUIでも同様に hoverEffect というmodifierが用意されています。

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .onTapGesture {
            print("Hello, world!")
        }
        .hoverEffect()
    }
}

実際にTimeTreeでも、メニューを表示するためのカレンダー画像のアイコンが UIImageViewUITapGestureRecognizer を使った実装だったので、 hoverStyle を設定する必要がありました。

ちなみに、hover effectと似たものとしてfocus effectというものもありますが、こちらはリモコンやゲームコントローラー、キーボードなどのインプットデバイスで使われるもので、hoverとは明確に別なものです。詳しくはHIGを参照してください。

https://developer.apple.com/jp/design/human-interface-guidelines/eyes

SwiftUIでHover Effectが効かない問題

対応方法としてはとてもシンプルなので、比較的簡単にvisionOS上でも快適に使えるアプリにできそうです。そんなふうに考えていた時期が私にもありました。

TimeTreeの動作確認をしていて気がついたのですが、UIKitの画面では適切にhover effectが効いているのに、SwiftUIで作った画面ではOS標準のUIを使っている部分も含めてhover effectが効かなかったのです。 .hoverEffect() のmodifierを明示的に付けたりいろいろと試したのですが解決できませんでした。

最終的にフォーラムでAppleのエンジニアに確認したところOS側のバグのようでした。この問題はiPad対応しているアプリが Apple Vision Pro (Designed for iPad) で実行した場合は発生しません。iPhone互換モードの場合のみ発生するようです。visionOS 2.2で確認したところこの問題はまだ継続しています。

これについては修正されるのを待つしかありませんが、同じようにお困りの方はフィードバックアシスタントからバグ報告をしていただくと良いかと思います。

まとめ

visionOSでiOSアプリを起動するだけならば特別な対応は不要ですが、視線を使ったナビゲーションで快適に利用するためにはhover effectが適切に作動することが重要です。

iPhone専用アプリは残念ながらSwiftUIでhover effectが効かないという問題があり、現時点で完全な対応が難しいです。可能であればiPad対応をするのがベストということかもしれません。

最後に、オフィスでApple Vision Proの検証機を使っている様子をお届けして終わりにしたいと思います。ご覧いただきありがとうございました。

TimeTree Tech Blog

Discussion