Repository navigation
BuildArchive incremental build bug: Java resources alternate between present and missing in APK on consecutive publishes #11543
Description
Android framework version
net10.0-android
Affected platform version
VS 2026 18.6.2
Description
When running dotnet publish for an Android project, the resulting APK alternates between a "good" state (with Java/JAR resources) and a "bad" state (without them) on every consecutive build, even when no source files change.
Bad APK contains 438 files — missing all Java resources (kotlin/, commonMain/, nativeMain/, classes.jar, etc.)
Good APK contains 770 files — includes all expected Java resources.
The pattern is deterministic:
- Build → bad APK
- Build → good APK
- Build → bad APK
- (repeats forever)
Steps to Reproduce
- Create an Avalonia Android project targeting
net10.0-androidwithAndroidPackageFormat=apk - Run
dotnet publish -c Release -f net10.0-android -p:RuntimeIdentifier=android-arm64 - Inspect the APK contents
- Run the same publish command again (no source changes)
- Inspect the APK contents — the Java resources will be different
Did you find any workaround?
Environment
| Component | Version |
|---|---|
| OS | Windows 11 (10.0.26200) |
| .NET SDK | 10.0.300 |
| .NET Runtime | 10.0.8 |
| MSBuild | 18.6.3 |
| Android workload | 36.1.53/10.0.100 |
| Android SDK Platform | android-36 |
| Android Build Tools | 36.0.0 |
| JDK | OpenJDK 17.0.19 (Microsoft) |
| Avalonia | 12.0.4 |
| Xamarin.AndroidX.Core.SplashScreen | 1.0.1.15 |
Root Cause Analysis
The issue is in the BuildArchive task used by the _BuildApkEmbed target in Microsoft.Android.Sdk.Windows\36.1.53\tools\Xamarin.Android.Common.targets.
BuildArchive uses an incremental approach: it copies the previous intermediate APK (obj\Release\android\bin\<package>.apk) as the base, then adds/updates files from FilesToAddToArchive.
The bug manifests as follows:
Good build (previous APK was bad = missing Java resources)
The previous APK does NOT contain Java resources, so BuildArchive successfully adds them:
Adding META-INF/androidx.versionedparcelable_versionedparcelable.version from lp\61\jl\classes.jar as the archive file is out of date.
Adding META-INF/androidx.tracing_tracing.version from lp\62\jl\classes.jar as the archive file is out of date.
Adding commonMain/default/manifest from ... as the archive file is out of date.
...
(400 entries added, 37 duplicates "Failed to add")
Bad build (previous APK was good = already has Java resources)
The previous APK already contains all Java resources, so every add attempt fails:
Failed to add jar entry META-INF/androidx.versionedparcelable_versionedparcelable.version from classes.jar: the same file already exists in the apk
Failed to add jar entry META-INF/androidx.tracing_tracing.version from classes.jar: the same file already exists in the apk
Failed to add jar entry commonMain/default/manifest from ... the same file already exists in the apk
...
(369 entries "Failed to add", only 68 entries added)
The key observation: when an entry "already exists" and fails to add, BuildArchive treats these files as if they were no longer needed by the current build and removes them from the APK. This is incorrect — if a file is both present in the APK AND in FilesToAddToArchive, it should be treated as retained, not removed.
This creates a feedback loop:
- Good APK → all adds fail as duplicates → files removed → Bad APK
- Bad APK → adds succeed → files present → Good APK
- (repeats)
Files Missing from Bad APK
The bad APK is missing 332 Java resource files compared to the good APK, including:
commonMain/— Kotlin/Native klib data (manifests, linkdata, .knm files)nativeMain/— native platform klib dataconcurrentMain/,unixMain/,webMain/, etc. — platform-specific klib datakotlin/— Kotlin builtins (kotlin_builtins files)classes.jar— merged Java classesMETA-INF/*.version— AndroidX library version filesMETA-INF/androidx/**/LICENSE.txt— license filesMETA-INF/proguard/*.pro— ProGuard rulesMETA-INF/services/*— service loader registrationsMETA-INF/kotlin-project-structure-metadata.jsonMETA-INF/maven/**— Maven POM filesR.txt,proguard.txt
Attached Logs
log_bad_buildarchive.txt— BuildArchive task messages from a bad build (448 lines)log_good_buildarchive.txt— BuildArchive task messages from a good build (448 lines)diff_apk_files.txt— diff between bad and good APK file listings (332 files missing)
Workaround
Deleting the intermediate APK before _BuildApkEmbed forces BuildArchive to build from scratch, avoiding the incremental bug:
<Target Name="_CleanIntermediateApk" BeforeTargets="_BuildApkEmbed">
<Delete Files="$(ApkFileIntermediate)" Condition="Exists('$(ApkFileIntermediate)')" />
</Target>This has been verified to produce consistent APKs across consecutive builds.
Expected Fix
The BuildArchive task should track which files it attempted to add (regardless of whether the add succeeded due to the file already existing). Files that exist in both the previous APK AND FilesToAddToArchive should be treated as retained and must NOT be removed by the incremental cleanup logic.
diff_apk_files.txt
log_bad_buildarchive.txt
log_good_buildarchive.txt
Activity
simonrozsival commentedon Jun 1, 2026
@tms320 thanks for the report. I'll look into it!
kerams commentedon Jun 2, 2026
Noticed this too, but I always take the smaller apk with fewer files and it works fine.
tms320 commentedon Jun 2, 2026
I've never developed for Android before and understand nothing about the structure of APK files. But the smaller apk doesn't work in my case.