Permissions Plugin for Xamarin (Simplifying Runtime Permissions)

JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

Just released my latest plugin to request permissions from shared code! Checkout my blog for details

Code: https://github.com/jamesmontemagno/Xamarin.Plugins/tree/master/Permissions

NuGet: http://www.nuget.org/packages/Plugin.Permissions

Example:

try
{
    var status = await CrossPermissions.Current.CheckPermissionStatus(Permission.Location);
    if (status != PermissionStatus.Granted)
    {
        if(await CrossPermissions.Current.ShouldShowRequestPermissionRationale(Permission.Location))
        {
            await DisplayAlert("Need location", "Gunna need that location", "OK");
        }

        var results = await CrossPermissions.Current.RequestPermissions(new[] {Permission.Location});
        status = results[Permission.Location];
    }

    if (status == PermissionStatus.Granted)
    {
        var results = await CrossGeolocator.Current.GetPositionAsync(10000);
        LabelGeolocation.Text = "Lat: " + results.Latitude + " Long: " + results.Longitude;
    }
    else if(status != PermissionStatus.Unknown)
    {
        await DisplayAlert("Location Denied", "Can not continue, try again.", "OK");
    }
}
catch (Exception ex)
{

    LabelGeolocation.Text = "Error: " + ex;
}
«1

