Skip to content
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

Android API level or OS version for platform checks/TFM #43531

Closed
akoeplinger opened this issue Jul 1, 2020 · 9 comments
Closed

Android API level or OS version for platform checks/TFM #43531

akoeplinger opened this issue Jul 1, 2020 · 9 comments
Labels
untriaged New issue has not been triaged by the area owner

Comments

@akoeplinger
Copy link
Member

Neither the .NET 5 spec nor the minimum OS platform checks spec make it clear whether Android will be using the OS version (e.g. 4.3) or the API level (e.g. 21) for the version number.

@terrajobst @mhutch

@Happypig375
Copy link
Member

See https://github.com/dotnet/designs/blob/master/accepted/2020/minimum-os-version/minimum-os-version.md#nuget-manifest.

There is a mention of net6.0-android9.0. Therefore, OS version is used.

@terrajobst
Copy link
Contributor

terrajobst commented Jul 2, 2020

@mhutch

My working assumption was that we pick one model (either API level or OS version) because the various MSBuild properties/custom attribute are based on each other:

  1. <TargetPlatformVersion> is initialized by parsing <TargetFramework>
  2. <TargetPlatformMinVersion> defaults to <TargetPlatformVersion>
  3. [TargetPlatform] is generated from <TargetPlatformVersion>
  4. [MinimumOSPlatform] is generated from <TargetPlatformMinVersion>

If some of these values are API levels while others are OS versions, we'd need a mapping table at least somewhere in MSBuild. If we can contain it there, it might be workable. For instance, we might say that [MinimumOSPlatform] is the API level we only have to apply the translation in (4). I assume that Android allows asking the OS whether it supports a given API level, so that calls to RuntimeInformation.IsOSPlatformOrLater() would be using API levels too.

I would, however, push back on a design where the attributes use API levels while the OS checks use OS version because this would mean that developer no longer knows which versions to use in checks (even if we somehow could apply the mapping to the analyzer).

@mhutch
Copy link
Contributor

mhutch commented Jul 2, 2020

Agreed we should be consistent between attributes and build props.

I'm a little conflicted on this. Ultimately API levels are an important part of the Android developer experience and ecosystem, and they will be used in some parts of the toolchain, either internally or developer-facing. As such, the the API level to OS version mappings will exist somewhere in the tooling. However, using OS versions would be both consistent with our other platforms and more in line with how most folks think about Android.

@akoeplinger
Copy link
Member Author

akoeplinger commented Jul 2, 2020

However, using OS versions would be both consistent with our other platforms and more in line with how most folks think about Android.

I agree that they'd be more consistent with other platforms but I feel like most Android developers think in API levels.

It's what you set in your AndroidManifest.xml uses-sdk or what the docs tell you about when an API was introduced, e.g. https://developer.android.com/reference/android/net/wifi/WifiInfo#getRxLinkSpeedMbps() says Added in API level 29.

You'd need to manually translate that back to an OS version before you can pass it to RuntimeInformation.IsOSPlatformOrLater().

@mhutch
Copy link
Contributor

mhutch commented Jul 2, 2020

I agree that they'd be more consistent with other platforms but I feel like most Android developers think in API levels.

Fair, but this functionality will affect folks developing xplat libraries and apps, who may not think in the same way as developers who focus on Android.

I don't have strong feelings on which should be the canonical form but I think we need to make it easy to see the mappings. For example, we could define a set of constants such that ANDROID_API_29 with a docs tooltip of "Android 10.0" or vice versa, etc.

@terrajobst
Copy link
Contributor

Sorry, what I meant by consistent is within a given platform we are consistent between the various properties and attributes. I've got zero problems with Android using API levels while iOS uses OS versions. What I am concerned about is if an Android developer uses OS version for some properties but API levels in others. Does that make sense?

@jonpryor
Copy link
Member

jonpryor commented Jul 2, 2020

I'm torn.

The simple answer is to just use the API level everywhere. Thus:

This is also consistent with Android developer guidance, with <uses-sdk/> values, and more. The Xamarin.Android build system emits a set of __ANDROID_N__ defines, from 1 through the API level corresponding to $(TargetFrameworkVersion), such that __ANDROID_29__ is an existing symbol. I don't see why we would remove this functionality in .NET 6. (Therein lies part of the problem, actually: Xamarin.Android is already "inconsistent" here, with $(TargetFrameworkVersion) values being the OS version, but runtime version checks using API levels.)

Question: is using the API level everywhere even possible? Some "historical" constructs have required that values be parsable by Version.TryParse(), and Version.TryParse("29") is (was?) not a happy camper. (This question may not be relevant in the future .NET 6 world order; I don't know.)

However, I think that the API levels are "weird" and "big", and that net6.0-android11 looks much nicer than net6.0-android30. (There is no rhyme or reason to this opinion.)

My heart wants OS versions. My brain wants the simplicity of API levels.

@jonathanpeppers
Copy link
Member

The simple answer is to just use the API level everywhere.

After some discussion, we think using the Android API level makes the most sense:

  1. Android developers, in general, use API level in AndroidManifest.xml files:
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
  1. Java/Kotlin developers might use:
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
     // ...
}

// or the value of LOLLIPOP
if (android.os.Build.VERSION.SDK_INT >= 21) {
     // ...
}
  1. Android C/C++ developers might use:
#include <android/api-level.h>

#if __ANDROID_API__ >= 21
// ...
#endif

// or
#ifdef __ANDROID_API_L__ 
// ...
#endif

If we used the Android OS version in .NET, it seems like it would just be a source of confusion. Android 5.0 (for API 21) is not used in any of the above examples.

Android API levels are integers, so that is going to be one difference here. We would not have a $(TFM) like net5.0-android30.1.

@terrajobst terrajobst transferred this issue from dotnet/designs Oct 16, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Oct 16, 2020
@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

7 participants