Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Location permission for Android above 6.0 with Xamarin.Forms.Maps

I'm trying to implement a Xamarin.Forms application using Xamarin.Forms.Maps, however I always fall into the exception:

Java.Lang.SecurityException: my location requires permission ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION

I have already tried following the steps in this tutorial https://blog.xamarin.com/requesting-runtime-permissions-in-android-marshmallow/ but did not get results.

Would anyone have something more consistent to help me?

What I'm intending is to use an application very close to Uber and I can not progress if I can not get the location permissions.

My MainPage looks like this in my PCL:

public partial class MainPage: ContentPage
    {
        public MainPage ()
        {
            InitializeComponent ();
            var map = new Map ()
            {
                MapType = MapType.Street,
                IsShowingUser = true
            };

            var stack = new StackLayout {Spacing = 0};
            stack.Children.Add (map);

            Content = stack;
        }
    }

My MainActivity class in Xamarin.Android looks like this:

[Activity (Label = "ExampleGeolocation", Icon = "@ drawable / icon",
              Theme = "@ style / MainTheme", MainLauncher = true,
              ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

    public class MainActivity: global :: Xamarin.Forms.Platform.Android.FormsAppCompatActivity, ActivityCompat.IOnRequestPermissionsResultCallback
    {
        View layout;
        const int RequestLocationId = 0;
        readonly string [] PermissionsLocation = {Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation};

        protected override void OnCreate (Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate (bundle);

            global :: Xamarin.Forms.Forms.Init (this, bundle);
            global :: Xamarin.FormsMaps.Init (this, bundle);

            Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity = this;

            SetStatusBarColor (Android.Graphics.Color.Black);
            LoadApplication (new App ());
        }

        public override async void OnRequestPermissionsResult (int requestCode, string [] permissions, [GeneratedEnum] Permission [] grantResults)
        {
            switch (requestCode)
            {
                case RequestLocationId:
                    {
                        if (grantResults [0] == Permission.Granted)
                        {
                            var snack = Snackbar.Make (layout, "Location Permission is Available.", Snackbar.LengthShort);
                            snack.Show ();

                            await GetLocationAsync ();
                        }
                        else
                        {
                            var snack = Snackbar.Make (layout, "Location Permission Denied", Snackbar.LengthShort);
                            snack.Show ();
                        }
                    }

                    break;
            }
        }

        async Task TryGetLocationAsync ()
        {
            if ((int) Build.VERSION.SdkInt <23)
            {
                await GetLocationAsync ();
                return;
            }

            await GetLocationPermissionAsync ();
        }

        async Task GetLocationPermissionAsync ()
        {
            const string permission = Manifest.Permission.AccessFineLocation;

            if (CheckSelfPermission (permission) == Permission.Granted)
            {
                await GetLocationAsync ();
                return;
            }

            if (ShouldShowRequestPermissionRationale (permission))
            {
                Snackbar.Make (layout, "You must allow the application to access your location options.", Snackbar.LengthIndefinite)
                        .SetAction ("OK", v => RequestPermissions (PermissionsLocation, RequestLocationId))
                        .Show();

                return;
            }

            RequestPermissions (PermissionsLocation, RequestLocationId);
        }

        async Task GetLocationAsync ()
        {
            try
            {
                var locator = CrossGeolocator.Current;
            }
            catch (Exception e)
            {
                e.ToString ();
                throw new NotImplementedException ();
            }
        }
    };
like image 213
Alisson Boucinhas Avatar asked Jan 28 '18 14:01

Alisson Boucinhas


3 Answers

Location permission for Android above 6.0 with Xamarin.Forms.Maps

You wrote a lot of code about permission but I can't find where you request the permission, you need request the permission before you use it.

When you set IsShowingUser property to true, you should request the permission first, here are three solutions.

Solution 1:

I notice that you are using PermissionsPlugin in your code, if you need request this permission in PCL, you could refer to the PermissionsPlugin official sample.

Add this code in your MainActivity:

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

Request permission when you need it:

try
{
    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
    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];
     }

     if (status == PermissionStatus.Granted)
     {
         //Permission granted, do what you want do.
     }
     else if(status != PermissionStatus.Unknown)
     {
         await DisplayAlert("Location Denied", "Can not continue, try again.", "OK");
     }
}
catch (Exception ex)
{
    //...
}

Solution 2:

When you open your application, request the permission first, in MainActivity OnStart method:

protected override void OnStart()
{
    base.OnStart();

    if (ContextCompat.CheckSelfPermission(this, permission) != Permission.Granted)
    {
        ActivityCompat.RequestPermissions(this, new String[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }, 0);
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("Permission Granted!!!");
    }
}

Solution 3:

Use DependencyService to request the permission when you need it, here is the sample related to the tutorial you have read. In this example, it requests permission when execute this line:

buttonGetLocation.Click += async (sender, e) => await TryGetLocationAsync();
like image 123
York Shen Avatar answered Oct 12 '22 11:10

York Shen


add this inside android MainActiviy OnCreate()

Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity = this;

add this to android mainactivity:

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

then this code will function, prompting user for location permission.

                var locator = CrossGeolocator.Current;
                locator.DesiredAccuracy = 1000;
                var position = await locator.GetPositionAsync(timeoutMilliseconds: 10000);

refer to:

https://jamesmontemagno.github.io/GeolocatorPlugin/

like image 33
pollaris Avatar answered Oct 12 '22 11:10

pollaris


Be sure that you have set all necessary permissions. If you want to use Xamarin.Forms.Maps on Android be sure that you have the following permissions set in the AndroidManifest.xml file of your project:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

You can also set the permissions by clicking with the right mouse on your Android Project and selecting Properties. Go to the tab Android Manifest and mark all necessary permissions.

Be also sure that you have added the following two Statements in the application tag:

<meta-data android:name="com.google.android.geo.API_KEY" android:value="ADD_YOUR_KEY_HERE" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
like image 22
Sebastian Jensen Avatar answered Oct 12 '22 11:10

Sebastian Jensen