Skip to content

Commit d78d4be

Browse files
[Android] Updating breaking change page on restricting engine config flags (#13931)
_Description of what this PR is changing or adding, and why:_ Adds some corrections +renames to a breaking change page on restricting engine config flags for Android. _Issues fixed by this PR (if any):_ Part of flutter/flutter#190461 _PRs or commits this PR depends on (if any):_ flutter/flutter#191924 (but this can land at any time) ## Presubmit checklist - [x] If you are unwilling, or unable, to sign the CLA, even for a _tiny_, one-word PR, please file an issue instead of a PR. - [x] If this PR is not meant to land until a future stable release, mark it as draft with an explanation. - [x] This PR follows the [Google Developer Documentation Style Guidelines](https://developers.google.com/style)—for example, it doesn't use _i.e._ or _e.g._, and it avoids _I_ and _we_ (first-person pronouns). - [x] This PR uses [semantic line breaks](https://github.com/dart-lang/site-shared/blob/main/doc/writing-for-dart-and-flutter-websites.md#semantic-line-breaks) of 80 characters or fewer. --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent ab59c61 commit d78d4be

4 files changed

Lines changed: 276 additions & 164 deletions

File tree

‎sites/docs/firebase.json‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@
226226
{ "source": "/release/release-notes/changelogs/changelog-1.17.0", "destination": "/release/release-notes/release-notes-1.17.0", "type": 301 },
227227
{ "source": "/release/release-notes/supported-platforms", "destination": "/reference/supported-platforms", "type": 301 },
228228
{ "source": "/release/breaking-changes/can-request-focus", "destination": "https://github.com/flutter/flutter/issues/149067", "type": 301 },
229+
{
230+
"source": "/release/breaking-changes/restrict-command-line-flags-prebuilt-android-release-binaries",
231+
"destination": "/release/breaking-changes/restrict-android-engine-flags-release-mode",
232+
"type": 301
233+
},
229234
{ "source": "/release/breaking-changes/scrollable_alert_dialog", "destination": "/release/breaking-changes/scrollable-alert-dialog", "type": 301 },
230235
{ "source": "/release/breaking-changes/uiscene-lifecycle-ios", "destination": "/release/breaking-changes/uiscenedelegate", "type": 301 },
231236
{ "source": "/release/breaking-changes/win_lifecycle_process_function", "destination": "/release/breaking-changes/win-lifecycle-process-function", "type": 301 },

‎sites/docs/src/content/release/breaking-changes/index.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ They're sorted by release and listed in alphabetical order:
3838

3939
* [Added enabled property and made onChanged optional for DropdownButton][]
4040
* [Migrate to standalone `material_ui` and `cupertino_ui` packages][]
41-
* [Restrict command-line flags for prebuilt Android release binaries][]
41+
* [Restrict Android engine flags in release mode][]
4242
* [Removal of `useInheritedMediaQuery`][]
4343

4444
[Added enabled property and made onChanged optional for DropdownButton]: /release/breaking-changes/dropdownbutton-enabled-property
4545
[Migrate to standalone `material_ui` and `cupertino_ui` packages]: /release/breaking-changes/material-ui-and-cupertino-ui
46-
[Restrict command-line flags for prebuilt Android release binaries]: /release/breaking-changes/restrict-command-line-flags-prebuilt-android-release-binaries
46+
[Restrict Android engine flags in release mode]: /release/breaking-changes/restrict-android-engine-flags-release-mode
4747
[Removal of `useInheritedMediaQuery`]: /release/breaking-changes/remove-useInheritedMediaQuery
4848

4949
<a id="released-in-flutter-347" aria-hidden="true"></a>
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
---
2+
title: Restrict Android engine flags in release mode
3+
description: >-
4+
Passing engine configuration flags to Android release binaries using
5+
Android `Intent` extras or `--use-application-binary` is no longer supported.
6+
---
7+
8+
{% render "docs/breaking-changes.md" %}
9+
10+
## Summary
11+
12+
Previously, the Flutter Android embedding accepted engine configuration flags
13+
(such as `--dart-flags`, `--route`, or tracing flags)
14+
at launch time through Android `Intent` extras in all build modes.
15+
This mechanism allowed developers and tools—including the Flutter CLI
16+
when using `--use-application-binary`—to dynamically configure
17+
running applications without modifying their source code or manifest.
18+
19+
To protect production applications against `Intent`-based spoofing
20+
and parameter injection vulnerabilities,
21+
Flutter Android release builds now ignore engine configuration flags
22+
passed through `Intent` extras,
23+
reading engine configuration strictly from the compiled `AndroidManifest.xml`
24+
or from programmatic configuration prior to engine initialization.
25+
26+
This change impacts workflows in two ways:
27+
28+
- **Direct `Intent` launches:**
29+
Passing engine configuration flags through `Intent` extras
30+
(such as through `adb shell am start` or native Android code)
31+
is ignored by the embedding in release builds.
32+
- **Flutter CLI prebuilt binaries:**
33+
Because prebuilt binaries cannot have their manifests dynamically modified
34+
after compilation, the Flutter CLI now produces a fatal error
35+
if you pass engine configuration flags to a prebuilt release binary
36+
with `flutter run --release --use-application-binary`.
37+
This prevents flags from being silently ignored.
38+
39+
Standard release builds
40+
(where the CLI compiles the app with Gradle and injects flags into the manifest)
41+
and all debug and profile workflows continue to work without changes.
42+
43+
## Context
44+
45+
The Flutter engine accepts configuration flags
46+
(such as `--dart-flags`, `--route`, or `--trace-startup`)
47+
to configure runtime behavior when running or driving an application.
48+
Historically, the Flutter Android embedding accepted these flags at runtime
49+
through [`Intent`][] extras.
50+
Both developers (using `adb shell am start` or native code)
51+
and the Flutter CLI (via `adb`) relied on `Intent` extras
52+
to pass flags to running apps.
53+
54+
However, runtime `Intent` extras on Android can be spoofed or intercepted
55+
by other applications on a user's device.
56+
Allowing arbitrary engine flags in production builds presents
57+
security vulnerabilities, such as dynamic parameter injection attacks
58+
(for example, spoofing `--aot-shared-library-name`).
59+
60+
To harden production applications, Flutter establishes
61+
a build-mode-specific trust boundary:
62+
63+
- **Release mode:**
64+
Production application boundaries are treated as immutable.
65+
The Android embedding ignores engine configuration flags passed
66+
through `Intent` extras and logs a warning.
67+
Release builds read configuration strictly from a signed
68+
`AndroidManifest.xml` or from programmatic setup before engine startup.
69+
- **Debug and profile modes:**
70+
Dynamic `Intent` flag support is intentionally maintained
71+
to preserve developer velocity, dynamic benchmarking,
72+
and local testing workflows.
73+
74+
For release builds of standard Gradle-based projects,
75+
the Flutter CLI automatically injects command-line flags
76+
into `AndroidManifest.xml` during compilation.
77+
When you use a prebuilt release binary with `--use-application-binary`,
78+
the CLI cannot modify the compiled manifest,
79+
and the binary ignores runtime `Intent` flags.
80+
To prevent tests or scripts from running with unnoticed configuration failures,
81+
the CLI reports a fatal error.
82+
83+
Similarly, any automated scripts, test runners, or host applications
84+
that directly construct Android `Intent`s with configuration extras
85+
will find those flags ignored when launching a release binary.
86+
87+
[`Intent`]: https://developer.android.com/reference/android/content/Intent
88+
89+
## Description of change
90+
91+
### Android embedding behavior
92+
93+
The Flutter Android embedding enforces the following behavior
94+
when receiving engine configuration flags through Android `Intent` extras
95+
(such as from `adb shell am start` or native `Intent.putExtra()` calls):
96+
97+
| Build mode | Intent extras behavior | Notes |
98+
| :--- | :--- | :--- |
99+
| **Debug / Profile** | Accepted and parsed | Flags apply dynamically at launch time. |
100+
| **Release** | **Ignored** | The embedding logs a warning and discards all engine configuration flags received from `Intent` extras. |
101+
102+
In addition, the internal interface method
103+
`FlutterActivityAndFragmentDelegate.Host.getFlutterShellArgs` is deprecated
104+
in favor of `getFlutterEngineFlags()`.
105+
106+
### Flutter CLI behavior
107+
108+
The Flutter CLI enforces the following behavior
109+
when running Flutter apps on Android:
110+
111+
| Build mode | Using `--use-application-binary` | CLI behavior | Notes |
112+
| :--- | :--- | :--- | :--- |
113+
| **Debug / Profile** | Yes | Passes flags to binary through `adb` | No rebuild required; flags apply at runtime. |
114+
| **Debug / Profile** | No | Builds and passes flags through `adb` | Standard development workflow. |
115+
| **Release** | Yes | **Fatal error** if configuration flags are provided | Prebuilt release binaries cannot be dynamically configured. |
116+
| **Release** | No | Injects flags into `AndroidManifest.xml` during compilation | Standard release build workflow. |
117+
118+
## Migration guide
119+
120+
:::note
121+
You are **not affected** and do not need to take action if:
122+
- You build and run standard release apps with the Flutter CLI
123+
(`flutter run --release`, `flutter build apk --release`,
124+
or `flutter build appbundle`).
125+
- You run tests and benchmarks in **debug** or **profile** mode.
126+
- You use `--use-application-binary` without passing engine configuration flags.
127+
:::
128+
129+
You are **affected** if:
130+
- You launch release builds using Android `Intent` extras directly
131+
(such as with `adb shell am start` or custom launch intents in native code)
132+
to pass engine configuration flags or route arguments.
133+
- Your CI/CD pipelines, automated scripts, or test runners pass flags
134+
to prebuilt release binaries using `--use-application-binary`.
135+
- You build Flutter Android applications using non-Gradle or hermetic build
136+
systems (such as Bazel) and configure release binaries with launch-time flags.
137+
138+
If your workflows are affected, use one of the following migration paths:
139+
140+
### Switch testing and benchmarking to profile mode
141+
142+
If your automated test pipelines, scripts, or benchmarks pass flags
143+
to release binaries dynamically at launch time:
144+
145+
1. Switch your test target to **profile mode** (`--profile`).
146+
Profile mode mirrors release performance characteristics
147+
while retaining support for dynamic runtime flag configuration
148+
through `Intent` extras and the Flutter CLI without recompilation.
149+
150+
### Configure direct Intent launches and hermetic build systems
151+
152+
If you launch release builds using Android `Intent`s directly
153+
(for example, via `adb shell am start` or custom test runners),
154+
or if you build Flutter Android apps with non-Gradle or hermetic build systems
155+
(such as Bazel) that separate compilation from execution:
156+
157+
1. **Do not rely on `Intent` extras for release builds.**
158+
Any engine flags passed in `Intent` extras to a release binary
159+
are silently ignored by the embedding at runtime.
160+
1. **Use profile mode for dynamic testing:**
161+
For integration tests or performance benchmarks that require
162+
varying flags dynamically at launch time, compile and run
163+
a **profile** build instead of a release build.
164+
1. **Declare flags statically in `AndroidManifest.xml`:**
165+
If you must run a release binary with specific engine flags,
166+
statically declare those flags in your `AndroidManifest.xml`
167+
before compiling the release binary.
168+
For details, refer to
169+
[Declare engine flags in `AndroidManifest.xml`](#declare-engine-flags-in-manifest).
170+
171+
### Build release binaries with flags directly using the Flutter CLI
172+
173+
If you must run tests against a release binary with the Flutter CLI:
174+
175+
1. Run `flutter build` or `flutter run` with your configuration flags
176+
without `--use-application-binary`.
177+
The CLI automatically embeds the flags into the compiled manifest.
178+
1. Alternatively, compile separate release binaries
179+
for each required configuration.
180+
181+
### Configure engine flags programmatically in native host code
182+
183+
If you launch Flutter from native Android code
184+
(such as in an add-to-app integration or custom native activity)
185+
and previously passed engine flags through `Intent` extras:
186+
187+
1. **Override `getFlutterEngineFlags()`:**
188+
If you subclass `FlutterActivity` or `FlutterFragment`, override
189+
`getFlutterEngineFlags()` instead of using `Intent` extras
190+
or the deprecated `getFlutterShellArgs()`:
191+
192+
```kotlin
193+
class MyFlutterActivity : FlutterActivity() {
194+
override fun getFlutterEngineFlags(): List<String> {
195+
val flags = super.getFlutterEngineFlags().toMutableList()
196+
flags.add("--trace-startup")
197+
return flags
198+
}
199+
}
200+
```
201+
202+
1. **Use `FlutterFragment.NewEngineFragmentBuilder`:**
203+
If you host a `FlutterFragment`, pass flags using the builder:
204+
205+
```kotlin
206+
val fragment = FlutterFragment.withNewEngine()
207+
.flutterEngineFlags(listOf("--trace-startup"))
208+
.build<FlutterFragment>()
209+
```
210+
211+
1. **Pre-initialize and cache a `FlutterEngine`:**
212+
If you manage the engine lifecycle directly, supply engine arguments
213+
to the `FlutterEngine` constructor:
214+
215+
```kotlin
216+
val args = arrayOf("--trace-startup", "--enable-impeller=true")
217+
val flutterEngine = FlutterEngine(context, args)
218+
FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine)
219+
```
220+
221+
### Declare engine flags in manifest
222+
223+
To configure engine flags statically in release builds,
224+
add `<meta-data>` elements under the `<application>` tag in
225+
your `android/app/src/main/AndroidManifest.xml` file:
226+
227+
```xml title="AndroidManifest.xml" highlightLines=6-12
228+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
229+
<application
230+
android:label="my_app"
231+
android:name="${applicationName}"
232+
android:icon="@mipmap/ic_launcher">
233+
<!-- Declare engine configuration flags statically -->
234+
<meta-data
235+
android:name="io.flutter.embedding.android.DartFlags"
236+
android:value="--some-dart-flag" />
237+
<meta-data
238+
android:name="io.flutter.embedding.android.EnableDartProfiling"
239+
android:value="false" />
240+
<activity
241+
...
242+
</activity>
243+
</application>
244+
</manifest>
245+
```
246+
247+
## Timeline
248+
249+
Landed in version: TBD<br>
250+
In stable release: TBD
251+
252+
## References
253+
254+
Relevant issues:
255+
256+
* [Issue 180686][]
257+
* [Issue 190461][]
258+
259+
Relevant pull requests:
260+
261+
* [PR 190870][]
262+
* [PR 191328][]
263+
* [PR 191924][]
264+
265+
[Issue 180686]: https://github.com/flutter/flutter/issues/180686
266+
[Issue 190461]: https://github.com/flutter/flutter/issues/190461
267+
[PR 190870]: https://github.com/flutter/flutter/pull/190870
268+
[PR 191328]: https://github.com/flutter/flutter/pull/191328
269+
[PR 191924]: https://github.com/flutter/flutter/pull/191924

0 commit comments

Comments
 (0)