Skip to content

[CP-stable][tool] Fix libapp.so dropped from APK/app bundle - #188516

Merged
auto-submit[bot] merged 2 commits into
flutter:flutter-3.44-candidate.0from
flutteractionsbot:cp-stable-6efbbadd2ee7921be6135990dd6bfee856fb4d1e
Jun 30, 2026
Merged

auto-submit[bot] merged 2 commits into
flutter:flutter-3.44-candidate.0from
flutteractionsbot:cp-stable-6efbbadd2ee7921be6135990dd6bfee856fb4d1e

Conversation

@flutteractionsbot

@flutteractionsbot flutteractionsbot commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

Issue Link:

What is the link to the issue this cherry-pick is addressing?

#186810
#187388
#187553

Impact Description:

What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

The root cause either presents as the app crashing on startup, or the build failing with the message

"Release app bundle failed to strip debug symbols from native libraries"

Changelog Description:

Explain this cherry pick:

  • In one line that is accessible to most Flutter developers.
  • That describes the state prior to the fix.
  • That includes which platforms are impacted.
    See best practices for examples.

< Replace with changelog description here >
[flutter/186810 flutter/187388 flutter/187553] When building android app bundles using flavors, or with an old app template combined with a plugin coming alphabetically before app, fixes problems with failing to include libapp.so in the produced app bundle.

Workaround:

Is there a workaround for this issue?

For the case of the old app template combined with a plugin coming before "app" alphabetically, there is a workaround here #186810 (comment). For the flavors case there is not a workaround.

Risk:

What is the risk level of this cherry-pick?

  • Low
  • Medium
  • High

Test Coverage:

Are you confident that your fix is well-tested by automated tests?

  • Yes
  • No

Validation Steps:

What are the steps to validate that this fix works?

  1. make a fresh project
  2. combine the subprojects in android/build.gradle(.kts):
    find
subprojects {
    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
    project.layout.buildDirectory.value(newSubprojectBuildDir)
}

subprojects {
    project.evaluationDependsOn(":app")
}

and combine

subprojects {
    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
    project.layout.buildDirectory.value(newSubprojectBuildDir)
    project.evaluationDependsOn(":app")
}
  1. add a plugin which comes alphabetically before "app"
  2. also you will need to disable r8, due to how the templates have drifted over time.
// after signingConfig = signingConfigs.getByName("debug")

isMinifyEnabled = false
isShrinkResources = false

Also, you can separately test the repro steps listed in
#187388
to validate that this fixes the flavors-symptom of this underlying root cause.

## Summary

`libapp.so` could be silently dropped from release APKs
and app bundles, surfacing as either:

- a runtime crash on launch — `VM snapshot invalid and could not be
inferred from
  settings` — for APKs, or
- a `Release app bundle failed to strip debug symbols from native
libraries`
  build failure for app bundles.

## Root cause

Regression from flutter#181275, which moved `libapp.so` from a jar dependency
onto a
Flutter Gradle Plugin source-set `jniLibs` directory. That delivery was
fragile
in two ways, both of which dropped `libapp.so` from the merged native
libraries
(while `libflutter.so`/`libdartjni.so`, delivered as AAR dependencies,
were
unaffected — which is why the failure looked asymmetric):

1. The source-set `jniLibs` `srcDir` was resolved eagerly
(`.get().asFile`) at
`:app` configuration time, while the copy task wrote lazily. When `:app`
was
   evaluated before its build directory had been redirected — a combined
