获取用户位置

重要

必应地图企业版服务停用

Windows.Services.Maps 命名空间中的 UWP MapControl 和地图服务依赖于必应地图。 必应地图企业版已弃用,并且将停用,届时 MapControl 和服务将不再接收数据。

有关详细信息,请参阅必应地图开发人员中心必应地图文档

注意

MapControl 和地图服务需要称为 MapServiceToken 的地图身份验证密钥。 有关获取和设置地图身份验证密钥的详细信息,请参阅请求地图身份验证密钥

查找用户的位置并响应位置更改。 访问用户的位置由 Windows 设置应用中的隐私设置管理。 本主题还介绍了如何查看你的应用是否具有访问用户位置的权限。

启用位置功能

  1. 解决方案资源管理器中,双击 package.appxmanifest 并选择功能选项卡。
  2. 功能列表中,选中位置框。 这将向程序包清单文件中添加 location 设备功能。
  <Capabilities>
    <!-- DeviceCapability elements must follow Capability elements (if present) -->
    <DeviceCapability Name="location"/>
  </Capabilities>

获取当前位置

此部分介绍如何使用 Windows.Devices.Geolocation 命名空间中的 API 检测用户的地理位置。

步骤 1:请求访问用户的位置

除非你的应用具有 coarse location 功能(参见备注),否则在尝试访问用户的位置之前,必须使用 RequestAccessAsync 方法请求对该位置的访问权限。 必须从 UI 线程调用 RequestAccessAsync 方法,并且你的应用必须在前台。 只有在用户授予相应的应用权限后,你的应用才可以访问用户的位置信息。*

using Windows.Devices.Geolocation;
...
var accessStatus = await Geolocator.RequestAccessAsync();

RequestAccessAsync 方法提示用户提供访问其位置的权限。 仅提示用户一次(每个应用)。 在他们第一次授予或拒绝授予权限之后,此方法不会再提示用户提供权限。 若要在提示之后帮助用户更改位置权限,我们建议提供位置设置的链接,如本主题中后面部分所示。

注意

粗略的位置功能允许你的应用在不获得用户的显式权限的情况下获取有意模糊(不精确)的位置(但系统范围的位置开关仍 必须打开)。 若要了解如何在应用中利用 coarse location,请参阅 Geolocator 类中的 AllowFallbackToConsentlessPositions 方法。

步骤 2:获取用户的位置并注册位置权限的更改

GetGeopositionAsync 方法执行当前位置的一次读取。 此处,一个语句与 accessStatus(上一switch示例)一起使用,仅当允许访问用户的位置时才能执行操作。 如果允许访问用户位置,该代码将创建 Geolocator 对象、注册位置权限的更改,并请求用户位置。

switch (accessStatus)
{
    case GeolocationAccessStatus.Allowed:
        _rootPage.NotifyUser("Waiting for update...", NotifyType.StatusMessage);

        // If DesiredAccuracy or DesiredAccuracyInMeters are not set (or value is 0), DesiredAccuracy.Default is used.
        Geolocator geolocator = new Geolocator { DesiredAccuracyInMeters = _desireAccuracyInMetersValue };

        // Subscribe to the StatusChanged event to get updates of location status changes.
        _geolocator.StatusChanged += OnStatusChanged;

        // Carry out the operation.
        Geoposition pos = await geolocator.GetGeopositionAsync();

        UpdateLocationData(pos);
        _rootPage.NotifyUser("Location updated.", NotifyType.StatusMessage);
        break;

    case GeolocationAccessStatus.Denied:
        _rootPage.NotifyUser("Access to location is denied.", NotifyType.ErrorMessage);
        LocationDisabledMessage.Visibility = Visibility.Visible;
        UpdateLocationData(null);
        break;

    case GeolocationAccessStatus.Unspecified:
        _rootPage.NotifyUser("Unspecified error.", NotifyType.ErrorMessage);
        UpdateLocationData(null);
        break;
}

步骤 3:处理位置权限的更改

Geolocator 对象触发 StatusChanged 事件以指示用户位置设置已更改。 该事件通过参数的 Status 属性(类型为 PositionStatus)传递相应的状态。 请注意,此方法不是从 UI 线程中调用的,并且 Dispatcher 对象调用了 UI 更改。

