You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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代码里有两个致命问题:

  1. TryGetLocationAsync方法从来没被调用过——权限请求流程根本没启动!
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:52:35