`subprojects { … evaluationDependsOn(":app") }` block (the pre-flutter#91030
template
shape) together with a plugin whose Gradle subproject name sorts before
`:app` — the two disagreed on the build directory and the staged
`libapp.so`
   was never merged. (flutter#186810)
2. The copy task wrote into a directory nested inside the Flutter task's
own
output directory, creating overlapping task outputs that undermined
Gradle's
incremental checks — e.g. a flavored project where a prior single-ABI
build
(a `flutter run` on one device) left the other ABIs missing `libapp.so`.
   (flutter#187388)

## Fix

Stage `libapp.so` (and any bundled native assets) through a dedicated
`CopyFlutterJniLibsTask` whose output is registered on each variant via
AGP's
variant API:
[`variant.sources.jniLibs.addGeneratedSourceDirectory(...)`](https://developer.android.com/reference/tools/gradle-api/9.1/com/android/build/api/variant/SourceDirectories#addStaticSourceDirectory(kotlin.String)).
AGP then
owns the task dependency, resolves the output path lazily (correct
regardless of
project evaluation order or build-dir redirection), keeps it in its own
output
directory (no overlapping outputs), and strips/extracts debug symbols
from it
like any other native library. This restores the robustness of the
original
jar-based inclusion while keeping `libapp.so` strippable.

## Tests

New integration test `gradle_libapp_so_packaging_test.dart` covering
both
triggers: the combined `subprojects` block + a plugin sorted before
`:app`, and
a flavored single-ABI build preceding a multi-ABI build.

Fixes flutter#186810
Fixes flutter#187388
Fixes flutter#187553
@flutteractionsbot flutteractionsbot added the cp: review Cherry-picks in the review queue label Jun 24, 2026
@flutteractionsbot
flutteractionsbot requested a review from a team as a code owner June 24, 2026 18:19
@flutteractionsbot
flutteractionsbot requested review from reidbaker and removed request for a team June 24, 2026 18:19
@flutteractionsbot

Copy link
Copy Markdown
Contributor Author

@gmackall please fill out the PR description above, afterwards the release team will review this request.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 24, 2026
@flutter-dashboard

Copy link
Copy Markdown

This pull request was opened from and to a release candidate branch. This should only be done as part of the official Flutter release process. If you are attempting to make a regular contribution to the Flutter project, please close this PR and follow the instructions at Tree Hygiene for detailed instructions on contributing to Flutter.

Reviewers: Use caution before merging pull requests to release branches. Ensure the proper procedure has been followed.

@github-actions github-actions Bot added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. team-android Owned by Android platform team labels Jun 24, 2026

@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 migrates the Flutter Gradle Plugin from using the legacy Android extension to the modern AndroidComponentsExtension for registering JNI libraries. It introduces a new CopyFlutterJniLibsTask to stage native libraries (libapp.so and native assets) into a dedicated destination directory structured by ABI, and adds integration tests to verify packaging. Feedback on the changes suggests skipping target platforms with unresolved ABIs in CopyFlutterJniLibsTask to avoid copying files to or from a directory named "null".

Comment on lines +51 to +63
targetPlatforms.get().forEach { targetPlatform ->
val abi: String? = FlutterPluginConstants.PLATFORM_ARCH_MAP[targetPlatform]
from(intermediateDir.dir(abi ?: "null")) {
include("*.so")
rename { filename: String -> "lib$filename" }
into(abi ?: "null")
}
val nativeAssetsDir = intermediateDir.dir("native_assets/jniLibs/lib/$abi")
from(nativeAssetsDir) {
include("*.so")
into(abi ?: "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

If targetPlatform is not found in PLATFORM_ARCH_MAP, abi will be null. Using abi ?: "null" results in copying files from/to a directory named "null", which is unexpected and could package unwanted files or create a redundant null directory in the build output. It is safer to skip platforms with an unresolved ABI entirely.

Suggested change
targetPlatforms.get().forEach { targetPlatform ->
val abi: String? = FlutterPluginConstants.PLATFORM_ARCH_MAP[targetPlatform]
from(intermediateDir.dir(abi ?: "null")) {
include("*.so")
rename { filename: String -> "lib$filename" }
into(abi ?: "null")
}
val nativeAssetsDir = intermediateDir.dir("native_assets/jniLibs/lib/$abi")
from(nativeAssetsDir) {
include("*.so")
into(abi ?: "null")
}
}
targetPlatforms.get().forEach { targetPlatform ->
val abi = FlutterPluginConstants.PLATFORM_ARCH_MAP[targetPlatform] ?: return@forEach
from(intermediateDir.dir(abi)) {
include("*.so")
rename { filename: String -> "lib$filename" }
into(abi)
}
val nativeAssetsDir = intermediateDir.dir("native_assets/jniLibs/lib/$abi")
from(nativeAssetsDir) {
include("*.so")
into(abi)
}
}

@reidbaker reidbaker added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 30, 2026
@auto-submit
auto-submit Bot merged commit c63e437 into flutter:flutter-3.44-candidate.0 Jun 30, 2026
150 checks passed
@flutteractionsbot
flutteractionsbot deleted the cp-stable-6efbbadd2ee7921be6135990dd6bfee856fb4d1e branch July 20, 2026 17:04
Anas-Qasem pushed a commit to Anas-Qasem/flutter that referenced this pull request Aug 11, 2026
…188516)

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#186810
flutter#187388
flutter#187553

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

The root cause either presents as the app crashing on startup, or the build failing with the message
> "Release app bundle failed to strip debug symbols from native libraries"

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

< Replace with changelog description here >
[flutter/186810 flutter/187388 flutter/187553] When building android app bundles using flavors, or with an old app template combined with a plugin coming alphabetically before app, fixes problems with failing to include libapp.so in the produced app bundle.

### Workaround:
Is there a workaround for this issue?

For the case of the old app template combined with a plugin coming before "app" alphabetically, there is a workaround here flutter#186810 (comment). For the flavors case there is not a workaround.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

1. make a fresh project
2. combine the subprojects in `android/build.gradle(.kts)`:
find 
```kotlin
subprojects {
    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
    project.layout.buildDirectory.value(newSubprojectBuildDir)
}

subprojects {
    project.evaluationDependsOn(":app")
}
```
and combine
```kotlin
subprojects {
    val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
    project.layout.buildDirectory.value(newSubprojectBuildDir)
    project.evaluationDependsOn(":app")
}
```

3. add a plugin which comes alphabetically before "app"
4. also you will need to disable r8, due to how the templates have drifted over time.
```
// after signingConfig = signingConfigs.getByName("debug")

isMinifyEnabled = false
isShrinkResources = false
```

Also, you can separately test the repro steps listed in 
flutter#187388
to validate that this fixes the flavors-symptom of this underlying root cause.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD cp: review Cherry-picks in the review queue platform-android Android applications specifically team-android Owned by Android platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants