Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3d83f89
Refactor FlutterShellArgs
camsim99 Feb 10, 2026
be6d388
format
camsim99 Feb 10, 2026
d8ae1db
Apply suggestion from @gemini-code-assist[bot]
camsim99 Feb 10, 2026
00095d6
allow EnableDartProfiling in release mode
camsim99 Feb 11, 2026
16b2dbb
Merge branch 'fix_flutter_shell_args' of github.com:camsim99/flutter …
camsim99 Feb 11, 2026
6bd6535
add test for enable-dart-profiling
camsim99 Feb 11, 2026
66397ed
[Android] Add mechanism for setting Android engine flags via Android …
camsim99 Feb 9, 2026
3c8649f
Merge branch 'fix_flutter_shell_args' into reland_flags
camsim99 Feb 17, 2026
fcccb66
add note about deprecation suppressions
camsim99 Feb 17, 2026
3733474
reduce loops from 2 to 1
camsim99 Feb 17, 2026
9a32c37
add merged-platform-ui-thread
camsim99 Feb 17, 2026
09ab372
add internal flags
camsim99 Feb 18, 2026
ecb6ea0
add all switch_defs and rename manifest file
camsim99 Feb 18, 2026
e546283
add test flag + logs
camsim99 Feb 18, 2026
3f6e95a
add renamed markdown file
camsim99 Feb 18, 2026
421fb77
loop through flags instead of manifest
camsim99 Feb 18, 2026
a2a4908
some good stuff some bad
camsim99 Feb 18, 2026
78fe7c7
undo adding unecessary flags
camsim99 Feb 18, 2026
ff053d3
add back necessary flags
camsim99 Feb 18, 2026
e2f0d28
self review
camsim99 Feb 19, 2026
d6d4a07
small fixes + impeller fix
camsim99 Feb 19, 2026
f7b0c12
self review
camsim99 Feb 23, 2026
8916140
add back flutterloader flags
camsim99 Feb 24, 2026
5fca5fd
handle empty and specified boolean values
camsim99 Feb 24, 2026
659df01
extra test :)
camsim99 Feb 24, 2026
6dc62a7
take matt's suggestion
camsim99 Feb 25, 2026
eb9b5e2
Merge remote-tracking branch 'upstream/master' into reland_flags
camsim99 Feb 25, 2026
6a1bc5b
remove cache_sksl and clarify command line flag availability
camsim99 Feb 27, 2026
45120eb
Merge remote-tracking branch 'upstream/master' into reland_flags
camsim99 Feb 27, 2026
06fb8d9
rework warning
camsim99 Mar 3, 2026
f3e6ff4
Merge remote-tracking branch 'upstream/master' into reland_flags
camsim99 Mar 3, 2026
5c02a63
rework other warning for consistency
camsim99 Mar 4, 2026
ff47dad
Merge remote-tracking branch 'upstream/master' into reland_flags
camsim99 Mar 16, 2026
97c27e9
refactor hcpp
camsim99 Mar 16, 2026
0170936
remove print statement
camsim99 Mar 16, 2026
accedba
remove enable-surface-control
camsim99 Mar 16, 2026
409df0f
minor hcpp correction
camsim99 Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions docs/engine/Flutter-Android-Engine-Flags.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Setting Flutter Android engine flags

You can set flags for the Flutter engine on Android in two different ways:

- From the command line when launching an app with the Flutter tool
- Via `AndroidManifest.xml` metadata (static, per-build configuration)

Flags available on Android may be set via the command line **and/or** via
manifest metadata depending on the flag. See
`src/flutter/shell/platform/android/io/flutter/embedding/engine/`
`FlutterEngineFlags.java` for the list of flags that can be set for
the Android shell, and see `src/flutter/shell/common/switch_defs.h`
for the list of all supported flags.

For flags that can be set on the command line and via the manifest,
see below to determine which method to use.

## When to use manifest metadata versus the command line

Use the manifest when:

- You want a fixed, reproducible baseline of engine flags
for your app across all launches. This is ideal for CI and for enforcing a
consistent configuration for your app.
- You want to vary flags by build mode or product flavor
via manifest merging. For example, place metadata in
`src/debug/AndroidManifest.xml`, `src/profile/AndroidManifest.xml`, and
`src/release/AndroidManifest.xml` (or per-flavor manifests) to tailor flags
per variant.

Use the command line when:

- You want to quickly experiment with a flag for a single run of your app.
- You need to override a flag that is already set in the manifest temporarily for debugging
or testing purposes.

**Note: If a flag is specified both on the command line and in the manifest,
the command-line value takes precedence at runtime.**

See below for details on using each method.

## How to set engine flags from the command line

When you run a standalone Flutter app with the Flutter tool, engine flags
can be passed directly and are forwarded to the Android engine. Examples:

```bash
flutter run --trace-startup \
--enable-software-rendering \
--dart-flags="--enable-asserts"
```

Notes:

- Flags that take values use the `--flag=value` form (with `=`). The Flutter
tool forwards them in that form to the Android embedding.

