Xamarin.Formsマップの初期化と構成

Map コントロールは、各プラットフォームでネイティブ マップ コントロールを使用します。 これにより、すばやく使い慣れたマップ エクスペリエンスをユーザーに提供しますが、各プラットフォーム API の要件に準拠するために一部の構成手順が必要になります。

マップの初期化

Map コントロールは、Xamarin.Forms.Maps NuGet パッケージにより提供されます。これは、ソリューション内のすべてのプロジェクトに追加する必要があります。

Xamarin.Forms.Maps NuGet パッケージをインストールしてから、各プラットフォーム プロジェクトで初期化する必要があります。

iOS では、これは Xamarin.Forms.Forms.Init メソッドの "後" に Xamarin.FormsMaps.Init メソッドを呼び出して AppDelegate.cs 内で行う必要があります。

Xamarin.FormsMaps.Init();

Android では、これは Xamarin.Forms.Forms.Init メソッドの "後" に Xamarin.FormsMaps.Init メソッドを呼び出して、MainActivity.cs 内で行う必要があります。

Xamarin.FormsMaps.Init(this, savedInstanceState);

ユニバーサル Windows プラットフォーム (UWP) では、MainPage コンストラクターから Xamarin.FormsMaps.Init メソッドを呼び出すと、MainPage.xaml.cs でこれが発生します。

Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");

UWP に必要な認証トークンの詳細については、「ユニバーサル Windows プラットフォーム」を参照してください。

NuGet パッケージが追加され、各アプリケーション内で初期化メソッドが呼び出されたら、Xamarin.Forms.Maps API を共有コード プロジェクトで使用できます。

プラットフォームの構成

マップが表示される前に、Android とユニバーサル Windows プラットフォーム (UWP) では追加の構成が必要です。 さらに、iOS、Android、UWP ユーザーの場所にアクセスするには、場所のアクセス許可がアプリケーションに付与されている必要があります。

iOS

iOS でのマップの表示と操作には、追加の構成は必要ありません。 ただし、位置情報サービスにアクセスするには、Info.plist で次のキーを設定する必要があります。

iOS 11 以前をサポートするには、NSLocationWhenInUseUsageDescriptionNSLocationAlwaysAndWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription の 3 つのキーをすべて含めます。

Info.plist のこれらのキーの XML 表現を次に示します。 アプリケーションで位置情報がどのように使用されているかを反映するように string 値を更新する必要があります。

<key>NSLocationAlwaysUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your application is being used?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>

Info.plist エントリは、Info.plist ファイルの編集中にソース ビューに追加することもできます。

iOS 8 用 Info.plist

その後、アプリケーションがユーザーの場所へのアクセスを試み、アクセスを要求すると、プロンプトが表示されます。

iOS での位置情報のアクセス許可要求のスクリーンショット

Android

Android でマップを表示および操作するための構成プロセスは次のとおりです。

  1. Google マップ API キーを取得し、マニフェストに追加します。
  2. マニフェストで Google Play サービスのバージョン番号を指定します。
  3. マニフェストで Apache HTTP レガシ ライブラリの要件を指定します。
  4. [オプション] マニフェストで WRITE_EXTERNAL_STORAGE アクセス許可を指定します。
  5. [オプション] マニフェストで場所のアクセス許可を指定します。
  6. [省略可能] MainActivity クラスのランタイムの場所のアクセス許可を要求します。

正しく構成されたマニフェスト ファイルの例については、サンプル アプリケーションの AndroidManifest.xml を参照してください。

Google Maps API キーを取得する

Android で Google マップ API を使用するには、API キーを生成する必要があります。 これを行うには、「Google マップ API キーを取得する」の手順に従います。

API キーを取得したら、Properties/AndroidManifest.xml ファイルの <application> 要素内に追加する必要があります。

<application ...>
    <meta-data android:name="com.google.android.geo.API_KEY" android:value="PASTE-YOUR-API-KEY-HERE" />
</application>

これにより、API キーがマニフェストに埋め込まれます。 有効な API キーがないと、Map コントロールに空白のグリッドが表示されます。

Note

com.google.android.geo.API_KEY は、API キーに推奨されるメタデータ名です。 下位互換性のために、com.google.android.maps.v2.API_KEY メタデータ名を使用できますが、Android マップ API v2 への認証のみが許可されます。

APK が Google マップにアクセスするには、APK の署名に使用するすべてのキーストア (デバッグおよびリリース) の SHA-1 フィンガープリントとパッケージ名を含める必要があります。 たとえば、1 台のコンピューターをデバッグに使用し、別のコンピューターをリリース APK の生成に使用する場合、最初のコンピューターのデバッグ キーストアの SHA-1 証明書フィンガープリントと、2 番目のコンピューターのリリース キーストアの SHA-1 証明書フィンガープリントを含める必要があります。 また、アプリのパッケージ名が変更された場合は、キー資格情報を編集することを忘れないでください。 「Google マップ API キーを取得する」を参照してください。

Google Play サービスのバージョン番号を指定する

AndroidManifest.xml<application> 要素内に次の宣言を追加します。

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

これにより、アプリケーションがコンパイルされた Google Play サービスのバージョンがマニフェストに埋め込まれます。

Apache HTTP レガシ ライブラリの要件を指定する

Xamarin.Forms アプリケーションが API 28 以上を対象とする場合は、AndroidManifest.xml <application> 要素内に次の宣言を追加する必要があります。

<uses-library android:name="org.apache.http.legacy" android:required="false" />    

