Android 6.0及以上版本Xamarin.Forms.Maps定位权限问题求助
解决Xamarin.Forms.Maps定位权限异常的可靠方案
我来帮你搞定这个定位权限的问题!看了你的代码,发现几个关键的疏漏点,咱们一步步调整就能解决:
第一步:先确认AndroidManifest.xml的权限声明
这是最容易被忽略的基础——你必须在Android项目的AndroidManifest.xml里添加定位权限,否则代码里的权限请求全白搭:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 如果你的应用需要在后台也获取位置(比如类似Uber的实时追踪),Android 10+还要加这个: --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="32" />
第二步:修复MainActivity里的核心问题
你的MainActivity代码里有两个致命问题:
TryGetLocationAsync方法从来没被调用过——权限请求流程根本没启动!layout变量没初始化,导致Snackbar.Make(layout...)会直接崩溃。
修改后的MainActivity代码:
[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); // 初始化layout,解决Snackbar找不到View的问题 layout = Window.DecorView.FindViewById(Android.Resource.Id.Content); 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()); // 启动权限请求流程,这一步你之前漏掉了! Task.Run(async () => await TryGetLocationAsync()); } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) { base.OnRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case RequestLocationId: { // 检查所有请求的定位权限是否都被授予 bool allPermissionsGranted = grantResults.All(result => result == Permission.Granted); if (allPermissionsGranted) { var snack = Snackbar.Make(layout, "Location Permission is Available.", Snackbar.LengthShort); snack.Show(); // 通知PCL端权限已授予,更新地图 MessagingCenter.Send<object>(this, "LocationPermissionGranted"); 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() { // 同时检查两种定位权限 bool hasFineLocation = CheckSelfPermission(Manifest.Permission.AccessFineLocation) == Permission.Granted; bool hasCoarseLocation = CheckSelfPermission(Manifest.Permission.AccessCoarseLocation) == Permission.Granted; if (hasFineLocation && hasCoarseLocation) { await GetLocationAsync(); return; } // 显示权限 rationale(如果系统认为需要) if (ShouldShowRequestPermissionRationale(Manifest.Permission.AccessFineLocation) || ShouldShowRequestPermissionRationale(Manifest.Permission.AccessCoarseLocation)) { Snackbar.Make(layout, "You must allow location access to use this feature.", Snackbar.LengthIndefinite) .SetAction("OK", v => RequestPermissions(PermissionsLocation, RequestLocationId)) .Show(); return; } // 直接请求权限 RequestPermissions(PermissionsLocation, RequestLocationId); } async Task GetLocationAsync() { try { var locator = CrossGeolocator.Current; locator.DesiredAccuracy = 50; // 设置定位精度 // 主动获取一次位置 var position = await locator.GetPositionAsync(TimeSpan.FromSeconds(10)); Console.WriteLine($"Got location: Lat {position.Latitude}, Lon {position.Longitude}"); } catch (Exception e) { Console.WriteLine($"Location error: {e.Message}"); Snackbar.Make(layout, $"Failed to get location: {e.Message}", Snackbar.LengthShort).Show(); } } }
第三步:调整PCL的MainPage,避免提前触发异常
你之前直接设置IsShowingUser = true,这时候权限还没拿到,必然会抛出SecurityException。咱们改成权限授予后再启用这个功能:
public partial class MainPage : ContentPage { private Map _map; public MainPage() { InitializeComponent(); // 先把IsShowingUser设为false,避免权限未授权时触发异常 _map = new Map() { MapType = MapType.Street, IsShowingUser = false }; var stack = new StackLayout { Spacing = 0 }; stack.Children.Add(_map); Content = stack; // 监听Android端发来的权限授予通知 MessagingCenter.Subscribe<object>(this, "LocationPermissionGranted", (sender) => { // 回到UI线程更新地图 Device.BeginInvokeOnMainThread(() => { _map.IsShowingUser = true; }); }); } }
几个关键注意点:
- 权限请求必须在应用启动后主动触发(也就是调用
TryGetLocationAsync),否则系统不会弹出权限申请弹窗。 - 不要在权限未确认前开启地图的
IsShowingUser,这是你当前异常的直接原因。 - 处理权限结果时,要确保所有请求的权限都被授予,而不是只检查第一个。
内容的提问来源于stack exchange,提问作者Alisson Boucinhas
相关产品推荐
相关产品推荐

