Skip to content

Add --[no-]enable-hcpp build flag and pipe through via Gradle manifest transformation - #189955

Merged
auto-submit[bot] merged 18 commits into
flutter:masterfrom
gmackall:hcpp-build-flag-manifest
Aug 5, 2026
Merged

auto-submit[bot] merged 18 commits into
flutter:masterfrom
gmackall:hcpp-build-flag-manifest

Conversation

@gmackall

@gmackall gmackall commented Jul 23, 2026 •

Copy link
Copy Markdown
Member
  • Adds --[no-]enable-hcpp to flutter build apk and flutter build appbundle.
    Not added to build aar: a value injected into a module's library manifest can
    fail an add-to-app host's build in the manifest merger when the host selects the
    opposite value, so the host application's manifest stays the source of truth.
  • Passes -Penable-hcpp=<bool> (the tool's default) and -Pexplicit-enable-hcpp=<bool>
    (set only when the developer passed the flag) to Gradle.
  • Registers EnableHcppManifestTask in the Flutter Gradle Plugin, a transform of the
    application project's merged manifest. Precedence is
    --[no-]enable-hcpp > AndroidManifest.xml > the tool's default:
    an explicit flag is written into the merged manifest over whatever is there and
    reported at lifecycle level; without the flag, the default is only injected when the
    manifest does not set EnableHcpp at all.
  • Known tradeoff: when the transform modifies the manifest it re-serializes it, which
    drops XML comments including the manifest merger's provenance annotations. This is
    invisible to aapt2 and is covered by a test.
  • Adds Kotlin Gradle task and Dart tool unit/integration test coverage.

- Adds --[no-]enable-hcpp CLI flag to build apk/appbundle/aar commands.
- Passes -Penable-hcpp=<bool> and -Pexplicit-enable-hcpp=<bool> to Gradle.
- Registers EnableHcppManifestTask in the Flutter Gradle Plugin to inject
  EnableHcpp metadata into application merged manifests when requested and
  warn on merged manifest conflicts.
- Adds Kotlin Gradle task and Dart tool unit/integration test coverage.
@github-actions github-actions Bot added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. labels Jul 23, 2026
@gmackall gmackall added the CICD Run CI/CD label Jul 23, 2026
gmackall and others added 10 commits July 23, 2026 16:04
- computeHcppEnabled now takes an ifAbsent value, so `flutter build
  apk/appbundle --enable-hcpp` against a manifest that does not set
  EnableHcpp reports what actually gets packaged instead of always
  reporting false.
- Only send -Pexplicit-enable-hcpp from commands that produce a final
  artifact. run/test/drive apply --enable-hcpp at launch, where it does
  override the manifest, so the gradle "does not affect this artifact"
  warning was wrong for them.
- Correct the flag help text: --no-enable-hcpp does not currently
  override a manifest value at launch, only --enable-hcpp does.
- Drop the RunCommandBase.enableHcpp override, which is now identical to
  the FlutterCommand implementation.
- Remove the addEnableHcppMetadataIfAbsent "legacy wrapper", which was
  never a legacy anything and had no callers outside tests, and make
  requestedEnableHcpp a required argument so nothing silently defaults
  to enabling hcpp.
- The FlutterPluginUtilsTest registration tests only asserted that
  getByType had been called. Drive onVariants and assert the task name
  and the values it is configured with.
- Cover the requested=false, metadata absent path, and pin the fact that
  re-serializing the manifest drops XML comments.
- Note in the task doc that the conflict warning is not repeated on
  up-to-date or cached builds.
@gmackall
gmackall marked this pull request as ready for review July 29, 2026 01:01
@gmackall
gmackall requested a review from a team as a code owner July 29, 2026 01:01
@gmackall
gmackall requested review from reidbaker and removed request for a team July 29, 2026 01:01

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EnableHcppManifestTask to inject io.flutter.embedding.android.EnableHcpp metadata into the merged Android manifest of application projects. It adds the --[no-]enable-hcpp CLI flag to build commands, updates BuildInfo and FlutterCommand to pass these properties to Gradle, and includes corresponding tests. Feedback on the changes highlights a critical compilation error in project.dart due to an undefined defaultValue reference in a catch block, and suggests simplifying property checks in FlutterPluginUtils.kt and avoiding unsafe null assertions in flutter_command.dart.

return _computeManifestMetadataBoolValueOrNull(metadataKey) ?? defaultValue;
}

bool? _computeManifestMetadataBoolValueOrNull(String metadataKey) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The helper method _computeManifestMetadataBoolValueOrNull does not define a defaultValue parameter, but the unchanged catch block inside the try statement (which is not shown in this diff but is part of the method body) still attempts to return defaultValue when an XmlException is caught. This will result in a compilation error (Undefined name 'defaultValue').\n\nTo fix this, the catch block should be updated to return null instead of defaultValue. Since the catch block is not part of the modified lines in this diff, please manually update it in project.dart:\n\ndart\n } on XmlException {\n return null;\n }\n

