Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用)

2015年3月11日

Android/iOSアプリで各プラットフォーム標準の地図を表示するには、Xamarin.Forms.Mapsコントロールを使う。その基本的な使い方を説明する。

古谷 誠進(@furuya02
  • このエントリーをはてなブックマークに追加

 スマートフォンの各プラットフォームでは、標準の地図機能が提供されており、Androidでは「Google Maps Android API v2」、iOSでは「MapKit」がそれである。Xamarin.Formsでは、この各プラットフォームの標準マップAPIを共通的に扱えるようにXamarin.Forms.Mapsコントロールが提供されている。

 今回は、このXamarin.Forms.Mapsコントロールの利用方法について解説する*1

  • *1 なお本Tipsは、Windows上でVisual Studio 2013を使用してXamarin.Forms開発をすることを前提としている(編集部注: Mac上のXamarin Studioでも同様の手順で、本稿の内容が実現できることは確認している)。使用しているXamarin.Formsのバージョンは、プロジェクト作成時に利用されている「1.3.1.6296」である。

1. シナリオ

 Xamarin.Forms.Mapsコントロールを使用して地図を表示するためには、最初に、プラットフォーム側での初期化処理が必要である。そして、プラットフォームごとにパーミッションなどのいくつかの設定も必要になる。

 今回は、これらの作業について、順を追って解説する。

2. Xamarin.Formsプロジェクトを作成する

 メニューバーの[ファイル]-[新規作成]-[プロジェクト]から表示したダイアログで、[テンプレート]-[Visual C#]-[Mobile Apps]-[Blank App (Xamarin.Forms Portable)]を選択し、名前を「MapsSample」として[OK]ボタンを押す。

図1 「Blank App (Xamarin.Forms Portable)」の新規作成

3. Xamarin.Forms.Mapsパッケージの追加

 Xamarin.Forms.Mapsを使用するためには、NuGetパッケージのインストールが必要だ。

 Visual StudioでのNuGetパッケージのインストールは、メニューバーの[ツール]-[NuGet パッケージマネージャー]-[ソリューションの NuGet パッケージの管理]を選択して表示された[NuGet パッケージの管理]ダイアログから行う。検索欄にXamarin.Forms.Mapsと入力すると、目的のパッケージを簡単に見つけることができる。また、依存関係を見ると分かるように、Xamarin.Formsの最新stableである1.3.5.6337や、Xamarin.GooglePlayServicesも同時にインストールされることになる。

図2 パッケージマネージャー

 図2の[インストール]ボタンを押した後、続いて表示される[プロジェクトの選択]ダイアログでは、全てのプロジェクトにチェックを入れて[OK]ボタンを押す(図3)。

図3 全てのプロジェクトを選択する
図3 全てのプロジェクトを選択する

 実は、ここまでの要領でXamarin.Forms.Mapsパッケージのインストールは完了するはずなのだが、2015年3月9日現在、一部のプロジェクトでエラーが発生してインストールが失敗する(次の画面はその例)。

図4 共通プロジェクトおよびAndroidプロジェクトで、パッケージのインストールが失敗している
図4 共通プロジェクトおよびAndroidプロジェクトで、パッケージのインストールが失敗している

 この問題を回避するためには、先のインストールを行う前に、以下の作業を順に行う必要がある。

  • ソリューションエクスプローラーでAndroidプロジェクトを右クリックして表示されるメニューから[プロパティ](=プロジェクトのプロパティ)を選択し、図5のように[Application]の[Compile using Android version]をUse Latest Platform (API Level 21 (Xamarin.Android v5.0 Support))からAPI Level 21 (Xamarin.Android v5.0 Support)に変更する(この変更の意味は、後述のコラムを参照)
  • Visual Studioを再起動する
  • もう一度、図2の[NuGet パッケージの管理]ダイアログを表示し、左側のツリーから[インストール済みのパッケージ]-[すべて]を選択し、中央に表示される「Xamarin.Forms.Maps」の[管理]ボタンを押す。これにより図3のダイロアログが表示されるので、チェックボックスが外れている項目をチェックし直して[OK]ボタンを押すと、先ほどエラーが発生したNuGetパッケージがインストールされる(これでうまくインストールされない場合は、全てのチェックを外してXamarin.Forms.Mapsをアンインストールして、もう一度インストールし直すとよい)
図5 Androidプロジェクトのプロパティ設定

 パッケージのインストールが完了すると、各プロジェクトの参照設定に、次のようなライブラリが追加されているのを確認できる。

図6 各プロジェクトに追加された参照(共通プロジェクト)
図6 各プロジェクトに追加された参照(Android) 図6 各プロジェクトに追加された参照(iOS)
図6 各プロジェクトに追加された参照(共通プロジェクト/Android/iOS)

【コラム】Xamarin.Forms.Mapsのインストールが失敗する

 2015年3月9日現在、エラーが発生する原因は、依存関係から、Androidプロジェクトで必要となるXamarin.Android.Support.v7.AppCompatアセンブリのVersion 21以降が、MonoAndroid,Version=v2.2の条件下でインストールできないためである。Visual Studioでは、[Compile using Android version]がUse Latest Platform (API Level 21 (Xamarin.Android v5.0 Support))になっていると、MonoAndroid,Version=v2.2となってしまうのである。

 そして、これを回避する方法が、先に紹介したAPI Level 21(Xamarin.Android v5.0 Support)への変更である。

 なお、UI上でこの変更を実施すると、プロジェクトを再度読み直すまで、TargetFrameworkVersion(=.csprojファイルで指定されている.NETのターゲットバージョン)の値が正常に処理されない場合がある。手順の中でVisual Studioを再起動したのは、このためである。

4. Xamarin.Forms.Mapsの初期化

 Xamarin.Forms.Mapsを使用するためには、プラットフォームごとに、初期化コードを記述する必要がある。

 初期化コードは、iOSプロジェクトでは、AppDelegate.csファイルに追加する。

C#
……省略……
namespace MapsSample.iOS {
  [Register("AppDelegate")]
  public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate {
    public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
      global::Xamarin.Forms.Forms.Init();
      Xamarin.FormsMaps.Init(); // Xamarin.Forms.Mapsの初期化コード
      LoadApplication(new App());
      return base.FinishedLaunching(app, options);
    }
  }
}
Xamarin.Forms.Mapsの初期化コード(AppDelegate.cs)

 また、Androidプロジェクトでは、MainActivity.csファイルに追加する。

C#
……省略……
namespace MapsSample.Droid {
  [Activity(Label = "MapsSample", Icon = "@drawable/icon", MainLauncher = true,
    ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
  public class MainActivity : FormsApplicationActivity {
    protected override void OnCreate(Bundle bundle) {
      base.OnCreate(bundle);

      Forms.Init(this, bundle);
      Xamarin.FormsMaps.Init(this, bundle); // Xamarin.Forms.Mapsの初期化コード
      LoadApplication(new App());
    }
  }
}
Xamarin.Forms.Mapsの初期化コード(MainActivity.cs)

5. プラットフォームごとの設定(Android)

 Xamarin.Forms.Mapsを使用するためには、プラットフォームごとに、もう少し作業が必要である。

 Androidでは、次の3つがそれである。

(1)パーミッションの追加

 インターネットに接続して地図データをダウンロードするため、INTERNETACCESS_FINE_LOCATIONおよびACCESS_NETWORK_STATEのパーミッションが必要だ。

 これらを設定するには、プロジェクトのプロパティで[Android Manifest]を開いて、上記の3つのパーミッションをチェックする。

Android Manifestで必要なパーミッションにチェックを入れる

(2)ヒープの最大サイズの設定

 ヒープの最大サイズの指定が無い場合、下記のようにエラーとなりコンパイルが失敗する。

コンソール
……省略……
1>C:\Users\Seishin\AppData\Local\Xamarin\Android.Support.v7.AppCompat\21.0.3\emb……省略……
1>COMPILETODALVIK : UNEXPECTED TOP-LEVEL error :
========== ビルド: 0 正常終了、1 失敗、1 更新不要、0 スキップ ==========
========== 配置: 0 正常終了、0 失敗、0 スキップ ==========
コンパイルが失敗している様子

 プロジェクトのプロパティで[Android Options]を選択し、[Advanced]タブで[Java Max Heap Size]欄に1Gと設定することで(図7)、この問題を回避できる。

図7 Java Heap Sizeの設定

「1G」=「1Gbytes」、「100m」=「100Mbytes」を意味する。

(3)アプリケーションキーの設定

 Androidでは、「Google Maps API v2」を使用するため、同サービスのAPIキーが必要になる。APIキーの取得方法については、「Tips:Xamarin.Androidで地図を表示するには?(Google Maps使用)」に解説されているので、そちらを参照していただきたい。

 取得したAPIキーを追加するためには、([Properties]の中にある)AndroidManifest.xmlファイルは以下のように修正する。

XML
 1
 2
 3
 4
 5
 6
 7
1
 9
10
11
<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example" android:installLocation="auto">
  <uses-sdk android:minSdkVersion="15" />

  <application>
    <meta-data android:name="com.google.android.maps.v2.API_KEY"
       android:value="<取得したAPI Keyをここに書く>" />
   </application>

</manifest>
APIキーを追加した

 <manifest>タグの中の<application>タグに<meta-data>タグを追加し、そのandroid:name属性にはcom.google.android.maps.v2.API_KEYを、android:value属性には取得したAPIキーを設定する(1)。

6. プラットフォームごとの設定(iOS)

 iOS 7では、現在位置を取得するアプリの場合、起動時に許可を求めるためのメッセージが自動的に表示された。しかしiOS 8では、このような許可を求めるためには、明示的に設定が必要である。

 iOSで「位置情報測位の許可」のメッセージを表示するには、Info.plistファイルを(GUIのPListエディターでは設定できないのでテキストエディターで開いて)以下のように修正する。

XML
 1
 2
 3
 4
 5
1
 7
2
 9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ……省略……
  <key>NSLocationAlwaysUsageDescription</key>
  <string>Can we use your location</string>
  <key>NSLocationWhenInUseUsageDescription</key>
  <string>We are using your location</string>
</dict>
</plist>
NSLocationAlwaysUsageDescriptionキーおよびNSLocationWhenInUseUsageDescriptionキーを追加した(Info.plist)

 NSLocationAlwaysUsageDescriptionキーは「常に許可」時のメッセージであり(1)、NSLocationWhenInUseUsageDescriptionキーは「このAppの使用中のみ許可」時のメッセージである(2)。これらのキーを追加すると、アプリ起動時に次のような確認ダイアログが表示される。

図8 現在位置の取得許可を求めるメッセージ(iOS 8)
図8 現在位置の取得許可を求めるメッセージ(iOS 8)

7. 地図を表示する(Android/iOS共通のコード)

 初期化コードの追加と、プラットフォームごとの設定が完了すると、いよいよ地図の表示が可能である。

 地図を表示するためには、App.csファイルを以下のように修正する。

C#
……省略……
using Xamarin.Forms.Maps;

namespace MapsSample {
  public class App : Application {
    public App() {
      MainPage = new MyPage();
    }
  ……省略……
  }

  public class MyPage : ContentPage {
    public MyPage() {
      var map = new Map(               // <-1
        MapSpan.FromCenterAndRadius(   // <-2
          new Position(35.71, 139.81), // <-3
          Distance.FromMiles(0.2))) {  // <-4
            IsShowingUser = true,
            VerticalOptions = LayoutOptions.FillAndExpand
          };
      Content = new StackLayout {
        Children = { map }
      };
    }
  }
}
Xamarin.Forms.Mapsを使用した地図を表示するコード(App.cs)

 1では、Mapクラスのインスタンスを生成しているが、パラメーターに指定されているのは、MapSpanクラスのインスタンスである(2)。

 MapSpanオブジェクトは、FromCenterAndRadiusメソッドを使用して生成されており、パラメーターに中心位置の座標(3*2と縮尺(4)が指定されている。

 その他、MapオブジェクトのIsShowingUserプロパティ(=現在位置を表示するかどうか)などの設定も行っている。

  • *2 設定されている数値は、東京スカイツリーの座標である。

 このコードを実行すると、次のような画面になる。

図9 AndroidおよびiOS実機による表示(HTC J) 図9 AndroidおよびiOS実機による表示(iPhone 6)
図9 AndroidおよびiOS実機による表示(HTC J/iPhone 6)

【コラム】Androidのエミュレーターでは実行できない

 通常使用しているAndroidエミュレーターでは、Google Play Servicesが含まれていないため、地図を表示することはできない。

 Xamarinから提供されているXamarin Android Playerで、同サービスをインストールする手順が、下記のページで紹介されている。

8. まとめ

 今回は、Xamarin.Forms.Mapsで地図を表示するまでの一連の作業を解説した。

 Xamarin.Forms.Mapsでは、この他にも、マーカーを表示したり、縮尺を操作したりするなどの機能が提供されているが、それらについては次回解説する。

※以下では、本稿の前後を合わせて5回分(第37回~第41回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

37. MvvmCrossのプロジェクトをセットアップするには?

クロスプラットフォーム開発を支援するXamarin用ライブラリの「MvvmCross」を使ってiOS/Androidアプリ開発を行うためのプロジェクトの作成方法を説明する。

38. Xamarin.FormsでListViewコントロールを使用するには?

データの一覧を表示できる「リストビュー」はXamarin.Formsでも提供されている。その基本的な使用方法を解説。また、セルの高さ指定/プログラムによるスクロール/画像表示などの方法も説明する。

39. 【現在、表示中】≫ Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用)

Android/iOSアプリで各プラットフォーム標準の地図を表示するには、Xamarin.Forms.Mapsコントロールを使う。その基本的な使い方を説明する。

40. Xamarin.Formsで地図の現在位置やピンの表示、縮尺や地図タイプの変更を行うには?(Xamarin.Forms.Maps使用)

Xamarin.Forms.Mapsコントロールで利用可能な機能として、「現在位置」や「衛星写真」「ピン立て」「スライダーコントロールによる地図の拡大・縮小」などを解説する。

41. MvvmCrossでプロパティバインディングをするには?

MvvmCrossでの画面表示に必要なプロパティバインディングについて、iOS/Androidの基本的な実装を説明する。

サイトからのお知らせ

Twitterでつぶやこう!


Build Insider賛同企業・団体

Build Insiderは、以下の企業・団体の支援を受けて活動しています(募集概要)。

ゴールドレベル

  • グレープシティ株式会社
  • 日本マイクロソフト株式会社