Xamarin.Essentials:位置情報

Geolocation クラスには、デバイスの現在の位置座標を取得する API が用意されています。

作業開始

この API の使用を始めるには、Xamarin.Essentials の概要ガイドを読み、ライブラリが正しくインストールされてプロジェクトに設定されていることを確認してください。

Geolocation の機能にアクセスするには、次のプラットフォーム固有の設定が必要です。

Coarse および Fine Location アクセス許可が必要であり、Android プロジェクトで構成する必要があります。 さらに、アプリの対象が Android 5.0 (API レベル 21) 以降である場合は、アプリがマニフェスト ファイルのハードウェア機能を使用することを宣言する必要があります。 これは次の方法で追加できます。

[プロパティ] フォルダーにある 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 マニフェストを更新します。

[プロパティ] フォルダーにある 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 では、OnCreate メソッド内で Xamarin.Essentials を初期化する必要があります。

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 上で実行時のアクセス許可を処理するには、OnRequestPermissionsResult で、すべての Xamarin.Essentials を受け取る必要があります。 すべての 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);
}

Geolocation の使用

クラスの Xamarin.Essentials への参照を追加します。

using Xamarin.Essentials;

Geolocation 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 を使用できます。 デバイスの場所を取得するには時間がかかる場合があるので、完全な GeolocationRequestCancellationToken を渡すのが最善です。

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 があります。

Geolocation の精度

次の表では、プラットフォームごとの精度を示します。

最低

プラットフォーム 距離 (メートル単位)
Android 500
iOS 3000
UWP 1000 ~ 5000

Low

プラットフォーム 距離 (メートル単位)
Android 500
iOS 1000
UWP 300 ~ 3000

中 (既定値)

プラットフォーム 距離 (メートル単位)
Android 100 ~ 500
iOS 100
UWP 30 ~ 500

High

プラットフォーム 距離 (メートル単位)
Android 0 ~ 100
iOS 10
UWP <= 10

最高

プラットフォーム 距離 (メートル単位)
Android 0 ~ 100
iOS ~0
UWP <= 10

擬似ロケーションの検出

一部のデバイスは、プロバイダーからの擬似ロケーションを返します。擬似ロケーションを提供するアプリケーションによって擬似ロケーションを返すこともあります。 LocationIsFromMockProvider を使用することでこれを検出できます。

var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);

if (location != null)
{
    if(location.IsFromMockProvider)
    {
        // location is from a mock provider
    }
}

2 つの場所の間の距離

Location クラスおよび LocationExtensions クラスでは、2 つの地理的な場所の間の距離を計算できる CalculateDistance メソッドが定義されています。 この計算では道路またはその他の経路は考慮されず、あくまでも地球の表面に沿った 2 点間の最短距離なので、"大圏距離" または "直線距離" とも呼ばれます。

次に例を示します。

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 クラスでは、2 つの単位の間で変換を行う KilometersToMiles および MilesToKilometers メソッドも定義されています。

プラットフォームによる違い

高度は、プラットフォームごとに異なる方法で計算されます。

Android で、高度が表示されている場合は、WGS 84 準拠楕円体のメートル単位で返されます。 この位置に高度がない場合は、0.0 が返されます。

API

他の Xamarin ビデオは、Channel 9 および YouTube でご覧いただけます。