using Windows.UI.Core;
...
async private void OnStatusChanged(Geolocator sender, StatusChangedEventArgs e)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        // Show the location setting message only if status is disabled.
        LocationDisabledMessage.Visibility = Visibility.Collapsed;

        switch (e.Status)
        {
            case PositionStatus.Ready:
                // Location platform is providing valid data.
                ScenarioOutput_Status.Text = "Ready";
                _rootPage.NotifyUser("Location platform is ready.", NotifyType.StatusMessage);
                break;

            case PositionStatus.Initializing:
                // Location platform is attempting to acquire a fix.
                ScenarioOutput_Status.Text = "Initializing";
                _rootPage.NotifyUser("Location platform is attempting to obtain a position.", NotifyType.StatusMessage);
                break;

            case PositionStatus.NoData:
                // Location platform could not obtain location data.
                ScenarioOutput_Status.Text = "No data";
                _rootPage.NotifyUser("Not able to determine the location.", NotifyType.ErrorMessage);
                break;

            case PositionStatus.Disabled:
                // The permission to access location data is denied by the user or other policies.
                ScenarioOutput_Status.Text = "Disabled";
                _rootPage.NotifyUser("Access to location is denied.", NotifyType.ErrorMessage);

                // Show message to the user to go to location settings.
                LocationDisabledMessage.Visibility = Visibility.Visible;

                // Clear any cached location data.
                UpdateLocationData(null);
                break;

            case PositionStatus.NotInitialized:
                // The location platform is not initialized. This indicates that the application
                // has not made a request for location data.
                ScenarioOutput_Status.Text = "Not initialized";
                _rootPage.NotifyUser("No request for location is made yet.", NotifyType.StatusMessage);
                break;

            case PositionStatus.NotAvailable:
                // The location platform is not available on this version of the OS.
                ScenarioOutput_Status.Text = "Not available";
                _rootPage.NotifyUser("Location is not available on this version of the OS.", NotifyType.ErrorMessage);
                break;

            default:
                ScenarioOutput_Status.Text = "Unknown";
                _rootPage.NotifyUser(string.Empty, NotifyType.StatusMessage);
                break;
        }
    });
}

响应位置更新

本部分介绍如何使用 PositionChanged 事件来接收一段时间内的用户的位置更新。 由于用户随时可能会取消对位置的访问,请务必调用 RequestAccessAsync 和使用 StatusChanged 事件,如上一部分中所示。

本部分假定你已启用位置功能并且已从前台应用的 UI 线程调用 RequestAccessAsync

步骤 1:定义报告间隔和注册位置更新

在此示例中,仅当允许访问用户的位置时,才使用 accessStatus(上一switch个示例中的语句)执行操作。 如果允许访问用户位置,该代码将创建 Geolocator 对象、指定跟踪类型并注册位置更新。

Geolocator 对象可以基于位置更改(基于距离的跟踪)或时间更改(基于定期的跟踪)触发 PositionChanged 事件。

如果两个属性都未设置,则每隔 1 秒(相当于 ReportInterval = 1000)返回一个位置。 此处,使用 2 秒 (ReportInterval = 2000) 报告间隔。

using Windows.Devices.Geolocation;
...
var accessStatus = await Geolocator.RequestAccessAsync();

switch (accessStatus)
{
    case GeolocationAccessStatus.Allowed:
        // Create Geolocator and define periodic-based tracking (2 second interval).
        _geolocator = new Geolocator { ReportInterval = 2000 };

        // Subscribe to the PositionChanged event to get location updates.
        _geolocator.PositionChanged += OnPositionChanged;

        // Subscribe to StatusChanged event to get updates of location status changes.
        _geolocator.StatusChanged += OnStatusChanged;

        _rootPage.NotifyUser("Waiting for update...", NotifyType.StatusMessage);
        LocationDisabledMessage.Visibility = Visibility.Collapsed;
        StartTrackingButton.IsEnabled = false;
        StopTrackingButton.IsEnabled = true;
        break;

    case GeolocationAccessStatus.Denied:
        _rootPage.NotifyUser("Access to location is denied.", NotifyType.ErrorMessage);
        LocationDisabledMessage.Visibility = Visibility.Visible;
        break;

    case GeolocationAccessStatus.Unspecified:
        _rootPage.NotifyUser("Unspecified error!", NotifyType.ErrorMessage);
        LocationDisabledMessage.Visibility = Visibility.Collapsed;
        break;
}

步骤 2:处理位置更新

Geolocator 对象通过触发 PositionChanged 事件以指示用户的位置更改或时间已过,具体取决于配置它的方式。 该事件通过参数的 Position 属性(属于类型 Geoposition)来传递相应的位置信息。 在此示例中,该方法不是从 UI 线程中调用的,并且 Dispatcher 对象调用了 UI 更改。

using Windows.UI.Core;
...
async private void OnPositionChanged(Geolocator sender, PositionChangedEventArgs e)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        _rootPage.NotifyUser("Location updated.", NotifyType.StatusMessage);
        UpdateLocationData(e.Position);
    });
}

更改位置隐私设置

如果位置隐私设置不允许你的应用访问用户位置,我们建议提供一个指向“设置”应用中的“位置隐私设置”的便捷链接。 在此示例中,“超链接”控件用于导航到 ms-settings:privacy-location URI。

<!--Set Visibility to Visible when access to location is denied -->  
<TextBlock x:Name="LocationDisabledMessage" FontStyle="Italic"
           Visibility="Collapsed" Margin="0,15,0,0" TextWrapping="Wrap">
    <Run Text="This app is not able to access Location. Go to "/>
        <Hyperlink NavigateUri="ms-settings:privacy-location">
            <Run Text="Settings"/>
        </Hyperlink>
    <Run Text=" to check the location privacy settings."/>
</TextBlock>

此外,你的应用可以调用 LaunchUriAsync 方法,以从代码启动“设置”应用。 有关详细信息,请参阅启动 Windows 设置应用

using Windows.System;
...
bool result = await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));

对应用进行故障排除

在你的应用可以访问用户位置之前,必须在设备上启用“位置”。 在设置应用中,检查以下位置隐私设置是否已打开:

  • “此设备的位置...”“打开”(在 Windows 10 移动版中不适用)
  • 位置服务设置(位置)已打开
  • “选择可以使用你的位置的应用”下,你的应用已设置为“打开”