.NET MAUI: How to ensure that Android platform specific code is only executed on supported Android versions?
Asked Answered
O

3

10

I have various implementations of a partial class DeviceServices to provide platform specific implementations of certain device or OS specific features for Android, iOS and so on. My app is targeting API level 33.0 and the minimum version is API level 21.0.

Some APIs are specific to certain Android versions and higher, so I want to make sure that they only get called on the supported version. However, I always receive the following warning (and similar ones depending on the API being used):

warning CA1416: This call site is reachable on: 'Android' 21.0 and later. 'WindowInsets.Type.SystemBars()' is only supported on: 'android' 30.0 and later.

The following code to hide and show the system bars works on all my devices and the emulators that I have tried so far, but I am concerned about earlier Android versions. I still receive the warning above with it despite checking for the correct target API version:

static partial class DeviceServices
{
    private static Activity _activity;

    public static void SetActivity(Activity activity)
    {
        _activity = activity;
    }

    public static partial void HideSystemControls()
    {
#if ANDROID30_0_OR_GREATER
       if (Build.VERSION.SdkInt >= BuildVersionCodes.R) //R == API level 30.0
       {
            _activity?.Window?.InsetsController?.Hide(WindowInsets.Type.SystemBars());
       }
#endif
    }

    public static partial void ShowSystemControls()
    {
#if ANDROID30_0_OR_GREATER
       if (Build.VERSION.SdkInt >= BuildVersionCodes.R) //R == API level 30.0
       {
            _activity?.Window?.InsetsController?.Show(WindowInsets.Type.SystemBars());
       }
#endif
    }
}

So, what is the correct way to do this? I'm not sure how to proceed. I've used platform-specific APIs plenty of times and never had any problems with it before, but this warning concerns me. I had a look at the support article about this warning already, too, but I didn't find it very helpful: https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416. I also don't want to suppress the warnings. Maybe I am missing something here or can I simply ignore the warning in this case?

Update:

I am using Visual Studio 2022 17.4 Preview 2.1 and .NET 7.0 RC1.

I have also tried calling the APIs directly from within the MainActivity, but keep receiving the same warnings after a rebuild.

Update 2:

Here is a sample repository where the problem can be reproduced, just uncomment the following code block in the MainActivity.cs file:

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        
//#if ANDROID30_0_OR_GREATER
//        if (Build.VERSION.SdkInt >= BuildVersionCodes.R) //R == API level 30.0
//        {
//            Window?.InsetsController?.Hide(WindowInsets.Type.SystemBars());
//        }
//#endif
    }
Octangular answered 22/10, 2022 at 17:4 Comment(6)
You have to check the api level at runtime. #if is compile timeCharmian
Yes, I'm aware that preprocessor directives are compile time checks. That's why I also tried the second approach, but it didn't help, either.Octangular
Your 2nd example is still wrapped in an #ifCharmian
I've updated the question. I also receive the warning without the #if. That's why I tried adding that. When it's compiled against API 29 or less, it shouldn't even show up in the MSIL code, right?Octangular
is there an actual problem you're trying to fix, or are you just trying to address the warning message? I suspect the compiler simply isn't "smart" enough to recognize that the suspect code is wrapped in an check for the API levelCharmian
@Charmian I want to avoid that the warning actually becomes a problem. There is probably a good reason for it and I haven't had this problem before when checking for the API level.Octangular
O
0

I've tested with different Android emulators and API versions now and so far, there is no actual problem despite the warnings. It seems they are false flags, possibly because the runtime checks are not evaluated by the compiler. Since I don't want to disable the warnings explicitly, I will just have to ignore them for now.

UPDATE

I've removed the SetActivity() and switched to using Microsoft.Maui.ApplicationModel.Platform.CurrentActivity and now the warnings are gone:

using AndroidPlatform = Microsoft.Maui.ApplicationModel.Platform;

static partial class DeviceServices
{
    public static partial void HideSystemControls()
    {
       if (Build.VERSION.SdkInt >= BuildVersionCodes.R) //R == API level 30.0
       {
            AndroidPlatform.CurrentActivity?.Window?.InsetsController?.Hide(WindowInsets.Type.SystemBars());
       }
    }
}
Octangular answered 24/10, 2022 at 9:59 Comment(0)
L
22