これにより、Android 9 の bootclasspath から削除された Apache Http クライアント ライブラリを使用するようにアプリケーションに指示されます。

WRITE_EXTERNAL_STORAGE 権限を指定する

アプリケーションが API 22 以下を対象とする場合は、<manifest> 要素の子としてマニフェストに WRITE_EXTERNAL_STORAGE アクセス許可を追加することが必要な場合があります。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

これは、アプリケーションが API 23 以上を対象とする場合は必要ありません。

場所のアクセス許可を指定する

アプリケーションがユーザーの場所にアクセスする必要がある場合は、<manifest> 要素の子として、マニフェストに ACCESS_COARSE_LOCATION または ACCESS_FINE_LOCATION (またはその両方) を追加して、アクセス許可を要求する必要があります。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.myapp">
  ...
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

ACCESS_COARSE_LOCATION アクセス許可により、API は WiFi またはモバイル データまたはその両方を使用して、デバイスの場所を決定できます。 ACCESS_FINE_LOCATION アクセス許可により、API はグローバル位置情報システム (GPS)、WiFi、またはモバイル データを使用して、正確な場所を可能な限り特定できます。

または、マニフェスト エディターを使用して次のアクセス許可を追加すると、これらのアクセス許可を有効にすることができます。

  • AccessCoarseLocation
  • AccessFineLocation

これらは次のスクリーンショットに示されています。

Android に必要なアクセス許可

ランタイムの場所のアクセス許可を要求する

アプリケーションが API 23 以降を対象とし、ユーザーの場所にアクセスする必要がある場合は、実行時に必要なアクセス許可があるかどうかを確認し、それがない場合は要求する必要があります。 これは次のようにして実装します。

  1. MainActivity クラスで、次のフィールドを追加します。

    const int RequestLocationId = 0;
    
    readonly string[] LocationPermissions =
    {
        Manifest.Permission.AccessCoarseLocation,
        Manifest.Permission.AccessFineLocation
    };
    
  2. MainActivity クラスで、次の OnStart オーバーライドを追加します。

    protected override void OnStart()
    {
        base.OnStart();
    
        if ((int)Build.VERSION.SdkInt >= 23)
        {
            if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted)
            {
                RequestPermissions(LocationPermissions, RequestLocationId);
            }
            else
            {
                // Permissions already granted - display a message.
            }
        }
    }
    

    アプリケーションが API 23 以上を対象としている限り、このコードは、AccessFineLocation アクセス許可の実行時アクセス許可チェックを実行します。 アクセス許可が付与されていない場合は、RequestPermissions メソッドを呼び出すとアクセス許可要求が行われます。

  3. MainActivity クラスで、次の OnRequestPermissionsResult オーバーライドを追加します。

    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
    {
        if (requestCode == RequestLocationId)
        {
            if ((grantResults.Length == 1) && (grantResults[0] == (int)Permission.Granted))
                // Permissions granted - display a message.
            else
                // Permissions denied - display a message.
        }
        else
        {
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    

    このオーバーライドは、アクセス許可要求の結果を処理します。

このコードの全体的な効果は、アプリケーションがユーザーの場所を要求するときに、アクセス許可を要求する次のダイアログが表示されることです。

Android での位置情報のアクセス許可要求のスクリーンショット

ユニバーサル Windows プラットフォーム

UWP では、マップを表示してマップ サービスを使用する前に、アプリケーションを認証する必要があります。 アプリケーションを認証するには、マップ認証キーを指定する必要があります。 詳細については、「マップ認証キーの要求」を参照してください。 認証トークンは、Bing マップを使用してアプリケーションを認証するために、FormsMaps.Init("AUTHORIZATION_TOKEN") メソッド呼び出しで指定する必要があります。

Note

UWP では、ジオコーディングなどのマップ サービスを使用するには、MapService.ServiceToken プロパティを認証キーの値に設定する必要もあります。 これを行うには、次のコード行を使用します: Windows.Services.Maps.MapService.ServiceToken = "INSERT_AUTH_TOKEN_HERE";

さらに、アプリケーションがユーザーの場所にアクセスする必要がある場合は、パッケージ マニフェストで場所機能を有効にする必要があります。 これは次のようにして実装します。

  1. ソリューション エクスプローラーで、package.appxmanifest をダブルクリックし、[機能] タブを選びます。

  2. [機能] ボックスの一覧で、[位置情報] チェックボックスをオンにします。 これにより、location デバイス機能がパッケージ マニフェスト ファイルに追加されます。

    <Capabilities>
      <!-- DeviceCapability elements must follow Capability elements (if present) -->
      <DeviceCapability Name="location"/>
    </Capabilities>
    

リリース ビルド

UWP リリース ビルドでは、.NET ネイティブ コンパイルを使用して、アプリケーションをネイティブ コードに直接コンパイルします。 ただし、その結果、UWP 上の Map コントロールのレンダラーが実行可能ファイルからリンクされる可能性があります。 これは、App.xaml.csForms.Init メソッドの UWP 固有のオーバーロードを使用して修正できます。

var assembliesToInclude = new [] { typeof(Xamarin.Forms.Maps.UWP.MapRenderer).GetTypeInfo().Assembly };
Xamarin.Forms.Forms.Init(e, assembliesToInclude);

このコードは、Xamarin.Forms.Maps.UWP.MapRenderer クラスが存在するアセンブリを Forms.Init メソッドに渡します。 これにより、.NET ネイティブ コンパイル プロセスで、アセンブリが実行可能ファイルからリンクされないようにします。

重要

これを行わないと、リリース ビルドの実行時に Map コントロールが表示されなくなります。