Daco Harkes 6e459a3860
[native_assets] Fix flutter build ios-framework (#181507)
This PR fixes two issues. Accidental reuse of code assets between build
modes and SDKs (https://github.com/flutter/flutter/issues/181724), and
the bundling in ios-frameworks
(https://github.com/flutter/flutter/issues/181382).

To fix the accidental caching, the `Target`s related to build hooks and
code assets now output their files to `environment.outputDir` instead of
`$projectDir/$buildDir/native_assets`.

* `xcode_backend` is updated to deal with this.
* `Flutter.kt` has been updated to deal with this.
* Because the `Target`s are responsible for caching, the code has been
refactored to provide the target directories from there. The
"global-ish" function `nativeAssetsBuildUri` that was calculating the
directory before has been removed.
* `runFlutterSpecificHooks` has nothing to do with that directory, it's
access to it has been removed.
* To avoid another cmakefile migration, the Linux and Windows
implementation use the same directory. (Note that output dir and build
dir overlap for Linux and Windows, while they do not for MacOS, iOS, and
Android.)
* This also means that we don't have to read `NativeAssetsManifest.json`
in `xcode_backend` anymore. Instead the `Target` clears the output
directory, so we should not have any stale frameworks.
* Refactored `installCodeAssets` and its platform-specific
implementations to return a list of all produced files. These are now
added to the `Target`'s depfile. This fixes an issue where the build
system would skip re-installing native assets after an Xcode "Clean
Build Folder because it wasn't tracking the frameworks/dylibs as
outputs.

Closes: https://github.com/flutter/flutter/issues/181724

Other `Target`s related tweaks:

* Added proper
`Source.pattern('{BUILD_DIR}/${DartBuild.dartHookResultFilename}'),` for
all `Target`s that depend on that file. These were missing. (The build
system uses `dependencies` for ordering of `Target`s, but relies on
`inputs` and `outputs` for caching.)
* Removed code assets from `CopyAssets`. That target is supposed to make
an asset-bundle that is OS-independent if I understand correctly.

This PR changes the way code assets are bundled in `flutter build
ios-framework`.

* This PR now packages in an `.xcframework`, which is necessary to be
able to package both device and simulator.
* Run through the frameworks of both device and simulator and give
errors on inconsistencies.

Closes: https://github.com/flutter/flutter/issues/181382

Other iOS related tweaks:

* Use `xcrun` for invoking all the commands. (This is used for producing
the app framework, but was not for code assets frameworks.)
* Make sure all commands are added to the traces when running verbose.
(Also to bring it in line for with the other `xcrun` commands.)

Testing:

* The integration test is updated to inspect the `xcframework`s.
* Added a test that simulates Xcode "Product > Clean Build Folder...",
to check that it now correctly triggers a rebuild.
* We do _not_ have an integration test that _runs_ the frameworks output
from `flutter build ios-framework` inside a host app at all as far as
I'm aware.
* dev/devicelab/bin/tasks/build_ios_framework_module_test.dart builds a
framework, but doesn't run it in a host app
* dev/integration_tests/ios_add2app_life_cycle/build_and_test.sh runs,
but does so via `flutter build ios` not as a framework.
* Does not add an integration test for caching behavior between
switching build modes. However, the proper functioning of `flutter build
ios-framework` depends on the `Target`s for different not using
overlapping directories.

Architectural approaches tried but didn't work:

* Subclass `InstallCodeAssets` per OS to be more precise in the
`output`s on what files are output. This doesn't work because other
OS-independent targets on the `InstallCodeAssets` target.
2026-02-12 15:33:43 +00:00
..
2025-07-02 14:30:22 +00:00

The Flutter Gradle Plugin

This directory contains Gradle code used to by the Flutter tool to build Flutter apps for Android, primarily the Flutter Gradle Plugin (FGP) - a Gradle plugin built on top of Gradle and the Android Gradle Plugin (AGP).

Editing in Android Studio

To get code completion in Android Studio, you must open a new Android Studio window with this directory as the root. Code completion will not work when navigating to files in an Android Studio window opened at the root of the entire Flutter repo.

Contributing

The Flutter Gradle Plugin is currently being re-written from Groovy to Kotlin (Kotlin source specifically, i.e. not .kts). As such, outside of critical bug fixes, new contributions will only be accepted in src/main/kotlin (and src/test/kotlin).

Testing

To run the tests from the CLI, you first need to download the Gradle wrapper.

  1. Ensure you have run gclient sync recently (i.e., from the root of your framework checkout, run gclient sync -D).
  2. From this directory, run ../../../engine/src/flutter/third_party/gradle/bin/gradle wrapper.

Tests can be run in Android Studio, or directly with Gradle: ./gradlew test (note that this directory does not contain a version controlled Gradle file. You can find one in the engines third_party directory at <flutter_root>/engine/src/flutter/third_party/gradle/bin/gradle).

If you can not run the test task try running ./gradlew tasks. If that does not work then there is a configuration error. The most common one is using the wrong version of java. Java can be overridden by setting the JAVA_HOME environment variable. This example sets the java version to 17 downloaded with brew and then runs the tests: JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home/ ./gradlew test

You can run all the tests in one file by passing in the fully qualified class name, e.g. ./gradlew test --tests com.flutter.gradle.BaseApplicationNameHandlerTest, or one test in one file by passing in the fully qualified class name followed by the method name, e.g ./gradlew test --tests "com.flutter.gradle.BaseApplicationNameHandlerTest.setBaseName respects Flutter tool property".

Sometimes changing a test name and then running it will cause an IDE error. To get Android Studio back to a good state on Mac, run Help > "Repair IDE", and then in the popup window "Rescan project indexes > Everything works now."

To add a new test, add a class under src/test/kotlin, with methods annotated with @Test. These tests will get automatically run on CI by packages/flutter_tools/test/integration.shard/android_run_flutter_gradle_plugin_tests_test.dart.