Skip to content

[build] Default .NET 11 to target net11.0-android37 only#11254

Open
jonathanpeppers wants to merge 16 commits intomainfrom
jonathanpeppers/default-api-37-target
Open

[build] Default .NET 11 to target net11.0-android37 only#11254
jonathanpeppers wants to merge 16 commits intomainfrom
jonathanpeppers/default-api-37-target

Conversation

@jonathanpeppers
Copy link
Copy Markdown
Member

Stop building API 36.1 as a separate stable target and make net11.0-android37 the sole default target framework for .NET 11.

Changes:

  • Configuration.props: Set AndroidLatestStableApiLevel to 37, AndroidLatestStablePlatformId to 37.0 (explicit, since Google ships platform-37.0), framework version to v17.0. Unstable properties now reference stable (since they are the same). Updated AndroidLatestStableApiLevel2 comment example to 38.1.
  • AndroidToolchain.cs: Move isLatestStable from platform-36.1 to platform-37.0, remove isPreview flag
  • WorkloadManifest.in.json: Update workload packs from 36.1 to 37, add Mono/CoreCLR/NativeAOT runtime pack definitions for 37, remove 36.1 pack definitions
  • Xamarin.Android.Build.Tasks.targets: Use $(AndroidLatestStablePlatformId) for @SDK_PLATFORM_VERSION@ replacement instead of $(AndroidLatestStableApiLevel) (needed because ApiLevel=37 but PlatformId=37.0)
  • BuildTest.cs: Hardcode MinorApiLevelFallbackThrowsXA5207 to use 36.1 since 37.0 == 37 (no meaningful minor version distinction for this test scenario)

Note: AndroidLatestStablePlatformId is now explicitly set to 37.0 rather than defaulting to $(AndroidLatestStableApiLevel). This is because Google ships the platform as platform-37.0 (directory android-37.0), but the API level for TFMs and PublicAPI directories is just 37. Previous APIs (like 36 and 36.1) happened to have identical ApiLevel and PlatformId values.

jonathanpeppers and others added 15 commits April 30, 2026 10:41
Stop building API 36.1 as a separate stable target and make
net11.0-android37 the sole default target framework for .NET 11.

Changes:

- Configuration.props: Set AndroidLatestStableApiLevel to 37,
  AndroidLatestStablePlatformId to 37.0, framework version to v17.0.
  Unstable properties now reference stable (since they are the same).
- AndroidToolchain.cs: Move isLatestStable from platform-36.1 to
  platform-37.0, remove isPreview flag
- WorkloadManifest.in.json: Update workload packs from 36.1 to 37,
  add Mono/CoreCLR/NativeAOT runtime pack definitions for 37
- Xamarin.Android.Build.Tasks.targets: Use AndroidLatestStablePlatformId
  for SDK_PLATFORM_VERSION replacement (needed because ApiLevel=37 but
  PlatformId=37.0)
- BuildTest.cs: Hardcode MinorApiLevelFallbackThrowsXA5207 to use 36.1
  since 37.0 == 37 (no meaningful minor version distinction)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add acceptable-breakages-v17.0.txt for the v17.0 vs v16.1 API compat
check, and update acceptable-breakages-vReference-net11.0.txt with the
same breakages for the reference assembly comparison.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AndroidJavaRuntimeApiLevel was using AndroidLatestStableApiLevel (37),
but the Android SDK platform directory is android-37.0, not android-37.
Use AndroidLatestStablePlatformId (37.0) so java-runtime.csproj can
find android.jar.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Starting with API 37, Google ships the SDK platform as android-37.0
instead of android-37. Tests that hardcode platform.Major to construct
paths like "android-{platform.Major}/android.jar" fail because the
directory is actually android-37.0.

Add AndroidSdkResolver.GetPlatformDirectoryName() and GetAndroidJarPath()
helpers that check for both directory names and return the correct one.
Update Aapt2Tests and ManagedResourceParserTests to use these helpers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
net11.0-android36.1 is no longer valid on .NET 11 (API 37 is the only
supported target), so BundledVersions.targets silently upgrades to
API 37 and XA5207 never fires. Use net10.0-android36.1 instead since
36.1 is the supported API level for .NET 10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Starting with API 37, Google ships the SDK platform directory as
android-37.0 instead of android-37. Gradle compileSdk = 37 (integer)
looks for platforms/android-37 which does not exist.

Add GetCompileSdkGradleLine() helper that detects when the platform
directory uses the ".0" suffix and generates compileSdkPreview =
"android-37.0" instead of compileSdk = 37.

