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-android with AndroidPackageFormat=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 data
concurrentMain/, unixMain/, webMain/, etc. — platform-specific klib data
kotlin/ — Kotlin builtins (kotlin_builtins files)
classes.jar — merged Java classes
META-INF/*.version — AndroidX library version files
META-INF/androidx/**/LICENSE.txt — license files
META-INF/proguard/*.pro — ProGuard rules
META-INF/services/* — service loader registrations
META-INF/kotlin-project-structure-metadata.json
META-INF/maven/** — Maven POM files
R.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
Relevant log output
Android framework version
net10.0-android
Affected platform version
VS 2026 18.6.2
Description
When running
dotnet publishfor 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:
Steps to Reproduce
net10.0-androidwithAndroidPackageFormat=apkdotnet publish -c Release -f net10.0-android -p:RuntimeIdentifier=android-arm64Did you find any workaround?
Environment
Root Cause Analysis
The issue is in the
BuildArchivetask used by the_BuildApkEmbedtarget inMicrosoft.Android.Sdk.Windows\36.1.53\tools\Xamarin.Android.Common.targets.BuildArchiveuses an incremental approach: it copies the previous intermediate APK (obj\Release\android\bin\<package>.apk) as the base, then adds/updates files fromFilesToAddToArchive.The bug manifests as follows:
Good build (previous APK was bad = missing Java resources)
The previous APK does NOT contain Java resources, so
BuildArchivesuccessfully adds them:Bad build (previous APK was good = already has Java resources)
The previous APK already contains all Java resources, so every add attempt fails:
The key observation: when an entry "already exists" and fails to add,
BuildArchivetreats 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 inFilesToAddToArchive, it should be treated as retained, not removed.This creates a feedback loop:
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.txtAttached 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
_BuildApkEmbedforcesBuildArchiveto build from scratch, avoiding the incremental bug:This has been verified to produce consistent APKs across consecutive builds.
Expected Fix
The
BuildArchivetask 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 ANDFilesToAddToArchiveshould 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
Relevant log output