Android 16以上をターゲットにすると対応が必要になる 予測型「戻る」って何？

Android 16 の公開が間近に迫ってきている中、公式ドキュメントを見ていると気になる項目が。

https://developer.android.com/about/versions/16/behavior-changes-16?hl=ja

> 予測型「戻る」に移行またはオプトアウトが必要
>
> Android 16（API レベル 36）以上をターゲットとし、Android 16 以降のデバイスで実行されるアプリの場合、予測型「戻る」システム アニメーション（ホーム画面への戻る、タスク間、アクティビティ間）はデフォルトで有効になっています。また、onBackPressed は呼び出されず、KeyEvent.KEYCODE_BACK はディスパッチされなくなりました。

そもそも予測型「戻る」って何…？となった私のような人のために、ざっくり概要だけまとめてお伝えしていこうと思います。

## 予測型「戻る」ジェスチャーとは一体何？

https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture?hl=ja

私は以前、名前だけ聞いたときに「戻るを押したら、AI的な何かでいい感じの画面に戻すのか…？」とか思いましたが全然そんなことはなく、単に「戻り先がちらっと見えるようになるよ」というだけの機能です。英語だと`predictive back gesture`とか呼称されています。最近３ボタンナビゲーションでもできるようになりましたね。

見たことがない人向けに。「戻る」ジェスチャー後、ホールドすると戻る画面のプレビューが出るようになります。

|ジェスチャー ナビゲーション|3ボタン ナビゲーション|
|---|---|
|![Screen_recording_20250322_183624-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/721314/533d278d-1cfa-4ac5-9be7-419131a101ca.gif)|![Screen_recording_20250322_183533-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/721314/fb3260b0-e47b-4f68-974e-7b2f86033d56.gif)|
(環境: Pixel 8a, Android 16 Beta 3)

普段触っている範疇でこのような挙動をするアプリはまだ見たことがないので、対応しているアプリはまだ少ないんだろうなあ。

## オプトイン方法

画面ごとにどういう動きをするか、実際に自分のアプリで確認してみるのが一番手っ取り早いです。

`targetSDK`を35以下に指定している場合はデフォルト状態ではオフになっているので、`AndroidManifest.xml`に以下のフラグを追加します。

```xml:AndroidManifest.xml
<application
    ...
    android:enableOnBackInvokedCallback="true"
    ... >
...
</application>
```

`targetSDK`を36以上に指定している場合、上記フラグはデフォルトで`true`になっているようなので、`targetSDK`を36に変更するだけでも勝手にオプトインされます。

ちなみに、activityレベルでも有効・無効を切り替えられます。

```xml:AndroidManifest.xml
<manifest ...>
    <application . . .

        android:enableOnBackInvokedCallback="false">

        <activity
            android:name=".MainActivity"
            android:enableOnBackInvokedCallback="true"
            ...
        </activity>
        <activity
            android:name=".SecondActivity"
            android:enableOnBackInvokedCallback="false"
            ...
        </activity>
    </application>
</manifest>
```

私の確認したプロジェクトでは特にエラー等は出ずに有効化できました。
思ってたより簡単に予測型「戻る」ができるようになりましたね。

## 対応が必要な箇所

対応が必要な部分のメモをしておきます。対応の参考になれば幸いです。

### ダイアログでは有効化されない

ダイアログの場合はプレビューのアニメーションをしませんでした。通常のダイアログの利用においては、ダイアログの後ろはシャドーがかかった状態で見えているのでこれで自然な挙動ですが、一部の画面では全画面表示されるダイアログを利用しており、全画面ダイアログの場合は他の画面と挙動が揃わなくなってしまうので若干違和感が出てしまいます。

### `onBackPressed` が呼ばれない

冒頭でさらっと書きましたが、ここが場合によっては一番対応が大変なところかなあと思います(公式でも予測型「戻る」のページにサラッと書いてある。まあしばらく前からDeprecatedでしたが…)。

`android:enableOnBackInvokedCallback`を有効化した場合の作用として、`onBackPressed`が呼ばれなくなります。`onBackPressed`をオーバーライドして色々しているプロジェクトでは、ビルドエラーになったりはしてくれないので対応漏れをすると挙動が変わってしまう可能性があるので、有効化する際には注意が必要です。

また、同じく`KeyEvent.KEYCODE_BACK`で戻るイベントのインターセプトもできなくなります。

ここは素直に`OnBackPressedCallback`などで置き換えましょう。

https://developer.android.com/guide/navigation/custom-back?hl=ja

### コールバックを有効化すると予測型アニメーションは実行されない

`onBackPressedCallback`に置き換えたとして、コールバックを有効化すると予測型アニメーションが実行されなくなります。なんとまあ。そのため、ログ送信などほかの箇所でも代替可能な処理は移してコールバックを使わないようにするかなど、対応方針は検討した方が良さそうです。
(「戻る」ジェスチャーをときに、「なんか挟まれてるぞ！」ってわかるようになっちゃいますね。どうなんだろう。)

ベストプラクティスについて公式でまとめられているので、こちらを参照してください。

https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture?hl=ja#best-practices

## さいごに

一応オプトアウトの方法も紹介しておきます。方法としてはシンプルで、`enableOnBackInvokedCallback`フラグを`false`にしておけば`targetSDK`を36にしても予測型「戻る」を無効化できます。そのため、`targetSDK`を上げるだけであればオプトアウトしてしまうのが一番楽ではあります。

```xml:AndroidManifest.xml
<application
    ...
    android:enableOnBackInvokedCallback="false"
    ... >
...
</application>
```

ただ、上記方法はあくまでその場しのぎの手段ですので、調査と対応を優先的に進めておいたほうが良いと思います(特に、`onBackPressed`がまだ残っている箇所は置き換えを急いだほうがよさそうです)。Android 16 ではしごを外される edge-to-edge のオプトアウトのように…。

https://developer.android.com/develop/ui/views/layout/edge-to-edge?hl=ja