This fixes all AndroidGradleProjectTests (BuildApp, BindLibrary,
BindFacebook, BuildIncremental, BuildMultipleModules, etc.).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previous approach tried filesystem detection which was unreliable on
CI. Instead, use the known fact that API 37+ always ships as
android-{Major}.0 (e.g. android-37.0). For these API levels, generate
compileSdkPreview = "android-37.0" in the Gradle build file instead
of compileSdk = 37 (which looks for android-37 that does not exist).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The fundamental fix: xaprepare now creates a symlink from android-37
to android-37.0 after installing the SDK platform. This ensures Gradle
(which uses compileSdk = 37 and looks for android-37), our MSBuild
tasks, and all other tools can find the platform directory regardless
of whether they use the integer or ".0" form.

This reverts the compileSdkPreview approach (which was unreliable) in
favor of making both directory names work.

Also set xamarin_manifest_needs_updating = true in
AndroidDependenciesTests since the Xamarin manifest does not yet have
API 37 entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AGP 9.1.1 (April 2026) natively supports compileSdk = 37 with the
android-37.0 platform directory. No symlinks or compileSdkPreview
workarounds needed.

- Bump default AGP from 9.1.0 to 9.1.1
- Fix BindLibraryWithMultipleGradleVersions: AGP 9.0.0 only supports
  up to compileSdk 36, so hardcode that instead of using the default
- Remove xaprepare symlink creation (no longer needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lt-api-37-target

# Conflicts:
#	src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/ManagedResourceParserTests.cs
ReadAndroidManifest was constructing the platform path manually using
android-{apiLevel} which produces android-37 for API 37. But the
platform directory is android-37.0.

Use TryGetPlatformDirectoryFromApiLevel which already has the .0
fallback logic, fixing the org.apache.http.legacy.jar lookup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This test validates that targeting a minor API level (like 36.1) does
not silently fall back to the major version. With API 37 as the only
stable target and no minor version (37.1) yet, there is no valid
scenario to test. Re-enable when a minor API level is added.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the original test code from main (using XABuildConfig constants)
and just add the [Ignore] attribute. The test body will be correct when
a minor API level (e.g. 37.1) is added in the future.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lt-api-37-target

# Conflicts:
#	external/xamarin-android-tools
API 37 was still marked stable: false (preview), causing its
AndroidApiInfo.xml to have Stable=False. This made
LatestTargetFrameworkVersion() skip it, returning an empty apiLevel,
which led to empty targetSdkVersion in manifests and XAGMM7009 errors
in all device tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@jonathanpeppers

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@jonathanpeppers
Copy link
Copy Markdown
Member Author

✅ LGTM — Clean, well-structured API level migration

(Posted manually — the automated reviewer hit a GitHub API 422 error twice when trying to submit, see github/gh-aw#30662)

Summary: This PR correctly promotes API 37 (platform-37.0) to the sole default stable target for .NET 11, replacing the API 36.1 split. The changes are consistent across Configuration.props, AndroidToolchain, WorkloadManifest, and the build targets.

Positive callouts:

  • The ReadAndroidManifest.cs refactor to use TryGetPlatformDirectoryFromApiLevel is a solid improvement — it delegates platform directory resolution to the shared SDK infrastructure (which already handles the 37.0 fallback) instead of duplicating version-parsing logic inline.
  • Good addition of AndroidSdkResolver.GetPlatformDirectoryName() / GetAndroidJarPath() test helpers to centralize the platform path construction pattern across tests.
  • Appropriate [Ignore] on MinorApiLevelFallbackThrowsXA5207 with a clear comment explaining when to re-enable it.
  • Workload manifest changes correctly update both the packs list and pack definitions in lockstep.
  • AndroidLatestUnstable* properties now reference $(AndroidLatestStable*) — clean deduplication since they're identical.
  • AGP version bump to 9.1.1 and the compileSdk: 36 hardcode for AGP 9.0.0 (which doesn't support compileSdk 37) are well-commented.

Issues found:

Severity Count Category
⚠️ warning 1 Performance
💡 suggestion 1 Formatting

@jonathanpeppers

This comment was marked as outdated.

@jonathanpeppers

This comment was marked as outdated.

- Hoist TryGetPlatformDirectoryFromApiLevel above the foreach loop in
  ReadAndroidManifest since AndroidApiLevel is constant across iterations
- Add missing blank line before doc comment in AndroidSdkResolver

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers marked this pull request as ready for review May 6, 2026 16:51
Copilot AI review requested due to automatic review settings May 6, 2026 16:51
@jonathanpeppers jonathanpeppers added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant