Xamarin.Essentials:地理位置
地理位置類別會提供 API 來擷取裝置的目前地理位置座標。
開始使用
若要開始使用此 API,請閱讀 入門指南Xamarin.Essentials,以確保連結庫已正確安裝並設定在您的專案中。
若要存取地理位置功能,需要下列平台特定設定:
需要粗略和精確位置的權限,並且必須在 Android 專案中設定。 此外,如果您的應用程式針對 Android 5.0 (API 層級 21) 或更新版,則必須宣告您應用程式使用資訊清單 檔案中的硬體功能。 能以下列方式新增:
開啟 [Properties] 資料夾下的 AssemblyInfo.cs 檔案並新增:
[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 資訊清單:
開啟 [Properties] 資料夾下的 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 專案並開啟專案的屬性。 在 [Android 資訊清單] 下,尋找 [必要權限] 區域並選取 ACCESS_COARSE_LOCATION 和 ACCESS_FINE_LOCATION 權限。 這將會自動更新 AndroidManifest.xml 檔案。
如果您的應用程式是以 Android 10 - Q (API 層級 29 或更高版本)為目標,而且要求 LocationAlways,您也必須將下列許可權新增至 AssemblyInfo.cs:
[assembly: UsesPermission(Manifest.Permission.AccessBackgroundLocation)]
或直接進入您的 AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
建議您閱讀 有關背景位置更新 的 Android 檔,因為需要考慮許多限制。
此 API 會在 Android 上使用執行時間許可權。 請確定 Xamarin.Essentials 已完全初始化,且已在您的應用程式中設定許可權處理。
在 Android 專案的 MainLauncher
或任何 Activity
啟動時 Xamarin.Essentials ,必須在 方法中 OnCreate
初始化:
protected override void OnCreate(Bundle savedInstanceState)
{
//...
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
//...
}
若要處理 Android 上的執行時間權限, Xamarin.Essentials 必須接收任何 OnRequestPermissionsResult
。 將下列程式碼新增到所 Activity
類別:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
使用地理位置
在類別中新增 的 Xamarin.Essentials 參考:
using Xamarin.Essentials;
地理位置 API 也會在必要時,提示使用者提供權限。
您可以透過呼叫 GetLastKnownLocationAsync
方法取得裝置的最後一個已知位置。 這通常比執行完整查詢更快,但較不精確,而且可能會在沒有快取位置存在時傳回 null
。
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"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
}
若要查詢目前裝置的位置座標,可以使用 GetLocationAsync
。 建議您傳入完整的 GeolocationRequest
和 CancellationToken
,因為可能需要一些時間才能取得裝置的位置。
CancellationTokenSource cts;
async Task GetCurrentLocation()
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
if (location != null)
{
Console.WriteLine($"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
}
}
protected override void OnDisappearing()
{
if (cts != null && !cts.IsCancellationRequested)
cts.Cancel();
base.OnDisappearing();
}
請注意,由於每個裝置如何透過不同的提供者查詢地理位置,因此可能會提供所有值。 例如, Altitude
屬性可能是 null
、值為0,或具有正值,其位於海平面上方的公尺。 可能不存在的其他值包括 Speed
和 Course
。
地理位置精確度
下表概述每個平台的精確度:
最低
平台 | 距離 (以公尺為單位) |
---|---|
Android | 500 |
iOS | 3000 |
UWP | 1000 - 5000 |
低
平台 | 距離 (以公尺為單位) |
---|---|
Android | 500 |
iOS | 1000 |
UWP | 300 - 3000 |
中 (預設)
平台 | 距離 (以公尺為單位) |
---|---|
Android | 100 - 500 |
iOS | 100 |
UWP | 30-500 |
高
平台 | 距離 (以公尺為單位) |
---|---|
Android | 0 - 100 |
iOS | 10 |
UWP | <= 10 |
最佳
平台 | 距離 (以公尺為單位) |
---|---|
Android | 0 - 100 |
iOS | ~0 |
UWP | <= 10 |
偵測模擬位置
某些裝置可能會從提供者,或透過可提供模擬位置的應用程式傳回模擬位置。 您可使用在任何 Location
上的 IsFromMockProvider
來偵測此項。
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
if(location.IsFromMockProvider)
{
// location is from a mock provider
}
}
兩個位置之間的距離
Location
和 LocationExtensions
類別會定義 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
建構函式在該順序中具有緯度與經度的引數。 正緯度值位於赤道以北,正經度值位於本初子午線以東。 使用 CalculateDistance
的最後引數來指定英里或公里。 UnitConverters
類別也會定義在兩個單位之間進行轉換的 KilometersToMiles
和 MilesToKilometers
方法。
平台差異
高度在每個平臺上會以不同的方式計算。