Xamarin.Forms Runtime Permission Handling above Android 6.0

After Android 6.0, we have to using Runtime Persmissions. No more enaugth to create an Android.Manifest file. How can we correctly use it?

Step 1: Android.Manifest file

Still we have to create an Android.Manifest file, but a little bit otherwise. We have to use this way: https://developer.android.com/training/permissions/requesting#java. So, if we have used it so far as “uses-permission” before, from now we have to use it as “uses-permisson-sdk-<SDK_Version_Number>”. We can specify the max SDK version too.

<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_FINE_LOCATION" />

We have to specify the minimum SDK version of the application (https://developer.android.com/guide/topics/manifest/uses-sdk-element), because, if we don’t do, the minimum SDK version will be the 1.0. We can define the target and the max SDK version as well.

<uses-sdk android:minSdkVersion="23" />

Example Android.Manifest file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.companyname" android:versionCode="1" android:versionName="1.0.15" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="23" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_FINE_LOCATION" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_COARSE_LOCATION" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_MOCK_LOCATION" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.ACCESS_WIFI_STATE" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.INTERNET" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.READ_EXTERNAL_STORAGE" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.RECEIVE_SMS" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.SEND_SMS" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.WRITE_SMS" />
	<uses-permission-sdk-23 android:maxSdkVersion="28" android:name="android.permission.READ_SMS" />
	<application android:label="Application" android:icon="@drawable/icon">
		
	</application>
</manifest>

Step 2: Runtime Permission

Open the MainActivity.cs file in the Android Project. We have to create a Request to the user: “hello we have to use the calendar, location, sms, etc. when this app running”. The user will deside that, he/she will use these or not.

                var requiredPermissions = new string[]
                {
                    Manifest.Permission.AccessFineLocation,
                    Manifest.Permission.AccessCoarseLocation,
                    Manifest.Permission.AccessNetworkState,
                    Manifest.Permission.AccessLocationExtraCommands,
                    Manifest.Permission.AccessMockLocation,
                    Manifest.Permission.AccessNetworkState,
                    Manifest.Permission.AccessWifiState,
                    Manifest.Permission.Internet,
                    Manifest.Permission.WriteExternalStorage,
                    Manifest.Permission.ReadExternalStorage,
                    Manifest.Permission.ReceiveSms,
                    Manifest.Permission.SendSms,
                    Manifest.Permission.WriteSms,
                    Manifest.Permission.ReadSms
                };

                RequestPermissions(requiredPermissions, 1);

What have we done? We said that these permissions are neccessary to use at runtime and we created the request to the user. If any of theese permissions is not granted, it will be asked at the start of the application. If all were granted, nothing will happen. Okay, but what is “1” (the second param of the Request)? This is the request code, this can be another too, this is an app-defined code.

If we are corious, that our request is granted or not, we can override the OnRequestPermissionsResult() function.

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }

This function will response our permission request(s) result(granted or not).

Xamarin.Forms – Android – change the Theme at runtime

This project you can find at: https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime

In the .NET Standard/PCL Project we can’t say that, please change the Theme right now, because wehave to implement some platform specific implementation in the Android project.

How can the two project communicate? Now, we will see another way, unlike the previous ones, we will use events, not dependency service.

So, let’s create our event class in the .NET Standard/PCL Project (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/GlobalEvents.cs):

using System;
namespace XamarinFormsChangeAndoirdThemeRuntime
{
public class GlobalEvents
{
public static event EventHandler OnAndroidThemeChangeNeeded;
    
public static void OnAndroidThemeChangeNeeded_Event(object sender, int themeid)
    {
        OnAndroidThemeChangeNeeded?.Invoke(sender, themeid);
    }
   }
}

In the Android site, we will use the SetTheme(themeid) function, that set the Theme on the Application. We have to subscribe int the event int the MainActivity, and we have to call the SetTheme(themeid) method, in the main thread (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime.Android/MainActivity.cs):

using Android.App;
using Android.Content.PM;
using Android.OS;

namespace XamarinFormsChangeAndoirdThemeRuntime.Droid
{
    [Activity(Label = "XamarinFormsChangeAndoirdThemeRuntime", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

            GlobalVariables.MainThemeResourceID = Resource.Style.MainTheme;
            GlobalVariables.MainTransparentThemeResourceID = Resource.Style.MainTransparentTheme_Base;
            GlobalEvents.OnAndroidThemeChangeNeeded += GlobalEvents_OnAndroidThemeChangeNeeded; ;

            LoadApplication(new App());
        }

        private void GlobalEvents_OnAndroidThemeChangeNeeded(object sender, int themeid)
        {
            RunOnUiThread(() => {
                SetTheme(themeid);
            });
        }
    }
}

As you see, we gain the Theme’s Resource ID to the SetTheme(themeid) function. So we have to store theese Themes, in a global variable. Let’s create a class in the .NET Standard/PCL Project, and define static int variables as the Theme’s IDs (https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/GlobalVariables.cs):

namespace XamarinFormsChangeAndoirdThemeRuntime
{
    public class GlobalVariables
    {
        public static int MainThemeResourceID { get; set; }

        public static int MainTransparentThemeResourceID { get; set; }
    }
}

And now we have to just try theese codes. Let’s create a Page with two Buttons, and subscribe on their Click events:

https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsChangeAndoirdThemeRuntime.MainPage">
    <StackLayout>
        <Button x:Name="mainThemeButton" 
                Clicked="MainThemeButton_Clicked" 
                Text="MainTheme"/>
        <Button x:Name="mainTransparentButton" 
                Clicked="MainTransparentButton_Clicked" 
                Text="TransparentTheme"/>
    </StackLayout>
</ContentPage>

https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/blob/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime/MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace XamarinFormsChangeAndoirdThemeRuntime
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MainThemeButton_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(() => 
            {
                GlobalEvents.OnAndroidThemeChangeNeeded_Event(null, GlobalVariables.MainThemeResourceID);
            });
        }

        private void MainTransparentButton_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                GlobalEvents.OnAndroidThemeChangeNeeded_Event(null, GlobalVariables.MainTransparentThemeResourceID);
            });
        }
    }
}

I defined two Themes, theese Themes change a listview’s color. You can find they at: https://github.com/officialdoniald/Xamarin.Forms—Change-Android-Theme-at-runtime/tree/master/XamarinFormsChangeAndoirdThemeRuntime/XamarinFormsChangeAndoirdThemeRuntime.Android/Resources/values

Their was defined at the color.xml(link above).

Of cource you don’t have to do it this way, that was an extreme way, you can implement in the Android code, but if you want to use it from the .NET Standard/PCL Project, you have to write an event, or write through dependency service.

Fun fact: this GitHub project’s name is too large, so you can’t Debug it without renaming.