-
Notifications
You must be signed in to change notification settings - Fork 63
[generator] Support major.minor API levels #1360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jonathanpeppers
merged 1 commit into
dotnet:main
from
jonpryor:dev/jonpryor/jonp-minor-ApiLevels
Sep 8, 2025
Merged
[generator] Support major.minor API levels #1360
jonathanpeppers
merged 1 commit into
dotnet:main
from
jonpryor:dev/jonpryor/jonp-minor-ApiLevels
Sep 8, 2025
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0c95aed
to
2fae0ee
Compare
Context: dotnet/android#10438 Context: dotnet/android#10438 (comment) Android 16 Quarterly Platform Release 2 (QPR2) (API-CANARY) Beta 1 has been released. What makes API_CANARY unique in the history of Android is that it is a "minor" SDK version: * [`<uses-sdk/>`][3]: > It's not possible to specify that an app either targets or requires a minor SDK version. * [Using new APIs with major and minor releases][4]: > The new [`SDK_INT_FULL`][5] constant can be used for API checks… > > if (SDK_INT_FULL >= VERSION_CODES_FULL.[MAJOR or MINOR RELEASE]) { > // Use APIs introduced in a major or minor release > } > > You can also use the [`Build.getMinorSdkVersion()`][6] method to > get just the minor SDK version: > > minorSdkVersion = Build.getMinorSdkVersion(Build.VERSION_CODES_FULL.BAKLAVA); This is ***not*** "API-37". This is "API-36.1" This impacts *everything*: * `[SupportedOSPlatform]` should include the minor SDK value * `[UnsupportedOSPlatform]` should also include the minor SDK value. * `generator --api-level=API-LEVEL` should support the minor value and appropriately propagate the value. * … Add a new `Java.Interop.Tools.Generator.AndroidSdkVersion` type which holds the Android SDK version, both major (`ApiLevel)` and minor values (`MinorRevision)`. This is a value type which works like `System.Int32`/`System.Version`. Replace all instances of `int ApiLevel` (and equivalent) with `AndroidSdkVersion ApiLevel` (and equivalent). Update `[SupportedOSPlatform]`, `[UnsupportedOSPlatform]`, and `[ObsoletedOSPlatform]` attribute output to include the full SDK value. Update `NamingConverter.ParseApiLevel()` to support `MAJOR.MINOR` values within a `//@merge.SourceFile` value. *Note*: Changes to `NamingConverter.ParseApiLevel()` are largely a nothing-burger because the dotnet/android side usually has metadata: <attr api-since="36.1" path="/api//*[contains(@merge.SourceFile,'api-CANARY.xml.in')]" name="api-since">36.1</attr which explicitly adds/sets `//@api-since` based on the `//@merge.SourceFile` value. [3]: https://developer.android.com/guide/topics/manifest/uses-sdk-element [4]: https://developer.android.com/about/versions/16/features#using-new [5]: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL [6]: https://developer.android.com/reference/android/os/Build#getMinorSdkVersion(int)
2fae0ee
to
225d748
Compare
jonpryor
added a commit
to jonpryor/xamarin-android
that referenced
this pull request
Sep 4, 2025
Context: dotnet/java-interop#1360 `generator` changes to support `generator --api-level=36.1`.
jonpryor
added a commit
to jonpryor/xamarin-android
that referenced
this pull request
Sep 4, 2025
dotnet/java-interop#1360 allows `generator --api-level=36.1` to conceptually work, which is needed because `$(AndroidApiLevel)` is forwarded as `generator --api-level`. Thus: ./dotnet-local.sh build src/Mono.Android/*.csproj \ -p:AndroidApiLevel=36.1 -p:AndroidPlatformId=CANARY -p:AndroidFrameworkVersion=v16.1 \ -p:IsUnstableVersion=true -bl There were a couple problems with the above: Firstly, APIs added in API-CANARY weren't marked as `[SupportedOSPlatform("android36.1")]`. This was because `metadata` needed to be updated to set `//@api-since` to 36.1, not 36. Doh/oops. Secondly, we need a new set of `PublicAPI.*.txt` files in order for the Public API analyzer to "do its thing". Add them. `src/Mono.Android/PublicAPI/API-36.1/PublicAPI.Shipped.txt` is based on the union of `PublicAPI.Shipped.txt` and `PublicApi.Unshipped.txt` for API-36. The above `dotnet-local.sh` command now passes locally. TODO: update API compat checks. See also: bdc4ccc.
/azp run |
No pipelines are associated with this pull request. |
jonathanpeppers
approved these changes
Sep 8, 2025
jonpryor
added a commit
to jonpryor/xamarin-android
that referenced
this pull request
Sep 8, 2025
jonathanpeppers
pushed a commit
to dotnet/android
that referenced
this pull request
Sep 12, 2025
Context: https://developer.android.com/about/versions/16/qpr2/ Context: https://android-developers.googleblog.com/2025/08/android-16-qpr2-beta-1-is-here.html Changes: dotnet/java-interop@a5d7370...f07b538 * dotnet/java-interop@f07b5385: [generator] Support major.minor API levels (dotnet/java-interop#1360) Android 16 Quarterly Platform Release 2 (QPR2) Beta 1 has been released. * [API-CANARY Beta 1 vs. API-36][0] The Android 16 QPR2 Beta 1 [Announcement][1] suggests the following timeline: * Aug/Sep: Unstable Betas * Oct: Stable beta with a [Platform Stability milestone][2] * ???: Final Android 16 QPR2 adds an additional wrinkle: "minor" SDK versions are now A Thing™; see: * [`<uses-sdk/>`][3]: > It's not possible to specify that an app either targets or requires a minor SDK version. * [Using new APIs with major and minor releases][4]: > The new [`SDK_INT_FULL`][5] constant can be used for API checks… > > if (SDK_INT_FULL >= VERSION_CODES_FULL.[MAJOR or MINOR RELEASE]) { > // Use APIs introduced in a major or minor release > } > > You can also use the [`Build.getMinorSdkVersion()`][6] method to > get just the minor SDK version: > > minorSdkVersion = Build.getMinorSdkVersion(Build.VERSION_CODES_FULL.BAKLAVA); What these mean is that "Android 16 QPR2" *will not* be API-37. It will be "API-36.1": `<uses-sdk/>` will specify e.g. `android:targetSdkVersion="36"` (***not*** `37`), and runtime guards against Android 16 QPR2 will need to check against e.g. [`Build.VERSION_CODES_FULL#BAKLAVA_1`][7], documented as "Android 36.1". This in turn means that our historical approach to adding new API levels does not immediately apply. API-CANARY *will not be* API-37. `net10.0-android37.0` -- when it exists -- will not bind API-CANARY; it will bind Android 17, presumably in 2026. So what do we call it? We will need to call it `net10.0-android36.1`: * `net10.0-android36.0` is "plain"/"original" API-36. * `net10.0-android36.1` will be Android 16 QPR2 / API-CANARY. This will be usable in its preview form to `main` users who explicitly target `net10.0-android36.1`. This is unlikely to be released in .NET 10 GA (2025-Nov) as `net10.0-android36.1`. ~~ Changes: Minor SDK Versions ~~ "Minor" SDK versions are something we've never had to support before, so lots of associated changes to the build system and tooling are required to support it. Among the changes is the assumption that an API level is "just" an int. Update `create-android-api.csproj` to use `java-source-utils.jar` instead of `param-name-importer.dll`, as `param-name-importer.dll` was not able to import API-CANARY's `android-stubs-src.jar`: create-android-api failed with 2 error(s) (1.0s) EXEC : error (3050: 47) Invalid character: '''. More specifically: % dotnet bin/Debug/lib/packs/Microsoft.Android.Sdk.Darwin/36.0.0/tools/param-name-importer.dll \ "-source-stub-zip=$HOME/android-toolchain/sdk/platforms/android-CANARY/android-stubs-src.jar" \ "-output-text=src/Mono.Android/Profiles/api-CANARY.params.txt" \ -verbose -framework-only … java/lang/Character.java Error (3050:47) Invalid character: '''. As `param-name-importer.dll` uses an Irony-based Java source parser, and *we have a better* Java source parser which can *also* output the `param-name-importer.dll` text format in `java-source-utils.jar` use `java-source-utils.jar` instead. Update `GenerateSupportedPlatforms.cs` to look at `AndroidVersion.VersionCodeFull` instead of `AndroidVersion.ApiLevel`. This allows minor SDK versions to be present in `@(AndroidSdkSupportedTargetPlatformVersion)`. Update `GeneratedMonoAndroidProjitemsFile.cs` so that the generated `bin\Build$(Configuration)\Mono.Android.Apis.projitems` file contains `%(AndroidApiInfo.VersionCodeFull)` item metadata. Update `Mono.Android.targets` so that the generated `AndroidApiInfo.xml` file contains `<VersionCodeFull/>`, based on `%(VersionCodeFull)`. Add `InstallAndRunTests.DotNetInstallAndRunPreviewAPILevels()`, which uses the new `net10.0-android36.1` target framework and references one of the new Preview APIs. Add a new set of `PublicAPI.*.txt` files so that the Public API analyzer can "do its thing". `src/Mono.Android/PublicAPI/API-36.1/PublicAPI.Shipped.txt` is based on the union of `PublicAPI.Shipped.txt` and `PublicApi.Unshipped.txt` for API-36. Update the workloads to use `Microsoft.Android.Runtime.Mono.36.[RID]` packs. Fixes: …/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(119,5): error NETSDK1181: Error getting pack version: Pack 'Microsoft.Android.Runtime.Mono.36.1.android-arm64' was not present in workload manifests. …/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(119,5): error NETSDK1181: Error getting pack version: Pack 'Microsoft.Android.Runtime.Mono.36.1.android-x64' was not present in workload manifests. Update `XABuildConfig` so that all `*ApiLevel` fields are now `System.Version`, ***not*** `int`. This allows them to properly contain minor values. This in turn impacts "everything", changing many `int`s to `Versions`s. Additionally, update `XASdkTests.DotNetTargetFrameworks` to *not* always append `.0`. The use of `Version` handles this for us, nicely. Update `build.gradle` generation within unit tests to ensure that `compileSdk` et. al are `int` values. ~~ Changes: Disable lint checks for `@(AndroidGradleProject)` Tests ~~ Some `@(AndroidGradleProject)` tests were failing on CI: …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: FAILURE: Build failed with an exception. …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: * What went wrong: …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: Execution failed for task ':TestModule:lintVitalAnalyzeRelease'. …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: > A failure occurred while executing com.android.build.gradle.internal.lint.AndroidLintWorkAction …/Microsoft.Android.Sdk.Bindings.Gradle.targets(83,5): error XAGRDL0000: > For input string: "36.0" After a fair bit of digging around -- read the `.binlog`, find the `gradlew` invocation, *manually* run the `gradlew` invocation while adding `-d` go get diagnostic output, which in turn provides the `lint` invocation -- we see that `lint` is crashing with: Exception in thread "main" java.lang.NumberFormatException: For input string: "36.0" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:668) at java.base/java.lang.Integer.parseInt(Integer.java:786) at com.android.tools.lint.client.api.SimplePlatformLookup$Companion.platformFromSourceProp(SimplePlatformLookup.kt:256) at com.android.tools.lint.client.api.SimplePlatformLookup$Companion.addPlatforms(SimplePlatformLookup.kt:146) at com.android.tools.lint.client.api.SimplePlatformLookup$Companion.access$addPlatforms(SimplePlatformLookup.kt:113) at com.android.tools.lint.client.api.SimplePlatformLookup.<init>(SimplePlatformLookup.kt:65) at com.android.tools.lint.client.api.SimplePlatformLookup$Companion.get(SimplePlatformLookup.kt:118) at com.android.tools.lint.client.api.LintClient.getPlatformLookup(LintClient.kt:1045) at com.android.tools.lint.client.api.LintClient.getCompileTarget(LintClient.kt:1063) at com.android.tools.lint.detector.api.Project.getBuildTarget(Project.java:959) at com.android.tools.lint.LintCliClient$pickBuildTarget$2.invoke(LintCliClient.kt:1464) at com.android.tools.lint.LintCliClient$pickBuildTarget$2.invoke(LintCliClient.kt:1464) at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:210) at kotlin.sequences.FilteringSequence$iterator$1.calcNext(Sequences.kt:170) at kotlin.sequences.FilteringSequence$iterator$1.hasNext(Sequences.kt:194) at com.android.tools.lint.LintCliClient.pickBuildTarget(LintCliClient.kt:1947) at com.android.tools.lint.LintCliClient.getBootClassPath(LintCliClient.kt:1443) at com.android.tools.lint.Main$MainLintClient.getBootClassPath(Main.java:805) at com.android.tools.lint.LintCliClient.initializeProjects(LintCliClient.kt:1421) at com.android.tools.lint.client.api.LintClient.performInitializeProjects$lint_api(LintClient.kt:1009) at com.android.tools.lint.client.api.LintDriver.initializeProjectRoots(LintDriver.kt:569) at com.android.tools.lint.client.api.LintDriver.doAnalyze(LintDriver.kt:484) at com.android.tools.lint.client.api.LintDriver.analyzeOnly(LintDriver.kt:443) at com.android.tools.lint.LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:233) at com.android.tools.lint.LintCliClient$analyzeOnly$1.invoke(LintCliClient.kt:233) at com.android.tools.lint.LintCliClient.run(LintCliClient.kt:275) at com.android.tools.lint.LintCliClient.run$default(LintCliClient.kt:258) at com.android.tools.lint.LintCliClient.analyzeOnly(LintCliClient.kt:233) at com.android.tools.lint.Main.run(Main.java:1761) at com.android.tools.lint.Main.run(Main.java:284) at com.android.tools.lint.Main.main(Main.java:221) Of note is `SimplePlatformLookup$Companion.platformFromSourceProp()`, which reads the `source.properties` files within `$ANDROID_HOME/platforms/android-*/source.properties`. The problem is that API-CANARY's `source.properties` contains: AndroidVersion.ApiLevel=36.0 which `lint` doesn't like. `lint` has been fixed to support minor SDK versions, e.g. * https://cs.android.com/android-studio/platform/tools/base/+/5d246c720b206b7075a826d1bd4549882dd7c085 However, that commit was merged in 2025-May, while the latest cmdline-tools package is 19.0, released in 2025-March. Which means we have no `lint` package which has the fix! As a quick workaround, *disable* lint checks in the unit tests, by adding the block: android { lint { checkReleaseBuilds = false } } This *should* prevent `lint` from running at all, thus "fixing" the `NumberFormatException`. Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com> [0]: https://developer.android.com/sdk/api_diff/b-1-beta1/changes [1]: https://android-developers.googleblog.com/2025/08/android-16-qpr2-beta-1-is-here.html [2]: https://developer.android.com/about/versions/16/qpr2/overview#platform-stability [3]: https://developer.android.com/guide/topics/manifest/uses-sdk-element [4]: https://developer.android.com/about/versions/16/features#using-new [5]: https://developer.android.com/reference/android/os/Build.VERSION#SDK_INT_FULL [6]: https://developer.android.com/reference/android/os/Build#getMinorSdkVersion(int) [7]: https://developer.android.com/reference/android/os/Build.VERSION_CODES_FULL#BAKLAVA_1
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
[generator] Support major.minor API levels
Context: dotnet/android#10438
Context: dotnet/android#10438 (comment)
Android 16 Quarterly Platform Release 2 (QPR2) (API-CANARY) Beta 1
has been released. What makes API_CANARY unique in the history of
Android is that it is a "minor" SDK version:
<uses-sdk/>
:Using new APIs with major and minor releases:
This is not "API-37". This is "API-36.1"
This impacts everything:
[SupportedOSPlatform]
should include the minor SDK value[UnsupportedOSPlatform]
should also include the minor SDK value.generator --api-level=API-LEVEL
should include the minor valueAdd a new
Java.Interop.Tools.Generator.ApiLevel
type which holdsthe Android SDK version, both major and minor values. This is a
value type which works like
System.Int32
/System.Version
.Replace all instances of
int ApiLevel
(and equivalent) withApiLevel ApiLevel
(and equivalent).Update
[SupportedOSPlatform]
,[UnsupportedOSPlatform]
, and[ObsoletedOSPlatform]
attribute output to include the full SDK value.