Android framework version
net10.0-android
Affected platform version
Microsoft.Android.Sdk 36.1.69
Description
This is scoped to the shrinking and optimization percentages on Play Console. The obfuscation / -dontobfuscate work (#12535, #12575 and the [r8-obfuscation] stack) is separate and untouched here.
With $(AndroidLinkTool)=r8, R8 already runs with shrinking enabled, yet Play's App Bundle Explorer shows optimization and shrinking as - and only obfuscation gets a value (from mapping.txt). Per the DEX code optimization docs, for AGP 8.10+ the percentages come from BUNDLE-METADATA/com.android.tools/r8.json. The docs also say Play falls back to mapping.txt when r8.json is absent; in our measurements that fallback produced obfuscation only, never the other two.
The SDK never produces or embeds that file:
R8.cs has no build-metadata output. $(AndroidR8ExtraArguments) cannot be used for it from outside the SDK: D8.WriteArg writes the whole property as one response-file line, and R8's FlagFile treats one line as one token, so --build-metadata-output <path> arrives as a single unknown option. (The flag itself is supported by 8.11.18 — this is an SDK limitation, not an R8 one.)
_PrepareBuildApk adds exactly one AndroidAppBundleMetaDataFile entry, com.android.tools.build.obfuscation/proguard.map. Nothing for com.android.tools/r8.json.
Measurements (production .NET MAUI app, same project, same R8 flags, AndroidPackageFormat=aab, no AGP metadata injected anywhere)
|
DEX compiled by |
r8.json in AAB |
version in that json |
Play shrinking / optimization |
| stock |
pack 8.11.18 |
none |
— |
- |
| A |
pack 8.11.18 |
generated via setBuildMetadataConsumer |
8.11.18 |
- (obfuscation 37% from mapping) |
| B |
R8 9.0.32 via AndroidR8JarPath |
generated by 9.0.32 |
9.0.32 |
percentages shown |
| 111 |
pack 8.11.18 |
A's json, only version changed |
9.0.32 |
percentages shown |
| 112 |
R8 9.0.32 |
B's json, only version changed |
8.11.18 |
- |
111/112 keep DEX bytes and dexFiles[].checksum unchanged; only the version string differs. Diffing honest 8.11.18 vs 9.0.32 json (same input): identical stats, options, dexFiles[].checksum; 8.11 additionally has compilation.*; 9.0 has no key 8.11 lacks.
Together that isolates the gate to the version string in r8.json. Two points only: 8.11.18 is rejected, 9.0.32 is accepted. The cutoff between them was not probed (it could be 8.12, 9.0.0, or something else). There is no honest way for pack 8.11.18 to produce a version Play will score.
Ask — two separable changes
- Generate and embed
r8.json (backportable without changing the jar): an R8 task parameter that writes --build-metadata-output and the path as two response-file lines, plus one AndroidAppBundleMetaDataFile entry for com.android.tools/r8.json next to the existing proguard.map one. main already pins 9.4.17 and the net11 line (release/11.0.1xx-preview6) already pins 9.1.31; (1) is likely sufficient there. We uploaded and scored 9.0.32, and later the same production app compiled with main's R8 9.4.17 (src/r8 fat jar) — Play still filled optimization, obfuscation, and shrinking.
- Bump
src/r8/build.gradle on release/10.0.1xx (the live net10.0-android pack line; tools jar is 8.11.18 today) to a compiler that emits a version Play accepts. 9.0.32 is the version we first uploaded and Play scored; 9.4.17 is the main pin and also scored. Change (1) alone still emits "version": "8.11.18", which Play does not score. Rewriting version in json is not an SDK solution.
Follow-up, not required to get Play to read the file: the [r8-obfuscation] PRs (#12575, #12628–#12634) address -dontobfuscate / JNI renaming, not this. _CalculateProguardConfigurationFiles still passes tools/proguard-android.txt (line 16: -dontoptimize). The SDK does not currently ship proguard-android-optimize.txt. Switching that default would let compiler r8.json report optimizations enabled; it is independent of emit+embed and of the obfuscation stack.
Out of scope: -dontobfuscate / JNI remapping, shrinkResources, fabricating androidGradlePluginVersion, running Gradle in the SDK.
Steps to Reproduce
- Release
net10.0-android, AndroidLinkTool=r8, AndroidCreateProguardMappingFile=true, AndroidPackageFormat=aab, dotnet publish.
unzip -l app.aab | grep BUNDLE-METADATA → only proguard.map.
- Upload → App Bundle Explorer → shrinking/optimization
-.
- Set
AndroidR8JarPath to an R8 9.0.32 jar, produce r8.json via setBuildMetadataConsumer (or CLI --build-metadata-output on its own line), add it via AndroidAppBundleMetaDataFile Include="com.android.tools/r8.json:<path>", publish, upload.
- Percentages appear. The same DEX with json
version 8.11.18 (honest pack output, or 112 in the table) shows - again.
Did you find any workaround?
the csproj targets in step 4 — an external 9.0.32 jar plus an out-of-band json producer. Apps should not have to carry that.
Relevant log output
Android framework version
net10.0-android
Affected platform version
Microsoft.Android.Sdk 36.1.69
Description
This is scoped to the shrinking and optimization percentages on Play Console. The obfuscation /
-dontobfuscatework (#12535, #12575 and the[r8-obfuscation]stack) is separate and untouched here.With
$(AndroidLinkTool)=r8, R8 already runs with shrinking enabled, yet Play's App Bundle Explorer shows optimization and shrinking as-and only obfuscation gets a value (frommapping.txt). Per the DEX code optimization docs, for AGP 8.10+ the percentages come fromBUNDLE-METADATA/com.android.tools/r8.json. The docs also say Play falls back tomapping.txtwhenr8.jsonis absent; in our measurements that fallback produced obfuscation only, never the other two.The SDK never produces or embeds that file:
R8.cshas no build-metadata output.$(AndroidR8ExtraArguments)cannot be used for it from outside the SDK:D8.WriteArgwrites the whole property as one response-file line, and R8'sFlagFiletreats one line as one token, so--build-metadata-output <path>arrives as a single unknown option. (The flag itself is supported by 8.11.18 — this is an SDK limitation, not an R8 one.)_PrepareBuildApkadds exactly oneAndroidAppBundleMetaDataFileentry,com.android.tools.build.obfuscation/proguard.map. Nothing forcom.android.tools/r8.json.Measurements (production .NET MAUI app, same project, same R8 flags,
AndroidPackageFormat=aab, no AGP metadata injected anywhere)r8.jsonin AABversionin that json-setBuildMetadataConsumer8.11.18-(obfuscation 37% from mapping)AndroidR8JarPath9.0.32versionchanged9.0.32versionchanged8.11.18-111/112 keep DEX bytes and
dexFiles[].checksumunchanged; only theversionstring differs. Diffing honest 8.11.18 vs 9.0.32 json (same input): identicalstats,options,dexFiles[].checksum; 8.11 additionally hascompilation.*; 9.0 has no key 8.11 lacks.Together that isolates the gate to the
versionstring inr8.json. Two points only:8.11.18is rejected,9.0.32is accepted. The cutoff between them was not probed (it could be 8.12, 9.0.0, or something else). There is no honest way for pack 8.11.18 to produce aversionPlay will score.Ask — two separable changes
r8.json(backportable without changing the jar): an R8 task parameter that writes--build-metadata-outputand the path as two response-file lines, plus oneAndroidAppBundleMetaDataFileentry forcom.android.tools/r8.jsonnext to the existingproguard.mapone.mainalready pins 9.4.17 and the net11 line (release/11.0.1xx-preview6) already pins 9.1.31; (1) is likely sufficient there. We uploaded and scored 9.0.32, and later the same production app compiled withmain's R8 9.4.17 (src/r8fat jar) — Play still filled optimization, obfuscation, and shrinking.src/r8/build.gradleonrelease/10.0.1xx(the livenet10.0-androidpack line; tools jar is 8.11.18 today) to a compiler that emits aversionPlay accepts. 9.0.32 is the version we first uploaded and Play scored; 9.4.17 is themainpin and also scored. Change (1) alone still emits"version": "8.11.18", which Play does not score. Rewritingversionin json is not an SDK solution.Follow-up, not required to get Play to read the file: the
[r8-obfuscation]PRs (#12575, #12628–#12634) address-dontobfuscate/ JNI renaming, not this._CalculateProguardConfigurationFilesstill passestools/proguard-android.txt(line 16:-dontoptimize). The SDK does not currently shipproguard-android-optimize.txt. Switching that default would let compilerr8.jsonreport optimizations enabled; it is independent of emit+embed and of the obfuscation stack.Out of scope:
-dontobfuscate/ JNI remapping,shrinkResources, fabricatingandroidGradlePluginVersion, running Gradle in the SDK.Steps to Reproduce
net10.0-android,AndroidLinkTool=r8,AndroidCreateProguardMappingFile=true,AndroidPackageFormat=aab,dotnet publish.unzip -l app.aab | grep BUNDLE-METADATA→ onlyproguard.map.-.AndroidR8JarPathto an R8 9.0.32 jar, producer8.jsonviasetBuildMetadataConsumer(or CLI--build-metadata-outputon its own line), add it viaAndroidAppBundleMetaDataFile Include="com.android.tools/r8.json:<path>", publish, upload.version8.11.18(honest pack output, or 112 in the table) shows-again.Did you find any workaround?
the csproj targets in step 4 — an external 9.0.32 jar plus an out-of-band json producer. Apps should not have to carry that.
Relevant log output