## How to set engine flags in the manifest

All manifest metadata keys must be prefixed with the package name
`io.flutter.embedding.android` and are suffixed with the metadata name for the
related command line flag as determined in
`src/flutter/shell/platform/android/io/flutter/embedding/engine/`
`FlutterEngineFlags.java`. For example, the `--impeller-lazy-shader-mode=`
command line flag corresponds to the metadata key
`io.flutter.embedding.android.ImpellerLazyShaderInitialization`.

For flags that take values, set the numeric, string, or boolean value (without
the leading `--flag=` prefix).

### Examples

Set the `--trace-to-file=` flag to `some_file.txt`:

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application ...>
<meta-data
android:name="io.flutter.embedding.android.TraceToFile"
android:value="some_file.txt"/>
...
</application>
</manifest>
```

Set the `--enable-flutter-gpu` flag:

```xml
<meta-data
android:name="io.flutter.embedding.android.EnableFlutterGPU"
android:value=true
/>
```

For flags that take boolean values, if you omit a value entirely, it
will be assumed to be true. For example, this is the same as the
example above:

```xml
<meta-data
android:name="io.flutter.embedding.android.EnableFlutterGPU"
/>
```

## Release-mode restrictions

- Some flags are not allowed in release mode. The Android embedding enforces
this policy (see `src/flutter/shell/platform/android/io/flutter/
embedding/engine/FlutterEngineFlags`, which marks allowed flags
with `allowedInRelease`). If a disallowed flag is set in release, it will
be ignored.
- If you need different behavior in release vs debug/profile mode, configure it
via variant-specific manifests or product flavors.

## How to set engine flags dynamically

As of the writing of this document, setting Flutter shell arguments via an
Android `Intent` is no longer supported. If you need per-launch or
runtime-controlled flags in an add-to-app integration, you may do so
programatically before engine initialization.

To do that, supply engine arguments directly to a `FlutterEngine` with the
desired flags from the earliest point you can control in your
application. For example, if you are writing an add-to-app app that launches
a `FlutterActivity` or `FlutterFragment`, then you can cache a
`FlutterEngine` that is initialized with your desired
engine flags:

```kotlin
// Your native Android application
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// Initialize the Flutter engine with desired flags
val args = arrayOf(
"--trace-startup",
"--trace-to-file=some_file.txt",
"--enable-software-rendering"
)
val flutterEngine = FlutterEngine(this, args)

// Start executing Dart code in the FlutterEngine
flutterEngine.dartExecutor.executeDartEntrypoint(
DartEntrypoint.createDefault()
Comment thread
camsim99 marked this conversation as resolved.
)

// Store the engine in the cache for later use
FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine)
}
}
```

Then, your `Activity` can launch a `FlutterActivity` or `FlutterFragment`
with that cached `FlutterEngine`:

```kotlin
// Start a FlutterActivity using the cached engine...
val intent = FlutterActivity.withCachedEngine("my_engine_id").build(this)
startActivity(intent)

// Or launch a FlutterFragment using the cached engine
val flutterFragment = FlutterFragment.withCachedEngine("my_engine_id").build()
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, flutterFragment, TAG_FLUTTER_FRAGMENT)
.commit()
```

For a normal Flutter Android app, you can create and initialize a `FlutterEngine`
with your desired flags the same as in the example above, then override
`provideFlutterEngine` in your app's `FlutterActivity` to provide the
configured `FlutterEngine`. For example:

```kotlin
// Your Flutter Android application
class MyApplication : FlutterApplication() {
override fun onCreate() {
super.onCreate()

val args = arrayOf(
"--trace-startup",
"--trace-to-file=some_file.txt",
"--enable-software-rendering"
)
val flutterEngine = FlutterEngine(this, args)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
.getInstance()
.put(MY_ENGINE_ID, flutterEngine)
}
}
Comment thread
camsim99 marked this conversation as resolved.

