本文說明如何使用 .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 Manifest:
開啟 Platform/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 Manifest 檔案,在清單編輯器中:
在 Visual Studio 中,按兩下 Platform/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 就沒有作用。
檢查位置服務是否已啟用
類別 Geolocation 具有唯讀 IsEnabled
屬性,可用來判斷裝置上是否已啟用位置服務。
準確性
下列各節概述每個平臺的位置精確度距離:
這很重要
iOS 對於精確度有一些限制。 如需詳細資訊,請參閱 平台差異 一節。
最低
平台 | 距離(公尺) |
---|---|
安卓 | 500 |
iOS | 3000 |
窗戶 | 1000 - 5000 |
低
平台 | 距離(公尺) |
---|---|
安卓 | 500 |
iOS | 1000 |
窗戶 | 300 - 3000 |
中 (預設值)
平台 | 距離(公尺) |
---|---|
安卓 | 100 - 500 |
iOS | 100 |
窗戶 | 30-500 |
高
平台 | 距離(公尺) |
---|---|
安卓 | 0 - 100 |
iOS | 10 |
窗戶 | <= 10 |
最佳
平台 | 距離(公尺) |
---|---|
安卓 | 0 - 100 |
iOS | ~0 |
窗戶 | <= 10 |
偵測模擬位置
某些裝置可能會從提供者或提供模擬位置的應用程式傳回模擬位置。 您可以使用IsFromMockProvider在任何Location上偵測此狀況。
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) 構函式分別接受緯度和經度自變數。 正緯度值位於赤道以北,正經度值位於 Prime Meridian 以東。 使用最終參數來指定 CalculateDistance
的英里或公里。 類別 UnitConverters 也會定義 KilometersToMiles 和 MilesToKilometers 方法,以在兩個單位之間轉換。
平台差異
本節說明與地理位置 API 的平臺特定差異。
高度在每個平臺上會以不同的方式計算。
在 Android 裝置上,如果可用,則會以米為單位,傳回的高度是相對於 WGS 84 參考橢圓體的海拔高度。 如果這個位置沒有高度, 0.0
則會傳回 。
Location.ReducedAccuracy 屬性僅供 iOS 使用,在所有其他平台上返回 false
。