-
Notifications
You must be signed in to change notification settings - Fork 564
[Mono.Android] Bind Android API-CANARY Beta 1 #10438
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
[Mono.Android] Bind Android API-CANARY Beta 1 #10438
Conversation
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 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 Currently, this will be usable in its preview form to `main` users who explicitly target `net10.0-android36.1`. This *may* be released in .NET 10 GA (2025-Nov) as `net10.0-android36.0`, or may be released later as `net10.0-android36.1`. ~~ Changes ~~ 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. 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+": `<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 is something we've never had to support before, so lots of associated changes to the build system are required to support it. Among the changes is the assumption that an API level is "just" an int. [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
jonathanpeppers
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some next steps, we need to probably use double.TryParse() here:
Lines 95 to 110 in b1eb50a
| static AndroidVersion ToVersion (ITaskItem item) | |
| { | |
| /* | |
| <AndroidApiInfo Include="v12.0.99"> | |
| <Name>Sv2</Name> | |
| <Level>32</Level> | |
| <Id>Sv2</Id> | |
| <Stable>False</Stable> | |
| </AndroidApiInfo> | |
| */ | |
| int.TryParse (item.GetMetadata ("Level"), out int apiLevel); | |
| bool.TryParse (item.GetMetadata ("Stable"), out bool stable); | |
| return new AndroidVersion (apiLevel, item.ItemSpec.TrimStart ('v'), item.GetMetadata ("Name"), item.GetMetadata ("Id"), stable); | |
| } |
But then, the AndroidVersion type doesn't have a non-int value to use!
We could maybe extend the type here and add a property?
But then AndroidVersion also needs updates for any other software using it.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Context: dotnet/android#10438 9 months ago in [The First Developer Preview of Android 16][0]: > **Two Android API releases in 2025** > > * This preview is for the next major release of Android with a > planned launch in Q2 of 2025. This release is similar to all of > our API releases in the past, where we can have planned > behavior changes that are often tied to a targetSdkVersion. > > * … > > * We plan to have another release in Q4 of 2025 which also will > include new developer APIs. The Q2 major release will be the > only release in 2025 to include planned behavior changes that > could affect apps. The 3rd bullet point is a "25Q4 MINOR SDK RELEASE" , thus introducing the *concept* of a "minor" SDK version, with semantics: * [`<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); Update `AndroidVersion` and `AndroidVersions` to better support the concept of "minor SDK releases": * Add a new `AndroidVersion.VersionCodeFull` property, which is a `System.Version` -- not an `int` -- for which `Version.Major` matches `AndroidVersion.ApiLevel`. * Add a new internal `AndroidVersion.Ids` property, which is the= full set of "aliases" that should be checked when doing an "id" match. This simplifies `AndroidVersions` logic. `Ids` contains: `ApiLevel`, VersionCodeFull`, and `Id`. * Change `AndroidVersions.AlternateIds` into a set-only property which updates `AndroidVersion.Ids`. * Bump `$(LangVersion)`=9.0 to use target-typed `new()`. [0]: https://android-developers.googleblog.com/2024/11/the-first-developer-preview-android16.html [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)
Context: dotnet/android#10438 9 months ago in [The First Developer Preview of Android 16][0]: > **Two Android API releases in 2025** > > * This preview is for the next major release of Android with a > planned launch in Q2 of 2025. This release is similar to all of > our API releases in the past, where we can have planned > behavior changes that are often tied to a targetSdkVersion. > > * … > > * We plan to have another release in Q4 of 2025 which also will > include new developer APIs. The Q2 major release will be the > only release in 2025 to include planned behavior changes that > could affect apps. The 3rd bullet point is a "25Q4 MINOR SDK RELEASE" , thus introducing the *concept* of a "minor" SDK version, with semantics: * [`<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); Update `AndroidVersion` and `AndroidVersions` to better support the concept of "minor SDK releases": * Add a new `AndroidVersion.VersionCodeFull` property, which is a `System.Version` -- not an `int` -- for which `Version.Major` matches `AndroidVersion.ApiLevel`. * Add a new internal `AndroidVersion.Ids` property, which is the= full set of "aliases" that should be checked when doing an "id" match. This simplifies `AndroidVersions` logic. `Ids` contains: `ApiLevel`, VersionCodeFull`, and `Id`. * Change `AndroidVersions.AlternateIds` into a set-only property which updates `AndroidVersion.Ids`. * Bump `$(LangVersion)`=9.0 to use target-typed `new()`. [0]: https://android-developers.googleblog.com/2024/11/the-first-developer-preview-android16.html [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)
Context: dotnet/android-tools@31609ca Changes: dotnet/android-tools@c4cb3db...31609ca * dotnet/android-tools@31609ca: [Xamarin.Android.Tools.AndroidSdk] "Minor" SDK version support (dotnet/android-tools#261) @jonathanpeppers [noted][0]: > We could maybe extend the type here and add a property? > > But then `AndroidVersion` also needs updates for any other software using it. dotnet/android-tools@31609cac updates `AndroidVersion` and `AndroidVersions` to better support the concept of "minor" SDK versions, allowing lookup via "minor" version on `AndroidVersions.GetIdFromApiLevel(string)`. This would allow `MonoAndroidHelper.SupportedVersions.GetIdFromApiLevel("36.1")` to find CANARY, if and when appropriate. 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)`. [0]: dotnet#10438 (review)
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Context: dotnet#10438 We can always call `Assert.Inconclusive()`, to prevent failing tests from contributors.
Context: #10438 We can always call `Assert.Inconclusive()`, to prevent failing tests from contributors. Also updated `PerformanceTest.cs`, as two tests needed to call `AssertCommercialBuild()`.
Reviewing jpobst's PR from Baklava DP1: * dotnet@2dd4f74 It looks like we are missing some changes in `Configuration.props` and other files.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
We will eventually need to do this for all the values, but one step at a time.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
More failing tests!
GetDependencyWhenBuildToolsAreMissingTest
platforms/android-36.0 should be a dependency.
at Xamarin.Android.Build.Tests.AndroidDependenciesTests.GetDependencyWhenBuildToolsAreMissingTest()
The assertion:
StringAssertEx.Contains ($"platforms/android-{apiLevel}", builder.LastBuildOutput, $"platforms/android-{apiLevel} should be a dependency.");
and with the new "Versions Everywhere" approach, `apiLevel` is now
a Version, and thus `apiLevel.ToString()` is `36.0`, *not* `36`.
However, the "obvious" fix of using `apiLevel.Major` is not future-
proof. *Eventually* API-CANARY will be stable as `android-36.1`,
at which point we *will* want the full `apiLevel.ToString()` output.
Try to address this by adding a new `StringAssertEx.Contains()`
overload which allows providing a set of expected values, and if
*any* value is found, the assert succeeds:
StringAssertEx.Contains (
anyOf: new [] { $"platforms/android-{apiLevel}", $"platforms/android-{apiLevel.Major}" },
collection: builder.LastBuildOutput,
message: $"platforms/android-{apiLevel} should be a dependency.");
This will now check for *both* `platforms/android-36` (which will
succeed now) *and* `platforms/android-36.0` (which will fail now, but
is needed for a future 36.1).
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Expected: 36 But was: "36"
Missing feed for 36.1
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Commit message: 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: https://github.com/dotnet/java-interop/compare/a5d7370963ea835f075ab779a79d1aac5b206014...f07b53855063a297a4b4d3d3b96900dd3729e82c
* 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 <[email protected]>
[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 |


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
Android 16 Quarterly Platform Release 2 (QPR2) Beta 1 has been released.
The Android 16 QPR2 Beta 1 Announcement suggests the following timeline:
Currently, this will be usable in its preview form to
mainusers who explicitly targetnet10.0-android36.1.This may be released in .NET 10 GA (2025-Nov) as
net10.0-android36.0, or may be released later asnet10.0-android36.1.~~ Changes ~~
Update
create-android-api.csprojto usejava-source-utils.jarinstead ofparam-name-importer.dll, asparam-name-importer.dllwas not able to import API-CANARY'sandroid-stubs-src.jar:More specifically:
As
param-name-importer.dlluses an Irony-based Java source parser, and we have a better Java source parser which can also output theparam-name-importer.dlltext format injava-source-utils.jarusejava-source-utils.jarinstead.Android 16 QPR2 adds an additional wrinkle: "minor" SDK versions are now A Thing™; see:
<uses-sdk/>:Using new APIs with major and minor releases:
What these mean is that "Android 16 QPR2" will not be API-37. It will be "API-36+":
<uses-sdk/>will specify e.g.android:targetSdkVersion="36"(not37), and runtime guards against Android 16 QPR2 will need to check against e.g.Build.VERSION_CODES_FULL#BAKLAVA_1, 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.0is "plain"/"original" API-36.net10.0-android36.1will be Android 16 QPR2 / API-CANARY.This is something we've never had to support before, so lots of associated changes to the build system are required to support it. Among the changes is the assumption that an API level is "just" an int.