Comment on lines +1188 to +1193
val explicitEnableHcpp: Boolean? =
if (project.hasProperty(PROP_EXPLICIT_ENABLE_HCPP)) {
project.findProperty(PROP_EXPLICIT_ENABLE_HCPP)?.toString()?.toBoolean()
} else {
null
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The redundant hasProperty check can be simplified. project.findProperty already returns null if the property is not present, so you can directly retrieve and convert the property in a single expression.

        val explicitEnableHcpp: Boolean? =\n            project.findProperty(PROP_EXPLICIT_ENABLE_HCPP)?.toString()?.toBoolean()

Comment on lines +1346 to +1349
bool? get explicitEnableHcpp =>
(argResults?.options.contains('enable-hcpp') ?? false) && argResults!.wasParsed('enable-hcpp')
? boolArg('enable-hcpp')
: null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This expression can be simplified to avoid the unsafe null assertion operator (!) on argResults and improve readability.

  bool? get explicitEnableHcpp {\n    final ArgResults? results = argResults;\n    if (results == null || !results.options.contains('enable-hcpp') || !results.wasParsed('enable-hcpp')) {\n      return null;\n    }\n    return boolArg('enable-hcpp');\n  }

- Drop the redundant hasProperty check; findProperty already returns
  null when the property is absent.
- Give explicitEnableHcpp a block body so the argResults null check is
  explicit instead of relying on && short circuiting before a `!`.
package com.flutter.gradle.tasks

import groovy.util.Node
import groovy.xml.XmlNodePrinter

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non blocking. There are a couple of these xml parsing classes. Can you double check which one that people are supposed to use and make sure this does not add tech debt.

}

if (explicitEnableHcpp != null && (existingValueBool == null || explicitEnableHcpp != existingValueBool)) {
val flagName = if (explicitEnableHcpp) "--enable-hcpp" else "--no-enable-hcpp"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you pull the flag names out into constants at the top of the file.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


if (explicitEnableHcpp != null && (existingValueBool == null || explicitEnableHcpp != existingValueBool)) {
val flagName = if (explicitEnableHcpp) "--enable-hcpp" else "--no-enable-hcpp"
logger?.warn(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is backwards from what most developers expect. Specifically gradle has a different order of defaults. https://docs.gradle.org/current/userguide/build_environment.html

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair, changed to have cli win in all cases

Per review. The tests assert on the flag name in the warning, so make
them internal and reference them there instead of repeating the literals.
Per review. A flag passed at invocation time now takes priority over the
EnableHcpp metadata in AndroidManifest.xml, instead of being ignored with
a warning. This matches how gradle orders -P properties ahead of
gradle.properties, and drops the asymmetry where the same flag overrode
the manifest at launch for run/test/drive but not for a built artifact.

The precedence is now --[no-]enable-hcpp > AndroidManifest.xml > the
tool's default, for every command.

- The task writes an explicit value into the merged manifest, replacing
  what is there. Nothing conflicts in the merger because this is a
  transform of MERGED_MANIFEST, which already ran.
- Without the flag, the requested value is still only injected when the
  manifest says nothing, so the manifest keeps winning over a default.
- The warning becomes a lifecycle message reporting the override, and
  warnOnHcppManifestConflict is gone, since there is no longer a command
  for which the flag is inert.
- Analytics report the explicit value rather than the source manifest.
args_test flags "[a-z].[A-Z]" as a probable missing space after a
sentence, and io.flutter.embedding.android.EnableHcpp trips it on
"android.EnableHcpp". The bare name reads fine in context.
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@auto-submit

auto-submit Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189955, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR.

@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@auto-submit

auto-submit Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189955, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@auto-submit

auto-submit Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189955, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 4, 2026
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
@auto-submit

auto-submit Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189955, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
@auto-submit

auto-submit Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/189955, because - The status or check suite Dashboard Checks has failed. Please fix the issues identified (or deflake) before re-applying this label.

@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Aug 5, 2026
Merged via the queue into flutter:master with commit 7820e78 Aug 5, 2026
34 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2026
ValentinVignal pushed a commit to ValentinVignal/flutter that referenced this pull request Aug 27, 2026
…ter#190623)

AI pr description which is correct (I checked 🙂 )

- Enables the `enable-hcpp` feature flag by default on the `master` and
`beta` channels (remains default off on `stable`).
- Pipes the feature flag default through `FlutterCommand.enableHcpp`
into `BuildInfo.androidEnableHcpp`, allowing Gradle's
`EnableHcppManifestTask` (landed in flutter#189955) to inject
`io.flutter.embedding.android.EnableHcpp = true` into the merged
manifest when the app's manifest is silent.
- Preserves the established precedence: explicit `--[no-]enable-hcpp`
CLI flag > `AndroidManifest.xml` > feature flag default.
- Ensures `DebuggingOptions.enableHcpp` is treated as a nullable
`bool?`, only passing launch overrides
(`--enable-hcpp-and-surface-control=$enableHcpp` / `--ez
enable-hcpp-and-surface-control $enableHcpp`) when explicitly provided
on the CLI, allowing the installed artifact's manifest to decide by
default.
- Updates unit and command test suites across `flutter_tools`.

> **Note for reviewers**: iOS reviewers were auto-requested because
`build_swift_package_test.dart` was updated to implement `isHcppEnabled`
in its `FakeFeatureFlags` (queried by `FlutterCommand.getBuildInfo()`).
No iOS or Swift Package Manager logic is changed.

---------

Co-authored-by: Gray Mackall <[email protected]>
Co-authored-by: Camille Simon <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants