Not sure if I am doing something wrong or this is a bug.
I grant location permission on a main thread but after that when I use following:
var location = await Geolocation.GetLocationAsync();
wrapped in a async task it throws PermissionException pEx with message: "Permission request must be invoked on main thread.".
I already granted permission so why does it throws this exception?
Permission is asked with Plugin.Permissions;
For IOS and Windows platform this is untested.
Should show lat, long since permission is granted.
Permission ex : "Permission request must be invoked on main thread.".
Permission request:

Task Execution:

I think you don't need to ask permition, the Essential does that for you
Of course. But if permission is already granted it will try to fetch latitude, longitude and altitude. In this scenario it throws exception "Permission request must be invoked on main thread.". I granted permission already. If I let Essential ask for permission from within task it's normal behavior to throw exception since is not UI thread. Lets say I want to perform some background work that make use of X.E Geolocation from time to time.
Ok, try use async void instead Task.Run. As you are doing the request inside an event it is ok to use async void
I know that it will work with async void. I intentionally want to run in a task. In example is just button click event that demonstrates the problem. As long it's in a task no matter how you invoked the task it will still throw same exception.
@Draco94 sorry for delay, i reproduce your case.Your mistake is in dealing with the Task... Here the snippet to solve the problem.
void Button_Clicked(object sender, EventArgs e)
{
try
{
var task = Geolocation.GetLocationAsync();
task.ContinueWith(x =>
{
var location = x.Result;
if (location != null)
DisplayAlert("Localização", $"latitude:{location.Latitude}, logintude:{location.Longitude}", "OK");
},TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
throw ex;
}
}
It seems to be working. Thank you for your time.
Hi again, it doesn't seem to work if you use another thread.
void RequestLocation(object sender, EventArgs e)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
try
{
var task = Geolocation.GetLocationAsync();
task.ContinueWith(x =>
{
var location = x.Result;
if (location != null)
DisplayAlert("Localização", $"latitude:{location.Latitude}, logintude:{location.Longitude}", "OK");
});
}
catch (Exception ex)
{
throw ex;
}
}).Start();
}
This for example throws exception "System.AggregateException: One or more errors occurred." and status of the task is faulted.
This was working in essential version 0.10.0 preview and lower.
I want to do some work in thread that includes Geolocation.GetLocationAsync();
This thread will run occasionally to collect latitude and longitude and save them to database.
I've seen release notes for version 0.11.0 and this is some of the issues closed #621.
Now I thought that #621 is related only when you're requesting the permission. So if permission dialog happen it must be on UI thread. Since I allowed it in UI thread when I after want to get latitude and longitude in other thread problems happen.
Hi @Draco94 , the multi-thread can be complex to handle... When you use new Thread(() =>{}); you run your code in background thread, and the request permission too, so you get an Exception. If you want to get the location periodically you can use the Device.StartTimer
I'm running into the same problem. Seems like it would be better to put the responsibility for initial permission request onto the developer and have GeoLocation except only if permissions haven't already been granted? Rather than do a UI operation to grant them.
And then... generalize permission checking/granting into its own independent XEssentials feature :)
Did you initialize stuff: https://docs.microsoft.com/en-us/xamarin/essentials/get-started?tabs=windows%2Candroid
Do you have a sample?
We also only allow you to call this from the UI thread in 1.0 when you need to get permissions. This is as designed.
Closing as this is the expected behavior. You should check to ensure you have permission before calling.
FWIW--
I did initialize stuff.
I did check to ensure I have permission before calling.
Here's an example that will reproduce for Android, iOS, and UWP. Location permissions are granted before reaching this.
Task.Run(
async () =>
{
var request = new GeolocationRequest(GeolocationAccuracy.High, new TimeSpan(0, 0, 4));
var location = await Geolocation.GetLocationAsync(request);
});
I'm hitting the following throw in the Permissions class. This is called by RequireAsync() which is called by PlatformLocationAsync().
```
internal static Task
{
if (!MainThread.IsMainThread)
throw new PermissionException("Permission request must be invoked on main thread.");
return PlatformRequestAsync(permission);
}
```
I don't think this will ever work from anything but the main thread, regardless whether I check for permissions before calling.
For now I don't need to be running this in a background thread, will refactor.
What version of the plugin are you using @klzig
@redth are we missing PRs from https://github.com/xamarin/Essentials/tree/dev/api-fix
Re-opened https://github.com/xamarin/Essentials/issues/621 as this seems to have missed a PR into master for 1.0.0.
I noticed this happening on version 0.11.0 preview and 1.0.0.
I'm on 1.0.0. Thanks.
Will be fixed in 1.0.1 as we missed a pr into a different branch.
Cool, thanks for the attention and the awesome plugin.
Hi
I'm getting this error as well.
I'm using 1.0.1 V but still get this error.
when i try to use this code in regular view it dosen't have any problem
but when i use this in RG popup view it crashes
I did check if we are running on main thread by MainThread.IsMainThread and I was running on mainThread
If you don't have permission it will still try to prompt the user on the main thread:
https://github.com/xamarin/Essentials/blob/master/Xamarin.Essentials/Permissions/Permissions.android.cs#L104
This is the correct design. You can use my https://github.com/jamesmontemagno/PermissionsPlugin to check before calling.
Hi @jamesmontemagno
Thank you for your response
But i did try that and got permission from user by permission plugin
but still it throw this exception.
you should know that if i use it in a regular view it works perfectly but in popup it throws this error
Can you give me a repro sample please @mo-kml
(Ran into similar issues (permissions not prompted but run from a ViewModel page.) In case it's helpful to someone - I've put the following solution below:
Same issue here, running 1.0.1. Permission is already granted (I double-checked it), but when GetLastKnownLocationAsync is called from other than the main thread the exception occurs:
Permission request must be invoked on main thread.
at Xamarin.Essentials.Permissions.RequestAsync (Xamarin.Essentials.PermissionType permission) [0x00007] in C:\agent\_work\69\s\Xamarin.Essentials\Permissions\Permissions.shared.cs:18
at Xamarin.Essentials.Permissions+<RequireAsync>d__3.MoveNext () [0x0000a] in C:\agent\_work\69\s\Xamarin.Essentials\Permissions\Permissions.shared.cs:25
--- End of stack trace from previous location where exception was thrown ---
at Xamarin.Essentials.Geolocation+<PlatformLastKnownLocationAsync>d__6.MoveNext () [0x00017] in C:\agent\_work\69\s\Xamarin.Essentials\Geolocation\Geolocation.android.cs:22
--- End of stack trace from previous location where exception was thrown ---
at XY.UserLocationProvider+<GetLastLocationAsync>d__0.MoveNext () [0x00038] in XY\UserLocationProvider.cs:20
Even if this issue is solved, and the PermissionException only occurs when the permission really has to be requested, it is still some kind of confusing. Because we never know if permission was already granted, we either have to
a) Always check for permission ourself before invoking GeoLocation (which would make the internal permission handling senseless)
or b) Use the solution given in the link by @andrewchungxam which is not that beautiful because Geolocation.GetLastKnownLocationAsync will always run on the main thread, even if not required.
Wouldn't it be better to either
a) Remove the internal permission handling in GeoLocation and state that everyone has to care for the permissions themselves
or b) Use Device.BeginInvokeOnMainThread within GeoLocation when really required?
I'm using version 1.1.0.
`try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
Location = string.Format("{0}{1}{2}", "Latitude: " + location.Latitude.ToString(),
System.Environment.NewLine, "Longitude: " + location.Longitude.ToString());
}
}
catch (FeatureNotSupportedException fnsEx)
{
//await DisplayAlert("Faild", fnsEx.Message, "OK");
}
catch (PermissionException pEx)
{
//awaits NavigationServices.DisplayAlert(string.Empty, "Please give location permission", "OK");
}
catch (Exception ex)
{
//await DisplayAlert("Faild", ex.Message, "OK");
}`
I have above code in Page OnAppearing method.
When I run the app , this code asks Popup for Permission.
if I deny then again page OnAppearing is getting called, but this time this code not asks for permission.
if I put app in background and open again.
Page OnAppearing method is getting call, above code is also executed, but it is not asking for permission popup.
@SagarPanwala the permission pop-up doesn't show because you have try to update the UI from background thread. Take care about that.
@jamesmontemagno, can we guarantee the permission will be run in MainThread? I think if this lines await Permissions.RequireAsync(PermissionType.LocationWhenInUse); runs in Main Thread this trouble doesn't happens.
Hi,
How can you say I tried to get it in background thread?
I normally do api call like this and it updates UI also.
Can you please explain how can I debug my code called from background
thread or from main thread?
On Wed, 8 May 2019, 10:04 p.m. Pedro Jesus, notifications@github.com
wrote:
@SagarPanwala https://github.com/SagarPanwala the permission pop-up
doesn't show because you have try to update the UI from background thread.
Take care about that.@jamesmontemagno https://github.com/jamesmontemagno, can we guarantee
the permission will be run in MainThread? I think if this lines await
Permissions.RequireAsync(PermissionType.LocationWhenInUse); runs in Main
Thread this trouble doesn't happens.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/xamarin/Essentials/issues/634#issuecomment-490558560,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACDWB3BR4FVGZYZ4CZL765DPUL6JHANCNFSM4GIKPSCQ
.
@SagarPanwala you can use this helper class.
public static class ThreadHelper
{
static bool IsMainThread => !Thread.CurrentThread.IsBackground;
public static void WhatThreadAmI([CallerMemberName] string method = "", [CallerLineNumber] int line = 0)
{
Console.WriteLine("################");
Console.WriteLine($"{method} : line {line}, is on MainThread:{IsMainThread}");
Console.WriteLine("################");
}
}
And just put the methodWhatThreadAmI(). Reference
@pictos : this is certainly not the case. I'm now doing thing on button click, so call is being made in Main Thread. Permission popup only shows first time, if I deny , after that it is not showing at all. I must have to restart the application.
@SagarPanwala how did you implemented this? Someone had the similar issue, and I suggest this snippet
I had this issue recently and solved it by making one of these changes in the Android project properties, Android options tab:
This problem still exists. I solved it by asking for the location permission beforehand.
Most helpful comment
Will be fixed in 1.0.1 as we missed a pr into a different branch.