Use OperatingSystem.IsAndroidVersionAtLeast, instead of Build.VERSION.SdkInt. Like this:

if (OperatingSystem.IsAndroidVersionAtLeast(30))
{
    _activity?.Window?.InsetsController?.Hide(WindowInsets.Type.SystemBars());
}

You should get no warnings after this.

More documentation is here: https://learn.microsoft.com/en-us/dotnet/api/system.operatingsystem.isandroidversionatleast

Lenoralenore answered 12/11, 2022 at 9:52 Comment(3)
Thanks, for the proposed solution. I managed to solve it using Microsoft.Maui.ApplicationModel.Platform.CurrentActivity in my Android-specific class.Octangular
@Lenoralenore why instead of Build.VERSION.SdkInt, is IsAndroidVersionAtLeast better in some way or is Build.VERSION.SdkInt becoming obsolete?Mendelsohn
@CRice, not sure, was some time I worked with this :-) But at least IsAndroidVersionAtLeast removes compiler warnings.Lenoralenore
A
1

At first, I created a new sample and added the code you provided in the MainActivity, there is no any warning message. So you can also have a try.

And then, I created a new class just like you did, there was also no any warning. And the Composition of the solution:

  1. Visual Studio 2022 17.4 preview 2.1
  2. add <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" android:maxSdkVersion="33"/> this in the AndroidManifest.xml
  3. In my project's build settings file, the Android Target FrameWork is Android api 31.

In addition, for the android part in the maui, there is only one Activity nameed MainActivity which is inherited from the AppCompactActivity. So you don't need to declare the static partial class DeviceServices for android, you can just do this in the mainactivity. Furthermore, the Activity and the AppCompactActivity are not same.

Anglophobia answered 24/10, 2022 at 6:26 Comment(8)
Thank you for your answer. Unfortunately, that doesn't solve the problem for me. I've added the <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" /> to my AndroidManifest.xml and the warning still shows up. The DeviceServices are required in my scenario as I am not calling the the APIs from within the MainActivity but from the code behind of my Views, so that's on purpose and is unrelated to the problem at hand, AFAIK. Changing from Activity to MainActivity doesn't make a difference here, but is a good idea. The API calls work, I'm just concerned about the warnings.Octangular
You can try to update the Visual Studio or create a new project to test, this warning never appear in my project. @ewerspejAnglophobia
And when you try the code in the mainactivity, did you get the warning? @ewerspejAnglophobia
Yes I do. I just updated the question with that information.Octangular
I'll try to reproduce the issue with a new solution.Octangular
Did you get the warning in the new solution? @ewerspejAnglophobia
Yes, in a different solution, I get the same problem. I reused a small and recently created solution instead of an entirely new one, but it should suffice. I have added a link to the repo to the question.Octangular
Although this doesn't directly solve the issue. your hint about Activity and AppCompatActivity (or even MauiActivity) not being the same got me thinking. I dug a little deeper and found out that those are not even related inheritance-wise. Instead, a conversion takes place during the assignment (probably using the explicit operator). Therefore, I switched to using Microsoft.Maui.ApplicationModel.Platform.CurrentActivity which solved the issueOctangular
O
0

I've tested with different Android emulators and API versions now and so far, there is no actual problem despite the warnings. It seems they are false flags, possibly because the runtime checks are not evaluated by the compiler. Since I don't want to disable the warnings explicitly, I will just have to ignore them for now.

UPDATE

I've removed the SetActivity() and switched to using Microsoft.Maui.ApplicationModel.Platform.CurrentActivity and now the warnings are gone:

using AndroidPlatform = Microsoft.Maui.ApplicationModel.Platform;

static partial class DeviceServices
{
    public static partial void HideSystemControls()
    {
       if (Build.VERSION.SdkInt >= BuildVersionCodes.R) //R == API level 30.0
       {
            AndroidPlatform.CurrentActivity?.Window?.InsetsController?.Hide(WindowInsets.Type.SystemBars());
       }
    }
}
Octangular answered 24/10, 2022 at 9:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.