読者です 読者をやめる 読者になる 読者になる

SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Forms Maps(地図表示)

【 Xamarin 記事一覧 】

2015/01/19 Maps Ver1.3.x で変化した事項を一部追記しました。

Android iOS WindowsPhone
f:id:furuya02:20141214095801p:plain:w150 f:id:furuya02:20141214095758p:plain:w150 f:id:furuya02:20141214095759p:plain:w150

Xamarin.Forms.Mapsを使用すると、各プラットフォームで簡単に地図を扱うことができます。本記事では、Mapsの使用方法をまとめてみました。
と、偉そうに書いてますが・・・すいません、内容は概ね下記を日本語にしただけです。
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/maps/

1 インストール

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

PM>Install-Package Xamarin.Forms.Maps [全プラットフォーム]

f:id:furuya02:20141214100226p:plain:w150 f:id:furuya02:20141214100222p:plain:w150 f:id:furuya02:20141214100223p:plain:w150 f:id:furuya02:20141214100225p:plain:w150

Mapsのstableバージョンは、2014/12/13現在、1.2.3.6257です。
Mapsをインストールすると、依存関係から、いくつかのDLLが追加されるますが、Xamarin.Formsも最新である1.2.3.6257にバージョンアップされます。

Mapsのstableバージョンは、2015/01/19現在、1.3.1.6296です。
Mapsをインストールすると、依存関係から、いくつかのDLLが追加されるますが、Xamarin.Formsも最新である1.3.1.6296にバージョンアップされます。

また、Androidでは、GooglePlayServicesもインストールされています。

[2015/01/19追記]

PM> Get-Package

Id                             Version              Description/Release Notes                                                                 
--                             -------              -------------------------                                                                 
WPtoolkit                      4.2013.08.16         Windows Phone toolkit provides a collection of controls, extension methods and page ani...
Xamarin.Android.Support.v4     19.1.0               C# bindings for android support library v4.                                               
Xamarin.Android.Support.v7.... 19.1.0               C# bindings for android support library v7 app compat.                                    
Xamarin.Android.Support.v7.... 19.1.0               C# bindings for android support library v7 media router.                                  
Xamarin.Forms                  1.3.1.6296           Build native UIs for iOS, Android, and Windows Phone from a single, shared C# codebase    
Xamarin.Forms.Maps             1.3.1.6296           Maps models and renderers for Xamarin.Forms                                               
Xamarin.GooglePlayServices     16.0.0               C# bindings for google play services.   


2 初期化

Mapsを使用するためには、Xamarin.FormsMaps.Init();という初期化コードが必要ですが、これは、PCLではなく、各プラットフォーム側に記述します。
記述位置は、Forms初期化の直後です。

iOSの場合

//2015.01.19修正
//App1.iOS/AppDelegate.cs

[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();//Maps初期化
        LoadApplication(new App());
        return base.FinishedLaunching(app, options);
    }
}

Androidの場合

