地理位置
本文說明如何使用 .NET 多平臺應用程式 UI (.NET MAUI) IGeolocation 介面。 此介面提供 API 來擷取裝置目前的地理位置座標。
介面的預設實作 IGeolocation
可透過 Geolocation.Default 屬性取得。 IGeolocation
介面和Geolocation
類別都包含在 命名空間中Microsoft.Maui.Devices.Sensors
。
開始使用
若要存取地理位置功能,需要下列平台特定設定:
必須指定粗略 或 精細的位置許可權,或兩者,而且應該在Android項目中設定。
此外,如果您的應用程式針對 Android 5.0 (API 層級 21) 或更新版,則必須宣告您應用程式使用資訊清單 檔案中的硬體功能。 能以下列方式新增:
新增元件型權限:
開啟 Platform/Android/MainApplication.cs 檔案,並在 指示詞之後
using
新增下列元件屬性:[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)] [assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)] [assembly: UsesFeature("android.hardware.location", Required = false)] [assembly: UsesFeature("android.hardware.location.gps", Required = false)] [assembly: UsesFeature("android.hardware.location.network", Required = false)]
如果您的應用程式是以 Android 10 - Q (API 層級 29 或更高版本)為目標,而且要求
LocationAlways
,您也必須新增此許可權要求:[assembly: UsesPermission(Android.Manifest.Permission.AccessBackgroundLocation)]
- 或 -
更新 Android 指令清單:
開啟 [平臺/Android/AndroidManifest.xml] 檔案,並在
manifest
節點中新增下列內容:<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-feature android:name="android.hardware.location" android:required="false" /> <uses-feature android:name="android.hardware.location.gps" android:required="false" /> <uses-feature android:name="android.hardware.location.network" android:required="false" />
如果您的應用程式是以 Android 10 - Q (API 層級 29 或更高版本)為目標,而且要求
LocationAlways
,您也必須新增此許可權要求:<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
- 或 -
更新指令清單編輯器中的 Android 指令清單:
在 Visual Studio 中,按兩下 [平臺/Android/AndroidManifest.xml ] 檔案,以開啟 Android 指令清單編輯器。 然後,在 [必要許可權] 底下,檢查上面所列的許可權。 這將會自動更新 AndroidManifest.xml 檔案。
提示
請務必閱讀有關背景位置更新的 Android 檔,因為需要考慮許多限制。
取得最後一個已知位置
裝置可能已快取裝置的最新位置。 GetLastKnownLocationAsync()如果有的話,請使用 方法來存取快取的位置。 這通常比執行完整位置查詢更快,但可能不太精確。 如果沒有任何快取位置存在,這個方法會傳 null
回 。
注意
必要時,地理位置 API 會提示使用者提供許可權。
下列程式代碼範例示範檢查快取的位置:
public async Task<string> GetCachedLocation()
{
try
{
Location location = await Geolocation.Default.GetLastKnownLocationAsync();
if (location != null)
return $"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}";
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
catch (FeatureNotEnabledException fneEx)
{
// Handle not enabled on device exception
}
catch (PermissionException pEx)
{
// Handle permission exception
}
catch (Exception ex)
{
// Unable to get location
}
return "None";
}
視裝置而定,並非所有位置值都可以使用。 例如, Altitude 屬性可能是 null
、值為0,或具有正值,表示海平面上方的公尺。 可能不存在的其他值包括 Speed 和 Course 屬性。
取得目前的位置
雖然檢查 裝置的最後一個已知位置 可能會更快,但可能不正確。 GetLocationAsync使用方法來查詢裝置的目前位置。 您可以設定查詢的精確度和逾時。 最好是使用 GeolocationRequest 和 CancellationToken 參數的方法多載,因為可能需要一些時間才能取得裝置的位置。
注意
必要時,地理位置 API 會提示使用者提供許可權。
下列程式代碼範例示範如何在支援取消時要求裝置的位置:
private CancellationTokenSource _cancelTokenSource;
private bool _isCheckingLocation;
public async Task GetCurrentLocation()
{
try
{
_isCheckingLocation = true;
GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
_cancelTokenSource = new CancellationTokenSource();
Location location = await Geolocation.Default.GetLocationAsync(request, _cancelTokenSource.Token);
if (location != null)
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
// Catch one of the following exceptions:
// FeatureNotSupportedException
// FeatureNotEnabledException
// PermissionException
catch (Exception ex)
{
// Unable to get location
}
finally
{
_isCheckingLocation = false;
}
}
public void CancelRequest()
{
if (_isCheckingLocation && _cancelTokenSource != null && _cancelTokenSource.IsCancellationRequested == false)
_cancelTokenSource.Cancel();
}
並非所有位置值都可以使用,視裝置而定。 例如, Altitude 屬性可能是 null
、值為0,或具有正值,表示海平面上方的公尺。 可能不存在的其他值包括 Speed 和 Course。
警告
GetLocationAsync 在某些情況下可以傳回 null
。 這表示基礎平台無法取得目前的位置。
接聽位置變更
除了查詢裝置的目前位置之外,您還可以在應用程式處於前景時接聽位置變更。
若要檢查應用程式目前是否正在接聽位置變更, IsListeningForeground 您可以查詢的屬性。 準備好開始接聽位置變更之後,您應該呼叫 StartListeningForegroundAsync 方法。 這個方法會開始接聽位置更新,並在位置變更時引發 LocationChanged 事件,前提是應用程式位於前景。 伴隨 GeolocationLocationChangedEventArgs 此事件的物件具有 Location 類型 Location為 的屬性,表示偵測到的新位置。
注意
必要時,地理位置 API 會提示使用者提供許可權。
下列程式代碼範例示範如何接聽位置變更,以及如何處理變更的位置:
async void OnStartListening()
{
try
{
Geolocation.LocationChanged += Geolocation_LocationChanged;
var request = new GeolocationListeningRequest((GeolocationAccuracy)Accuracy);
var success = await Geolocation.StartListeningForegroundAsync(request);
string status = success
? "Started listening for foreground location updates"
: "Couldn't start listening";
}
catch (Exception ex)
{
// Unable to start listening for location changes
}
}
void Geolocation_LocationChanged(object sender, GeolocationLocationChangedEventArgs e)
{
// Process e.Location to get the new location
}
您可以註冊事件的事件處理程式來 ListeningFailed 實作錯誤處理。 此 GeolocationListeningFailedEventArgs 事件隨附的物件具有 Error 類型 GeolocationError為 的屬性,表示接聽失敗的原因。 ListeningFailed引發事件時,接聽進一步的位置變更會停止,而且不會引發任何進一步LocationChanged的事件。
若要停止接聽位置變更,請呼叫 StopListeningForeground 方法:
void OnStopListening()
{
try
{
Geolocation.LocationChanged -= Geolocation_LocationChanged;
Geolocation.StopListeningForeground();
string status = "Stopped listening for foreground location updates";
}
catch (Exception ex)
{
// Unable to stop listening for location changes
}
}
注意
當應用程式未接聽位置變更時,此方法 StopListeningForeground 就沒有作用。
準確率
下列各節概述每個平臺的位置精確度距離:
重要
iOS 對於精確度有一些限制。 如需詳細資訊,請參閱 平台差異 一節。
最低
平台 | 距離 (以公尺為單位) |
---|---|
Android | 500 |
iOS | 3000 |
Windows | 1000 - 5000 |
低
平台 | 距離 (以公尺為單位) |
---|---|
Android | 500 |
iOS | 1000 |
Windows | 300 - 3000 |
中 (預設)
平台 | 距離 (以公尺為單位) |
---|---|
Android | 100 - 500 |
iOS | 100 |
Windows | 30-500 |
高
平台 | 距離 (以公尺為單位) |
---|---|
Android | 0 - 100 |
iOS | 10 |
Windows | <= 10 |
最佳
平台 | 距離 (以公尺為單位) |
---|---|
Android | 0 - 100 |
iOS | ~0 |
Windows | <= 10 |
偵測模擬位置
某些裝置可能會從提供者,或透過可提供模擬位置的應用程式傳回模擬位置。 您可以在任何 Location上使用 來偵測此狀況IsFromMockProvider:
public async Task CheckMock()
{
GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium);
Location location = await Geolocation.Default.GetLocationAsync(request);
if (location != null && location.IsFromMockProvider)
{
// location is from a mock provider
}
}
兩個位置之間的距離
方法 CalculateDistance 會計算兩個地理位置之間的距離。 這個計算的距離不會考慮道路或其他路徑,只是地球表面兩點之間的最短距離。 此計算稱為 大圓距離 計算。
下列程式代碼會計算美國波士頓和三藩市城市 美國 之間的距離:
Location boston = new Location(42.358056, -71.063611);
Location sanFrancisco = new Location(37.783333, -122.416667);
double miles = Location.CalculateDistance(boston, sanFrancisco, DistanceUnits.Miles);
建 Location(Double, Double, Double) 構函式分別接受緯度和經度自變數。 正緯度值位於赤道以北,正經度值位於本初子午線以東。 使用 CalculateDistance
的最後引數來指定英里或公里。 UnitConverters 類別也會定義在兩個單位之間進行轉換的 KilometersToMiles 和 MilesToKilometers 方法。
平台差異
本節說明與地理位置 API 的平臺特定差異。
高度在每個平臺上會以不同的方式計算。
在 Android 上,如果可用,則會以高於 WGS 84 參考橢圓體公尺的公尺傳回高度。 如果這個位置沒有高度, 0.0
則會傳回 。
屬性 Location.ReducedAccuracy 只供 iOS 使用,而且會在所有其他平台上傳 false
回。