取得使用者的位置

注意

MapControl 和地圖服務要求地圖驗證金鑰,稱為 MapServiceToken。 如需取得和設定地圖驗證金鑰的詳細資訊,請參閱要求地圖驗證金鑰

尋找使用者的位置,並回應位置的變更。 存取使用者的位置是由 [設定] 應用程式中的隱私權設定所管理。 本主題也會示範如何檢查您的應用程式是否有權限存取使用者的位置。

提示 若要了解如何在您的應用程式中存取使用者的位置,請從 GitHub 上的 Windows-universal-samples 存放庫下載以下範例。

啟用位置功能

  1. 在 [方案總管] 中,按兩下 [package.appxmanifest],然後選取 [功能] 索引標籤。
  2. 在 [功能] 清單中,選取 [位置] 核取方塊。 這會將 location 裝置功能新增至套件資訊清單檔案。
  <Capabilities>
    <!-- DeviceCapability elements must follow Capability elements (if present) -->
    <DeviceCapability Name="location"/>
  </Capabilities>

取得目前位置

本節說明如何使用 Windows.Devices.Geolocation 命名空間中的 API 來偵測使用者的地理位置。

步驟 1:要求存取使用者的位置

除非您的應用程式具有粗略的定位功能 (請參閱附註),否則您必須使用 RequestAccessAsync 方法來要求存取使用者的位置,才能嘗試存取位置。 必須從 UI 執行緒呼叫 RequestAccessAsync 方法,並且應用必須位於前景。 在使用者授與應用程式權限之前,您的應用程式將無法存取使用者的位置資訊。*

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

RequestAccessAsync 方法提示使用者提供存取其位置的權限。 只會提示使用者一次 (每個應用程式)。 第一次授與或拒絕權限之後,這個方法就不會再提示使用者提供權限。 若要協助使用者在提示之後變更位置權限,建議您提供位置設定的連結,如本主題稍後所示。

附註:粗略定位功能允許您的應用程式在未經使用者明確許可的情況下取得經過刻意模糊化 (不精確) 的位置 (但系統範圍內的位置開關仍然必須處於啟用狀態)。 若要瞭解如何在應用程式中利用粗略的位置,請參閱 Geolocator 類別中的 AllowFallbackToConsentlessPositions 方法。

步驟 2:取得使用者的位置,並註冊位置權限的變更

GetGeopositionAsync 方法會讀取一次目前位置。 switch 陳述式在這裡搭配 accessStatus (來自前一個範例) 一起使用,只有在允許存取使用者位置時才會執行。 如果允許存取使用者的位置,程式碼會建立 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:定義報告間隔並註冊位置更新

在此範例中,switch 陳述式在這裡搭配 accessStatus (來自前一個範例) 一起使用,只有在允許存取使用者位置時才會執行。 如果允許存取使用者的位置,程式碼會建立 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 perodic-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("Unspecificed 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);
    });
}

變更位置隱私權設定

如果位置隱私權設定不允許您的應用程式存取使用者的位置,建議您提供 [設定] 應用程式中 [位置隱私權設定] 的便利連結。 在此範例中,會使用 Hyperlink 控制項瀏覽至 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 行動裝置版)
  • 位置服務設定 [位置] 已開啟
  • 在 [選擇可使用您位置的應用程式] 下,您的應用程式設定為 [開啟]