// Your Flutter Android Activity
class MainActivity: FlutterActivity() {
override fun provideFlutterEngine(context: Context): FlutterEngine? {
return FlutterEngineCache
.getInstance()
.get(MyApplication.MY_ENGINE_ID)
}
}
```
1 change: 1 addition & 0 deletions engine/src/flutter/shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ android_java_sources = [
"io/flutter/embedding/engine/FlutterEngine.java",
"io/flutter/embedding/engine/FlutterEngineCache.java",
"io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java",
"io/flutter/embedding/engine/FlutterEngineFlags.java",
"io/flutter/embedding/engine/FlutterEngineGroup.java",
"io/flutter/embedding/engine/FlutterEngineGroupCache.java",
"io/flutter/embedding/engine/FlutterJNI.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.FlutterEngineFlags;
import io.flutter.embedding.engine.FlutterEngineGroup;
import io.flutter.embedding.engine.FlutterEngineGroupCache;
import io.flutter.embedding.engine.FlutterShellArgs;
Expand All @@ -38,6 +39,7 @@
import io.flutter.plugin.view.SensitiveContentPlugin;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
* Delegate that implements all Flutter logic that is the same between a {@link FlutterActivity} and
Expand Down Expand Up @@ -331,6 +333,7 @@ private FlutterEngineGroup.Options addEntrypointOptions(FlutterEngineGroup.Optio
"No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
+ " this FlutterFragment.");

warnIfEngineFlagsSetViaIntent(host.getActivity().getIntent());
Comment thread
camsim99 marked this conversation as resolved.
FlutterEngineGroup group =
engineGroup == null
? new FlutterEngineGroup(host.getContext(), host.getFlutterShellArgs().toArray())
Expand All @@ -344,6 +347,32 @@ private FlutterEngineGroup.Options addEntrypointOptions(FlutterEngineGroup.Optio
isFlutterEngineFromHost = false;
}

// As part of https://github.com/flutter/flutter/issues/180686, the ability
// to set engine flags via Intent extras will be removed, so warn
// developers that engine shell arguments set that way will be ignored.
private void warnIfEngineFlagsSetViaIntent(@NonNull Intent intent) {
if (intent.getExtras() == null) {
return;
}

Bundle extras = intent.getExtras();
Set<String> extrasKeys = extras.keySet();

for (String extrasKey : extrasKeys) {
FlutterEngineFlags.Flag flag = FlutterEngineFlags.getFlagFromIntentKey(extrasKey);
if (flag != null) {
Log.i(
TAG,
"If you are attempting to set "
+ flag.engineArgument
+ " via Intent extras to launch a Flutter component outside of using the Flutter CLI, note that support for setting engine flags on Android via Intent will soon be dropped; see https://github.com/flutter/flutter/issues/180686 for more information on this breaking change. To migrate, set "
+ flag.engineArgument
+ " or any other flags specified via Intent extras on the command line instead or see https://github.com/flutter/flutter/blob/main/docs/engine/Flutter-Android-Engine-Flags.md for alternative methods.");
break;
}
}
}

/**
* Invoke this method from {@code Activity#onCreate(Bundle)} to create the content {@code View},
* or from {@code Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ public void onEngineWillDestroy() {
* native library and start a Dart VM.
*
* <p>In order to pass Dart VM initialization arguments (see {@link
* io.flutter.embedding.engine.FlutterShellArgs}) when creating the VM, manually set the
* initialization arguments by calling {@link
* io.flutter.embedding.engine.FlutterEngineFlags} for all available flags) when creating the VM,
* manually set the initialization arguments by calling {@link
* io.flutter.embedding.engine.loader.FlutterLoader#startInitialization(Context)} and {@link
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context,
* String[])} before constructing the engine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

// Standard FlutterPlugin
@NonNull private final FlutterEngine flutterEngine;
@NonNull private final FlutterLoader flutterLoader;
@NonNull private final FlutterPlugin.FlutterPluginBinding pluginBinding;

// ActivityAware
Expand Down Expand Up @@ -100,6 +101,7 @@
@NonNull FlutterLoader flutterLoader,
@Nullable FlutterEngineGroup group) {
this.flutterEngine = flutterEngine;
this.flutterLoader = flutterLoader;
pluginBinding =
new FlutterPlugin.FlutterPluginBinding(
appContext,
Expand Down Expand Up @@ -326,13 +328,31 @@ public void attachToActivity(

private void attachToActivityInternal(@NonNull Activity activity, @NonNull Lifecycle lifecycle) {
this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity, lifecycle);
final Intent intent = activity.getIntent();

final boolean useSoftwareRendering =
activity.getIntent() != null
? activity
.getIntent()
.getBooleanExtra(FlutterShellArgs.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)
// TODO(camsim99): Remove ability to set this flag via Intents. See
// https://github.com/flutter/flutter/issues/180686.
boolean useSoftwareRendering =
intent != null
? intent.getBooleanExtra(FlutterShellArgs.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)
: false;

// As part of https://github.com/flutter/flutter/issues/172553, the ability to set
// --enable-software-rendering via Intent will be removed. Inform
// developers about the new method for doing so if this was attempted.
// TODO(camsim99): Remove this warning after a stable release has passed:
// https://github.com/flutter/flutter/issues/179274.
if (useSoftwareRendering) {
Log.i(
TAG,
"If you are attempting to set --enable-software-rendering via Intent extras to launch a Flutter component outside of using the Flutter CLI, note that support for setting engine flags on Android via Intent will soon be dropped; see https://github.com/flutter/flutter/issues/172553 for more information on this breaking change. To migrate, set the "
+ FlutterEngineFlags.ENABLE_SOFTWARE_RENDERING.metadataKey
+ " metadata in the application manifest. See https://github.com/flutter/flutter/blob/main/docs/engine/Flutter-Android-Engine-Flags.md for more info.");
} else {
// Check manifest for software rendering configuration.
useSoftwareRendering = flutterLoader.getSofwareRenderingEnabledViaManifest();
}

flutterEngine.getPlatformViewsController().setSoftwareRendering(useSoftwareRendering);

// Activate the PlatformViewsController. This must happen before any plugins attempt
Expand Down
Loading