Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,40 @@ The simplest integration path uses a new `FlutterEngine`,
which comes with a non-trivial initialization time,
leading to a blank UI until Flutter is
initialized and rendered the first time.
Most of this time overhead can be avoided by using
a cached, pre-warmed `FlutterEngine`, which is discussed next.
Most of this time overhead can be avoided by using a cached, pre-warmed
`FlutterEngine`, which is discussed in
[Using a pre-warmed `FlutterEngine`](#using-a-pre-warmed-flutterengine).

### Automatic back button and predictive back handling

When embedding a `FlutterFragment` into a native Android app on Android 13 or
higher (API level 33+), you can configure the fragment to automatically handle
system back button presses and predictive back gestures without manually
forwarding `onBackPressed()`.
Comment thread
jesskuras marked this conversation as resolved.

Instead of overriding `onBackPressed` as shown above, set
`shouldAutomaticallyHandleOnBackPressed(true)` when building your fragment:

<Tabs key="android-language">
<Tab name="Kotlin">

```kotlin
val flutterFragment = FlutterFragment.withNewEngine()
.shouldAutomaticallyHandleOnBackPressed(true)
.build()
```

</Tab>
<Tab name="Java">

```java
FlutterFragment flutterFragment = FlutterFragment.withNewEngine()
.shouldAutomaticallyHandleOnBackPressed(true)
.build();
```

</Tab>
</Tabs>

## Using a pre-warmed `FlutterEngine`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,80 @@
title: Add the predictive-back gesture
shortTitle: Predictive-back
description: >-
Learn how to add the predictive back gesture to your Android app.
Learn how to enable and handle Android predictive back gestures in Flutter.
---

This feature has landed in Flutter,
but it's not enabled by default in Android itself yet.
You can try it out using the following instructions.
The Android predictive back gesture lets users preview
where a back gesture will navigate to,
whether that's the previous screen or the home screen,
before they commit to or cancel it.

## Configure your app
## Overview

Make sure your app supports Android API 33 or higher,
as predictive back won't work on older versions of Android.
Then, set the flag `android:enableOnBackInvokedCallback="true"`
in `android/app/src/main/AndroidManifest.xml`.
Starting with Android 14 (API level 34), predictive back animations are
enabled by default for system gestures when supported by the application.
Flutter provides built-in support for predictive back animations across
default page route transitions and custom pop handling.

## Configure your device
## Enable predictive back in Android

You need to enable Developer Mode and set a flag on your device,
so you can't yet expect predictive back to work on most users'
Android devices. If you want to try it out on your own device though,
make sure it's running API 33 or higher, and then in
**Settings => System => Developer** options,
make sure the switch is enabled next to **Predictive back animations**.
To support predictive back gestures in your Flutter app
on Android 13 or later:

## Set up your app
1. Open `android/app/src/main/AndroidManifest.xml`.
2. Add `android:enableOnBackInvokedCallback="true"` to the `<application>` tag:

The predictive back route transitions are currently
not enabled by default, so for now you'll need to enable them
manually in your app.
Typically, you do this by setting them in your theme:

```dart
MaterialApp(
theme: ThemeData(
pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
// Set the predictive back transitions for Android.
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
},
),
),
...
),
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="my_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true">
<!-- ... -->
</application>
</manifest>
```

## Run your app
## Handle back gestures with PopScope

To customize back navigation or prevent users from accidentally leaving a
screen, use the [`PopScope`]({{site.api}}/flutter/widgets/PopScope-class.html)
widget. `PopScope` replaces the deprecated `WillPopScope` widget and
supports predictive back gestures.

### Callback parameters

Lastly, just make sure you're using at least
Flutter version 3.22.2 to run your app,
which is the latest stable release at the time of this writing.
`PopScope` uses the `onPopInvokedWithResult` callback:

## For more information
* `didPop`: A boolean indicating whether the pop operation succeeded.
If `canPop` is `false`, `didPop` is `false`.
* `result`: An optional return payload passed when popping the route
(for example, with `Navigator.pop(context, result)`).

### Example: Intercepting back navigation
Comment thread
jesskuras marked this conversation as resolved.

```dart
PopScope(
canPop: false,
onPopInvokedWithResult: (bool didPop, Object? result) async {
if (didPop) {
return;
}
final shouldLeave = await _showExitConfirmationDialog(context);
if (shouldLeave && context.mounted) {
Navigator.of(context).pop(result);
}
},
child: Scaffold(
appBar: AppBar(title: const Text('Form Screen')),
body: const Center(child: Text('Complete the form before leaving.')),
),
)
```

You can find more information at the following link:
## More information

* [Android predictive back][] breaking change
For more details on API migrations, check out the
Comment thread
jesskuras marked this conversation as resolved.
[Android predictive back migration guide](
/release/breaking-changes/android-predictive-back).

[Android predictive back]: /release/breaking-changes/android-predictive-back
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ whether it was successful.
The `PopScope` class directly replaces `WillPopScope` in order to enable
predictive back. Instead of deciding whether a pop is possible at the time it
occurs, this is set ahead of time with the `canPop` boolean. You can still
listen to pops by using `onPopInvoked`.
listen to pops by using `onPopInvokedWithResult`.

```dart
PopScope(
canPop: _myPopDisableEnableLogic(),
onPopInvoked: (bool didPop) {
onPopInvokedWithResult: (bool didPop, Object? result) {
// Handle the pop. If `didPop` is false, it was blocked.
},
)
```

### Form.canPop and Form.onPopInvoked
### Form.canPop and Form.onPopInvokedWithResult

These two new parameters are based on `PopScope` and replace the deprecated
`Form.onWillPop` parameter. They are used with `PopScope` in the same way as
Expand All @@ -69,7 +69,7 @@ above.
```dart
Form(
canPop: _myPopDisableEnableLogic(),
onPopInvoked: (bool didPop) {
onPopInvokedWithResult: (bool didPop, Object? result) {
// Handle the pop. If `didPop` is false, it was blocked.
},
)
Expand Down Expand Up @@ -135,11 +135,11 @@ PopScope(
```

For cases where it's necessary to be notified that a
pop was attempted, the `onPopInvoked` method can be
pop was attempted, the `onPopInvokedWithResult` method can be
used in a similar way to `onWillPop`. Keep in mind
that while `onWillPop` was called before the pop
was handled and had the ability to cancel it,
`onPopInvoked` is called after the pop is finished being handled.
`onPopInvokedWithResult` is called after the pop is finished being handled.

Code before migration:

Expand All @@ -158,7 +158,7 @@ Code after migration:
```dart
PopScope(
canPop: true,
onPopInvoked: (bool didPop) {
onPopInvokedWithResult: (bool didPop, Object? result) {
_myHandleOnPopMethod();
},
child: ...
Expand Down Expand Up @@ -197,12 +197,12 @@ NavigatorPopHandler(
)
```

### Migrating from Form.onWillPop to Form.canPop and Form.onPopInvoked
### Migrating from Form.onWillPop to Form.canPop and Form.onPopInvokedWithResult

Previously, `Form` used a `WillPopScope` instance under
the hood and exposed its `onWillPop` method.
This has been replaced with a `PopScope` that exposes its
`canPop` and `onPopInvoked` methods.
`canPop` and `onPopInvokedWithResult` methods.
Migrating is identical to migrating from
`WillPopScope` to `PopScope`, detailed above.

Expand Down Expand Up @@ -326,7 +326,7 @@ Code after migration:
```dart
return PopScope(
canPop: false,
onPopInvoked: (bool didPop) async {
onPopInvokedWithResult: (bool didPop, Object? result) async {
if (didPop) {
return;
}
Expand All @@ -342,22 +342,9 @@ return PopScope(

### Supporting predictive back

1. Run Android 14 (API level 34) or above.
1. Enable the feature flag for predictive back on
the device under "Developer options".
This will be unnecessary on future versions of Android.
1. Set `android:enableOnBackInvokedCallback="true"` in
`android/app/src/main/AndroidManifest.xml`.
If needed, refer to
[Android's full guide]({{site.android-dev}}/guide/navigation/custom-back/predictive-back-gesture).
for migrating Android apps to support predictive back.
1. Make sure you're using version `3.14.0-7.0.pre`
of Flutter or greater.
1. Make sure your Flutter app doesn't use the
`WillPopScope` widget. Using it disables
predictive back. If needed, use `PopScope` instead.
1. Run the app and perform a back gesture (swipe from the
left side of the screen).
For complete setup instructions, guidelines on predictive back gesture
Comment thread
jesskuras marked this conversation as resolved.
animations, and Android manifest configuration, check out how to [add the
predictive-back gesture](/platform-integration/android/predictive-back).

## Timeline

Expand All @@ -372,7 +359,7 @@ API documentation:
* [`NavigatorPopHandler`][]
* [`PopEntry`][]
* [`Form.canPop`][]
* [`Form.onPopInvoked`][]
* [`Form.onPopInvokedWithResult`][]
* [`Route.popDisposition`][]
* [`ModalRoute.registerPopEntry`][]
* [`ModalRoute.unregisterPopEntry`][]
Expand All @@ -390,7 +377,7 @@ Relevant PRs:
[`NavigatorPopHandler`]: {{site.api}}/flutter/widgets/NavigatorPopHandler-class.html
[`PopEntry`]: {{site.api}}/flutter/widgets/PopEntry-class.html
[`Form.canPop`]: {{site.api}}/flutter/widgets/Form/canPop.html
[`Form.onPopInvoked`]: {{site.api}}/flutter/widgets/Form/onPopInvoked.html
[`Form.onPopInvokedWithResult`]: {{site.api}}/flutter/widgets/Form/onPopInvokedWithResult.html
[`Route.popDisposition`]: {{site.api}}/flutter/widgets/Route/popDisposition.html
[`ModalRoute.registerPopEntry`]: {{site.api}}/flutter/widgets/ModalRoute/registerPopEntry.html
[`ModalRoute.unregisterPopEntry`]: {{site.api}}/flutter/widgets/ModalRoute/unregisterPopEntry.html
Expand Down
8 changes: 7 additions & 1 deletion sites/docs/src/content/ui/navigation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,16 @@ navigates by removing a _page-backed_ route from the Navigator, all _pageless_
routes after (up until the next _page-backed_ route) are removed too.

:::note
You can't prevent navigation from page-backed screens using `WillPopScope`.
You can't prevent navigation from page-backed screens using `PopScope`
or the deprecated `WillPopScope`.
Instead, you should consult your routing package's API documentation.

For guidelines on migrating to `PopScope`,
check out the [Android predictive back migration guide][].
:::

[Android predictive back migration guide]: /release/breaking-changes/android-predictive-back

## Web support

Apps using the `Router` class integrate with the browser History API to provide
Expand Down
Loading