Posts

  • hvaughanhvaughan USMember ✭✭✭
    edited December 2015

    @JamesMontemagno

    Awesome plugin. Just installed it and wrote some code following your example above. I am having an issue though when running the code on a Nexus 7 API 23 emulator and requesting Phone permissions, though I wonder if I am doing it wrong.

    When the app is first installed to the emulator it looks like all of the permissions I requested in the manifest are automatically switched to granted, which is fine, and when I run CheckPermissionStatus() it correctly returns PermissionStatus.Granted.

    The issue happens when I try and go into the emulator's settings and switch the 'Phone' permission off, whether I first kill the app or whether I switch it off while the app is running, and then I run the CheckPermissionStatus() again. The method still returns PermissionStatus.Granted.

    I would post a bug report in GitHub but I am currently not able to login to my GitHub account as I am waiting for a new phone in the mail and lost my damned recovery code.

    Code below:

    try {
        PermissionStatus status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
    
        if(status != PermissionStatus.Granted) {    //It has not been granted so lets ask
    
            if(await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(permission)) {
                await App.AppNavPage.DisplayAlert(permission + " Permission Request", "In order for the app to " + GetPermissionVerbString(permission) + ", permission must first be granted.", "OK");
            }
    
            Dictionary<Permission, PermissionStatus> results = await CrossPermissions.Current.RequestPermissionsAsync(permission);
            status = results[permission];
        }
    
        return status;
    
    } catch(Exception ex) {
        System.Diagnostics.Debug.WriteLine("\nIn App.Helpers.NetworkHelper.CheckRequestPermissionAsync() - Exception attempting to check or request permission to Permission.{0}:\n{1}\n", permission, ex);
        return PermissionStatus.Unknown;
    }
    
  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    Unfortunately the emulators don't emulate this well :( you ahve to use a physical device for testing. I have tested this out :)

  • hvaughanhvaughan USMember ✭✭✭

    Ahh, thanks for the quick response. I assumed it was not an issue with the plugin. Will have to find a device now.

    I also wanted to mention a tip for others, in terms of MainApplication.cs file that gets created from the other plugin. I had the following in my AssemblyInfo.cs which was causing errors right after the plugin was installed:
    #if DEBUG [assembly: Application(Debuggable = true)] #else [assembly: Application(Debuggable=false)] #endif

    I found this post which shows that you can simply cut and paste that same code and place it right above public class MainApplication : Application, Application.IActivityLifecycleCallbacks { in MainApplication.cs.

    Thanks again for all the work making the plugin!

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    Ahhh yeah good catch and I can add to the readme for sure, it is nice to have a base application class, unfortunately it is the only way to get the Activity for permissions, but it is cool that it works ;) on my github I also have an app in the app store to test all the plugins if you want to try it out.

  • hvaughanhvaughan USMember ✭✭✭

    O very cool. Never saw that sample app part on your GitHub. I will definitely check it out.

  • hvaughanhvaughan USMember ✭✭✭

    Another question, related to CurrentActivity.

    Would you suggest moving things such as the [Activity] attribute (not sure if this would actually build and run) and something like ACR's UserDialogs.Init(this); code into the MainApplication.OnCreate()?

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    You wouldn't move the Activity attributes as that is part of the building process, but you could move any Init calls into the Application on create

  • hvaughanhvaughan USMember ✭✭✭

    Cool. And one more I swear!

    Does the Media plugin already ask for permissions or do I need to write the code to do that myself?

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    @hvaughan In the latest version I handle it all for you automatically :)

  • hi ,

    Nexus 5 API 23 CrossPermissions.Current.CheckPermissionStatusAsyn this function always return PermissionStatus.Granted.

    my location is off and i dont have location permisssion.

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    Did you specify the permissions in your manifest?

  • sudhir.9350sudhir.9350 INUniversity ✭✭

    Hi James,

    i tried to use your plugin in my existing xamarin.forms app. but it does not start and give me an error that "The application could not be started. Ensure that the application has been installed to the target device and has a launchable activity (MainLauncher = true)."

    so any thoughts?

  • hvaughanhvaughan USMember ✭✭✭
    edited December 2015

    @sudhir.9350

    Just got the same issue myself out of no where (I do not really think I changed anything). I decided to try to update all Xam related plugins within the Android project. So right-clicked the Android project -> Manage Nuget Package.

    I first updated the Permissions Plugin which showed successful (and said yes to overwriting the previous MainApplication.cs file), then I updated the Activity Plugin which showed successful, then I updated the Connectivity which showed successful.

    Then I went to edit the MainApplication.cs file to the way I had it before and saw that it was missing entirely. When I looked at the solution wide plugins, I saw that the Permission plugin was now only installed in the Xamarin Forms project and the iOS project. So I reinstalled the Permissions plugin into the Android project, rebuilt everything, and now all is working fine.

    I have noticed this before where, after updating the Permissions Plugin, it seems to completely uninstall itself from the Android project and I have to go back an manually install it again. Not sure if it is related to the "Do you want to overwrite the MainApplication.cs file" prompt or not. Hope this helps.

  • sudhirthankisudhirthanki USMember

    Hi James,

    I have the same problem. I used xlab.Forms MediaPicker to capture image from nexus 5 device with api 23. I always get CrossPermissions.Current.CheckPermissionStatusAsync as PermissionStatus.Granted. I explicitly revoke(turn off) the permission from App Permission on my device, but still the CheckPermissionStatusAsync method returns granted.

    I am using xamarin.forms.

    Any thoughts?

  • hvaughanhvaughan USMember ✭✭✭
    edited January 2016

    James,

    It looks like something strange is happening and I am wondering if the permissions plugin has anything to do with it. It seems that before installing the plugin, pressing the home button to leave the application and then going and click the application button (NOT the shortcut) would bring the application back normally. But now it seems like when the application is already running and we go and click the application icon on the home screen (again, not the same as clicking the shortcut) the application seems to get restarted or at least does not go through the same process as if you were to open the multitask window view and click the running app's window.

    So for example:

    Open the application for first time ->
    Hit home button ->
    Click either the app shortcut or open the app from the multitask/window view ->
    Everything works as expected

    But if you instead:

    Open the application for first time ->
    Hit home button ->
    Open the application from application icon

    All of the logic in OnAppearing() that tells wether to force the user to login to the app again is skipped and it acts as if I have manually closed the application completely and restarted it.

    Edit: After manually commenting out all of the code in MainApplication.cs and the OnRequestPermissionsResult() callback, it seems to be working correctly again and not restarting the app.

    Edit #2: Posted the issue as a bug in GitHub

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    I will comment on the Github on all these since you created the issue, but not experiencing any of these issues here.

  • vicky_mikvicky_mik INMember

    @JamesMontemagno Hi,it works perfectly..But how can i handle the OnRequestPermissionResult()..? Becoz my code will end up with this above line while i execute my app at first time
    var results =await CrossPermissions.Current.RequestPermissionsAsync(new[] { Plugin.Permissions.Abstractions.Permission.Contacts });
    and it will retrieve contacts when i execute my Application at second Time.

    Thanks.

  • vicky_mikvicky_mik INMember

    @James Montemagno Thanks for ur Reply james. now its woring great. Awesome Plugin it saves a day to me.. :smile:

    i add this method in my MainActivity. and now its working great.

       public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
        {
            PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    

    Thanks.

  • RenjithPRenjithP USMember

    Hi,

    I am getting the status as granted even by using a physical device.
    var status = await CrossPermissions.Current.CheckPermissionStatus(Permission.Location);

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai

    What device and OS is it running?

  • CalvinFong.7458CalvinFong.7458 USMember

    Hey @JamesMontemagno, thanks for the great plugin.

    One issue for me, RequestPermissionsAsync is never completing (it displays a request to the user but does not return a results). For example, in the function below, the 'var status = ...' line is never reached.

    private async void RequestPhonePermission() {
        var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
        var status = results[Permission.Phone];    //THIS LINE IS NEVER HIT REGARDLESS OF USER INPUT
        if (status == PermissionStatus.Granted) {
            //stuff here
        }
    }
    

    I'm running Android 6.0. The Plugin.Permissions is version 1.1.7 (the latest i think).

    If i run the function a second time, it causes a crash (System.Threading.TaskCancelledException).

    Thanks,
    Calvin Fong

  • NoahLaBierNoahLaBier USMember

    I need to request permission for Bluetooth. That's not listed.

  • SylvainGravelSylvainGravel CAMember ✭✭

    @CalvinFong Are you running the permision request in a worker thread? I'm having the same problem in one app where that's the case...

    @CalvinFong.7458 said:
    Hey @JamesMontemagno, thanks for the great plugin.

    One issue for me, RequestPermissionsAsync is never completing (it displays a request to the user but does not return a results). For example, in the function below, the 'var status = ...' line is never reached.

    private async void RequestPhonePermission() {
    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
    var status = results[Permission.Phone]; //THIS LINE IS NEVER HIT REGARDLESS OF USER INPUT
    if (status == PermissionStatus.Granted) {
    //stuff here
    }
    }

    I'm running Android 6.0. The Plugin.Permissions is version 1.1.7 (the latest i think).

    If i run the function a second time, it causes a crash (System.Threading.TaskCancelledException).

    Thanks,
    Calvin Fong

  • SylvainGravelSylvainGravel CAMember ✭✭

    I can confirm this was my issue, I suppose that displaying the permission dialog in a worker thread screws things up...

    Here is a workaround but hopefully this can be fixed in the plugin.

        public async void Start()
        {
            UserPermission = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
    
            if (UserPermission != PermissionStatus.Granted)
            {
                MainThread.Context.Post(RequestPermission, null);
            }
            else
            {
                Completed?.Invoke(this);
            }
        }
    
        private async void RequestPermission(object context)
        {
            UserPermission = (await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location))[Permission.Location];
    
            Completed?.Invoke(this);
        }
    
  • GVxGVx USMember ✭✭✭

    @CalvinFong.7458 said:
    One issue for me, RequestPermissionsAsync is never completing (it displays a request to the user but does not return a results). For example, in the function below, the 'var status = ...' line is never reached.

    private async void RequestPhonePermission() {
    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
    var status = results[Permission.Phone]; //THIS LINE IS NEVER HIT REGARDLESS OF USER INPUT
    if (status == PermissionStatus.Granted) {
    //stuff here
    }
    }

    Do you have this in your MainActivity.cs ??

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { // this is called when a user allows or denies a permission CrossPermissions.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults); }

  • CalvinFongCalvinFong USMember ✭✭
    edited August 2016

    @SylvainGravel Thanks. I was using a worker thread (and since the method does generate a pop-up it makes sense that this should be on the main thread). I tried running it on the main thread using the following code, but I still have the same issue. Does this mean my issue is different? Or am I doing something wrong?
    Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => {
    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
    status = results[Permission.Phone];
    });

    @GVx Thanks for the help, this sounds like it's my problem. However, I'm not sure how to implement the function. There seems to be no OnRequestPermissionsResult to override in my MainActivity.cs. And OnRequestPermissionsResult doesn't exist as a method for CrossPermissions.Current for me.
    I'm using a shared project (not PCL) if that's relevant. Also MainActivity extends XFormsApplicationDroid in my App.

  • SylvainGravelSylvainGravel CAMember ✭✭
    edited August 2016

    @CalvinFong said: Or am I doing something wrong?
    Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => {
    var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Phone });
    status = results[Permission.Phone];
    });

    By setting your delegate async in the BeginInvokeOnMainThread call, you are starting it in a new thread again? I'm not sure honestly... I use C# thread contexts.

        class MainThread
        {
            private static MainThread mInstance = null;
    
            private SynchronizationContext mMainThreadContext;
            public static SynchronizationContext Context
            {
                get
                {
                    return mInstance.mMainThreadContext;
                }
            }
    
            public MainThread()
            {
                mInstance = this;
                mMainThreadContext = SynchronizationContext.Current;
            }
        }
    
  • GVxGVx USMember ✭✭✭

    @GVx Thanks for the help, this sounds like it's my problem. However, I'm not sure how to implement the function. There seems to be no OnRequestPermissionsResult to override in my MainActivity.cs. And OnRequestPermissionsResult doesn't exist as a method for CrossPermissions.Current for me.
    I'm using a shared project (not PCL) if that's relevant. Also MainActivity extends XFormsApplicationDroid in my App.

    Ah yes sorry this is how your function in MainActivity should look:

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { PermissionsImplementation.Current.OnRequestPermissionsAsyncResult(requestCode, permissions, grantResults); }

    Also my MainActivity is derived from FormsAppCompatActivity .. This is most likely why you are not seeing the override..

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { }

  • Dennis.StringifyDennis.Stringify USMember ✭✭

    Hi James,
    been seeing a weird problem, hoping that you might be able to help.

    Prior to your Permission plug in, I was doing the permissioning for location for Android Marshmallow, myself. What I would experience would be after the permission popup appears and the user either allows or denies access to location, and the app would then either navigate to a black screen, crash completely, or works as expected.

    I then removed all my custom permission code and plugged in your permissions plug in, but am seeing the exact same behavior. I've been testing on a Nexus 5X, LG G4 and OnePlus 3, all running Marshmallow.

    Any ideas?

    thanks,
    Dennis

  • ChrisVardonChrisVardon GBMember ✭✭

    Hi @JamesMontemagno ,

    I'm finding that var results = await CrossPermissions.Current.RequestPermissions asks the user for permission, I then press allow and nothing happens. It just hangs? Any help with this would be appreciated :/

    This is on an android marshmallow Samsung device

  • JohnHardmanJohnHardman GBUniversity ✭✭✭✭✭

    @JamesMontemagno - On UWP, running on desktop, CheckPermissionStatusAsync pops up the dialog saying

    Let YourApp access your precise location?
    To change this later, go to the Settings app.
    Yes No

    Surely that should happen in RequestPermissionsAsync as per other platforms?

  • Hello, I'm having an issue here:

    if (status != PermissionStatus.Granted)
    {
    if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Location))
    {
    await DisplayAlert("Need location", "Gunna need that location", "OK");
    }

    var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
    status = results[Permission.Location];
    }

    this code always skips the italic part, the dialog is never shown and the status is always Unknown... tested on a SAMSUNG Galaxy S6 and SAMSUNG J5 (both android 6)

  • SuatKorkmazSuatKorkmaz USMember ✭✭✭

    I'm trying to grant storage write permission on an Android 6 device without luck. Code is:

    private async void RequestStorageWritePermission()
            {
                try
                {
                    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
                    if (status != PermissionStatus.Granted)
                    {
                        if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Plugin.Permissions.Abstractions.Permission.Storage))
                        {
                            await Application.Current.MainPage.DisplayAlert("Storage Permission", "OK?", "OK");
                        }
    
                        var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Storage);
                        status = results[Permission.Storage];
                    }
    
                    if (status == PermissionStatus.Granted)
                    {
                        await Application.Current.MainPage.DisplayAlert("Storage Permission", "Granted!", "OK");
                    }
                    else if (status != PermissionStatus.Unknown)
                    {
                        await Application.Current.MainPage.DisplayAlert("Storage Permission", "Denied!", "OK");
                    }
                }
                catch (Exception ex)
                {
    
    
                }
    }
    

    Permission status is always unknown.

    Am I doing it wrong? Code usage looks very simple tho.

  • SuatKorkmazSuatKorkmaz USMember ✭✭✭

    False alarm. It works now.

    Just added
    CrossCurrentActivity.Current.Activity = this;

    to MainActivity.

    Thanks for this nice plugin.

  • feanchefeanche RUMember

    @SuatKorkmaz said:
    False alarm. It works now.

    Just added
    CrossCurrentActivity.Current.Activity = this;

    to MainActivity.

    Thanks for this nice plugin.

    Be so kind, show this part of the code in the main code. I'll be very grateful.

  • SuatKorkmazSuatKorkmaz USMember ✭✭✭
    edited April 28

    In MainActivity.cs:

            protected override void OnCreate(Bundle bundle)
            {
                base.OnCreate(bundle);
                CrossCurrentActivity.Current.Activity = this;
                global::Xamarin.Forms.Forms.Init(this, bundle);
                LoadApplication(new App());
            }
    
  • alekssmykalekssmyk USMember ✭✭✭

    @JamesMontemagno I use this plugin for getting location permission. When the application is installed on the first page I see the System Location Request Access Message, but on this page I dont have any logic with location. How can I provide first request location access message only on the page where location is using? I dont want to ask user about location on the login page.

  • hvaughanhvaughan USMember ✭✭✭

    @alekssmyk
    Would need to see your code, but generally, only run the request permission code when and where you need it.

«1
Sign In or Register to comment.