//2015.01.19修正
//App1.Abdroid/MainActivity.cs
[Activity(Label = "App1", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity{
        protected override void OnCreate(Bundle bundle) {
            base.OnCreate(bundle);
        global::Xamarin.Forms.Forms.Init(this, bundle);
        Xamarin.FormsMaps.Init(this, bundle);//Maps初期化
        LoadApplication(new App());
    }
}

WindowsPhoneの場合

//2015.01.19修正
//App1.WinPhone/MainPage.xaml.cs
public partial class MainPage : global::Xamarin.Forms.Platform.WinPhone.FormsApplicationPage{
    public MainPage() {
        InitializeComponent();
        SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;

        global::Xamarin.Forms.Forms.Init();
        const string applicationId = "APP_ID_FROM_PORTAL";
        const string authToken = "AUTH_TOKEN_FROM_PORTAL";
        Xamarin.FormsMaps.Init(applicationId, authToken);//Maps初期化
        LoadApplication(new App1.App());
    }
}

パーミッション等の設定

Mapsを使用するためには、パーミッション等の設定のため、もう少し作業が必要です。
そして、この作業は各プラットフォームごとに違った作業になります。

(1)iOS

Info.plistへの文字列定義

iOS7 では、アプリ起動後に初めて位置情報測位の処理を実行しようとした場合、「位置情報測位の許可」を求めるためのメッセージが自動的に表示されます。
しかし iOS8 では、このようにして位置情報測位の許可を求めるために、「CLLocationManager」クラスに新しく追加された、requestAlwaysAuthorization/requestWhenInUseAuthorization
のいずれかのメソッドを、明示的に呼び出すようになりました。

そして、この時必要な、NSLocationAlwaysUsageDescription及びNSLocationWhenInUseUsageDescriptionの定義がInfo.plistに必要になります。

<key>NSLocationAlwaysUsageDescription</key>
    <string>Can we use your location</string>
<key>NSLocationWhenInUseUsageDescription</key>
    <string>We are using your location</string>

VisualStudioで開発している場合、Info.plistの編集は図のように設定画面になってしまうため、別にテキストとして編集する必要があります。

f:id:furuya02:20141214100643p:plain:w300 f:id:furuya02:20141214100642p:plain:w300

(2)Android

APIキー

Google Maps API v2」を使用するためには、APIキーを生成してプロジェクトに追加する必要があります。

APIキーの生成については下記のページ解説されています。
Obtaining a Google Maps API Key | Xamarin
※初音さんの下記のページには、より詳しい解説があります。
[Xamarin]Xamarin.Androidで地図を使う

取得したAPIキーは、AndroidManifest.xmlに下記のように追加します。

    <application>
        <meta-data android:name="com.google.android.maps.v2.API_KEY" 
                  android:value="AIzaSyBMUaWed8GWs-XXXXXXXXXXXXXX-SvY" />
    </application>

f:id:furuya02:20141214102112p:plain


INTERNET/ACCESS_NETWORK_STATE

インターネットに接続して地図データをダウンロードするため、INTERNET 及び ACCESS_NETWORK_STATE のパーミッションが必要です。プロジェクトのプロパティから「Android Manifest」を開いて、当該パーミッションをチェックしてください。


[2015/01/19追記]
version 1.3 では、新たに「ACCESS_FINE_LCOCATION」が無いとエラーとなっていました。
f:id:furuya02:20150119044937p:plain:w300

f:id:furuya02:20141214102140p:plain

(3)WindowsPhone

ID_CAP_MAP/D_CAP_LOCATION

f:id:furuya02:20141214102309p:plain

WMAppManifest.xmlを開いて、機能(Capabilities)タブで「ID_CAP_MAP」と「ID_CAP_LOCATION」にチェックが必要です。

AuthenticationID/AuthenticationToken

アプリをストアに展開するる前に、ApplicationId 及び AuthenticationToken をWindows Phone デベロッパー センター から取得して、コードに追加する必要があります。
以下に、その手順を示します。


デベロッパー・ダッシュボード(https://dev.windowsphone.com/dashboard)にログインし、「アプリの申請」を選択。
f:id:furuya02:20141214102317p:plain:w500
「アプリの情報」を選択
f:id:furuya02:20141214102327p:plain:w500
「名前」「カテゴリ」を入力して「保存」を選択
f:id:furuya02:20141214102339p:plain:w500
「アプリを申請」のページに戻ったら、「マップサービス」を選択
f:id:furuya02:20141214102347p:plain:w500
「ID取得」を選択すると、ID及びTokenが表示される

取得したIDとTokenは、FormsMaps.Init()にパラメータとしてセットします。

//App1.WinPhone/MainPage.xaml.cs
public MainPage() {
    // ・・・・・略・・・・
    Forms.Init();
    const string applicationId = "APP_ID_FROM_PORTAL";
    const string authToken = "AUTH_TOKEN_FROM_PORTAL";
    Xamarin.FormsMaps.Init(applicationId, authToken);
    // ・・・・・略・・・・
}

4 PCLからの利用

「インストール」「初期化」及び「各プラットフォームごとのパーミッション等の設定」が終わると、MapsはPLC及びシェアードコードで利用が可能になります。

下記は、XamarinDeveloperで紹介されているコードのコピペです。

//2015.01.19修正
public class App : Application{
    public App() {
        MainPage = new MapPage();
    }
    // ・・・・省略・・・
}

public class MapPage : ContentPage{
    public MapPage() {
        var map = new Map( MapSpan.FromCenterAndRadius(
                     new Position(37, -122), Distance.FromMiles(0.3))) {
                          IsShowingUser = true,
                          HeightRequest = 100,
                          WidthRequest = 960,
                          VerticalOptions = LayoutOptions.FillAndExpand
                     };
        var position = new Position(37, -122); // Latitude, Longitude
        var pin = new Pin {
            Type = PinType.Place,
            Position = position,
            Label = "custom pin",
            Address = "custom detail info"
        };
        map.Pins.Add(pin);

        Content = new StackLayout {
            Children = { map }
        }; 
    }
}

5 トラブルシュート

最後に、作業中に私が確認したエラーとその対処を列挙しておきます。参考になれば幸いです。

(1) Androidエミュレータで表示できない

これは、エラーという訳では無いのですが・・・Androidエミュレータでは、デフォルトでMapsを表示することはできません。

田淵さんのページで、Xamarin Android Player でMapsを使用できるようにするための方法が、詳しく解説されていますので、こちらをご参照ください。
Xamarin Android Player で Google Play サービスを使用するには - Xamarin 日本語情報

(2) Java Max Heep Size

Androidでは、デフォルトで、下記のエラーが発生してコンパイルが失敗します。
COMPILETODALVIK : UNEXPECTED TOP-LEVEL error
f:id:furuya02:20141214104040p:plain:w500
これは、ヒープのサイズを増やすことで解決できます。
プロジェクトのプロパティから「Android Options」-「Advanced」とたどって「Java Max Heep Size」に値を設定してください。
f:id:furuya02:20141214104037p:plain:w500

(3) READ_GSERVICESパーミッション

実機では発生しなかったのですが、Xamarin Android Playerを使用しようとすると、最初に下記のエラーが出ました。
Java.Lang.SecurityException: The Maps API requires the additional following permissions to be set in the AndroidManifest.xml to ensure a correct behavior:
f:id:furuya02:20141214103205p:plain:w300
指示通り
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
を追加することでエラーはでなくなりました。
f:id:furuya02:20141214103204p:plain:w500

(4) Warning: No authentication ID and/or token specified

WindowsPhoneで、地図の下部に赤字で「Warning: No authentication ID and/or token specified」が表示される場合は、
AppIDとAppTokenの設定に誤りがあります。このままではストアへの登録ができません。
f:id:furuya02:20141214104925p:plain:w150

(5) 灰色画面になる

Androidで、特にエラーは出ないが、地図が表示されず画面が灰色になってしまった場合は、GoogleMapsのAPIキーが正常設定されていない可能性があります。
f:id:furuya02:20141214105900p:plain:w150
APIキーが正常に生成されているか?、AndroidManifest.xmlに正常に登録されているか?パッケージ名に間違いが無いかなどを確認してみて下さい。
下記の図は、APIキーを生成した時のパッケージ名とAndroidManifest.xmlのパッケージ名が一致しているかどうかを確認しているようすです。
f:id:furuya02:20141214110239p:plain:w300
f:id:furuya02:20141214110047p:plain:w300

5 参考資料

Maps | Xamarin
[Xamarin]Xamarin.Androidで地図を使う
Xamarin Android Player で Google Play サービスを使用するには - Xamarin 日本語情報
How to authenticate a Maps app (Windows)
Xamarin API Documentation
Google Maps for Windows Phone 7 using Bing Map Control - CodeProject

【 Xamarin 記事一覧 】