Xamarin で「駅すぱあとWebサービス」を利用してみた!

2204
0
12-18-2017 10:07 PM

Xamarin で「駅すぱあとWebサービス」を利用してみた!

今回、株式会社ヴァル研究所が提供している「駅すぱあと Web サービス」を Xamarin で利用してみました。

駅すぱあと Web サービスの API を利用して駅情報を取得して、駅情報を地図にマッピングするというシンプルな地図アプリを作成しましたので、それについて紹介したいと思います。

地図アプリは、Xamarin.Forms を利用して SDK には、ArcGIS Runtime SDK for .NET ※1を利用しています。

※1 ArcGIS Runtime SDK for .NET は、ArcGIS プラットフォームを利用した地図開発用の SDK です。Windows プラットフォーム向けの開発キットですが、Xamarin.Forms、Xamarin.iOS、Xamarin.Android にも対応しています。

 

 

1.駅すぱあと Web サービスとは

 

駅すぱあと Web サービスとは、株式会社ヴァル研究所が提供しているサービスで、交通情報の API です。

メンテナンスフリーの鉄道情報を 円(フリープラン)から提供しており、経路探索や路線情報、交通費計算などの各種機能を、サービスやシステムに組み込み、高機能化を実現することが可能です。

また、フリープランは個人に限らず、企業でも利用することができるため、手軽に利用できるところも魅力的です。

 

今回はフリープランを利用しました。フリープランでは、駅情報や駅の付加情報(出口情報や福祉施設情報など)、さらに路線や会社情報まで取得することができます。API の仕様書もしっかりとまとめられているので簡単に開発を進めることができました。

 

2.Xamarin.Forms で API の利用から地図表示まで

 

今回作成した地図アプリは、入力された駅名をAPI経由で検索して、検索にヒットした駅の位置情報を地図上にポイントとして表示しています。駅名の属性情報はポップアップ画面に表示しました。

 

 

 

① 駅情報 API の利用

 

駅情報 API では、駅名称や駅の読みかな、駅コード、交通種別などを取得することができます。もちろん、駅の場所として、緯度・経度情報も取得できます。

 

駅情報 API の詳細な仕様についてはをご参照してください。

 

API のレスポンスデータは JSON 形式で返却されます。Xamarin.Forms JSON 形式のデータを扱う場合にはいくつか便利なライブラリがありますが、今回は、Json.NET というライブラリを利用しました。こちらは、.NET 用のオープンソースの JSON ライブラリで、JSON の作成からパース、検索までを行うことができ、JSON のデータを扱う場合にはとても便利なライブラリです。

 

コードの実装(C#

 

API のリクエストや JSON オブジェクトの作成は、HttpService クラスを作成して、そのクラス内で行っています。API へのリクエストは、HttpClient クラスを利用しています。これはアプリケーション内で HTTP リクエストを投げたい場合に使うクラスで、.NET Framework 4.5 で新設されています。

そして、API のリクエスト結果は、Json.NET を利用して、JSON をオブジェクトにデシリアライズしています。JSON をオブジェクトにすることで、データの取り出しなどが楽になります。

//  駅すぱあと Web サービスの駅情報 API の URL
string queryString = api_Endpoint + "/v1/json/station?key=" + api_key + "&" + "gcs=wgs84&" + "name=" + Ekiworld;
//  HttpService クラスからリクエストを投げて、リクエスト結果を JSON オブジェクトで取得
JObject results = await HttpService.getDataFromService(queryString).ConfigureAwait(false);
var resultset = results["ResultSet"];
:
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

HttpService クラス

public class HttpService 
{
     private static HttpClient client = new HttpClient();

     public static async Task<JObject> getDataFromService(string queryString)
     {
        JObject data = null;
        // HttpClient クラスを利用して、駅すぱあと Web サービスの URL を指定
        var response = await client.GetAsync(queryString);
        if ((response != null) && !((int)response.StatusCode >= 400))
        {
           string json = response.Content.ReadAsStringAsync().Result;
           // JSON をオブジェクトにデシリアライズ
           data = (JObject)JsonConvert.DeserializeObject(json);
        }
        return data;
     }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

② 地図上に駅情報を表示

 

Xamarin.Forms での地図表示には ArcGIS Runtime SDK for .NET を利用しています。API で取得した駅情報を地図上に表示し、地図上の駅をクリックすると駅情報をポップアップ画面に表示します。

 

コードの実装(C#

 

駅情報の表示には FeatureCollectionLayer クラスを利用しました。これは、座標などの位置情報を持ったジオメトリや属性情報の地物をフィーチャとして作成し、作成したフィーチャの集合をレイヤー オブジェクトとして定義したものです。

 

データはデータベースのテーブルのように管理して扱うことができるため、データの取得や更新などを行う場合にも便利です。

// フィーチャ コレクションのインスタンス化  ※ フィーチャ コレクションとは、ジオメトリや属性情報の地物として作成したフィーチャのリストになります。
FeatureCollection featuresCollection = new FeatureCollection();
foreach (Ekiworld Eki in Ekis) 
{
     // フィールド情報を定義
     List<Field> pointFields = new List<Field>();
     Field stationName = new Field(FieldType.Text, "stationName", Eki.stationName, 50);
     Field stationCode = new Field(FieldType.Text, "stationCode", Eki.stationCode, 50);
     Field stationYomi = new Field(FieldType.Text, "stationYomi", Eki.stationYomi, 50);
       :
     pointFields.Add(stationName);
     pointFields.Add(stationCode);
     pointFields.Add(stationYomi);
     // 作成したフィールド情報やジオメトリタイプからフィーチャ コレクションテーブルをインスタンス化
     FeatureCollectionTable pointsTable = new FeatureCollectionTable(pointFields, GeometryType.Point, SpatialReferences.Wgs84);
     pointsTable.Renderer = CreateRenderer(GeometryType.Point);
     // 新しいポイント フィーチャを作成し、ジオメトリと属性値を設定
     Feature pointFeature = pointsTable.CreateFeature();
     pointFeature.SetAttributeValue(stationName, Eki.stationName);
       :
     MapPoint point = new MapPoint(Eki.longi_d, Eki.lati_d, SpatialReferences.Wgs84);
     pointFeature.Geometry = point;
     await pointsTable.AddFeatureAsync(pointFeature);
     // フィーチャ コレクションにフィーチャ コレクションテーブルを追加
     featuresCollection.Tables.Add(pointsTable);
}
// フィーチャ コレクションからフィーチャ コレクションレイヤーをインスタンス化
FeatureCollectionLayer collectionLayer = new FeatureCollectionLayer(featuresCollection);
// フィーチャ コレクションレイヤーを Map に追加
MyMapView.Map.OperationalLayers.Add(collectionLayer);
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

地図上の任意の駅をクリックした時に、その駅情報を判別して情報を取得するために、GeoView.IdentifyLayerAsync メソッドを使用しました。このメソッドでは、データの取得条件として、レイヤーの指定やポップアップの要素だけを含めるかどうかや、レスポンス結果のデータ件数などを指定することができます。また、クリック地点のポイントを識別するために、クリック地点からの許容範囲も指定することができます。地図をクリックした時のイベントを制御できるため、目的に合わせて利用することができます。

var layer = MyMapView.Map.OperationalLayers[0];  // レイヤーの指定
var pixelTolerance = 20; // クリック地点からの許容範囲
var returnPopupsOnly = false; //ポップアップの要素だけを含めるか
var maxResults = 1; // レスポンス結果の MAX値
// IdentifyLayerAsync メソッドの定義
var idResults = await MyMapView.IdentifyLayerAsync(layer, e.Position, pixelTolerance, returnPopupsOnly, maxResults);
if (idResults.SublayerResults.Count > 0)
{
       foreach (var sr in idResults.SublayerResults)
       {
          // SublayerResults 内の GeoElements からフィーチャの情報を取得
            foreach (GeoElement idElement in sr.GeoElements)
            {
                  Feature idFeature = idElement as Feature;
                  stationName = idFeature.FeatureTable.GetField("stationName").Alias;
                  :
            }
       }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

GeoView.IdentifyLayerAsync メソッドから取得した駅情報から属性情報を取得して、ポップアップ画面に表示します。上記で指定したポップアップの要素を利用することもできますが、今回はシンプルに表示したかったので、GeoView.ShowCalloutAt メソッドを使用しました。このメソッドでは、クリック地点の緯度・経度、ポップアップ画面に表示する内容を指定することで、呼び出せます。

string mapLocationDescription = string.Format("Lat:{0:F3} Long:{1:F3}", lati_d, longi_d);
// 駅情報の座標を指定して、CalloutDefinition をインスタンス化
CalloutDefinition myCalloutDefinition = new CalloutDefinition("Location:", mapLocationDescription);
// myCalloutDefinition に ポップアップに表示させたい内容を指定(Text、DetailText 、BttonImage)
myCalloutDefinition.Text = prefName + " : " + stationName;
myCalloutDefinition.DetailText = stationYomi;
RuntimeImage rtImg = new RuntimeImage(new Uri("https://cdn0.iconfinder.com/data/icons/business-finance-vol-14-2/512/69-128.png"));
await rtImg.LoadAsync();
myCalloutDefinition.ButtonImage = rtImg;
// クリック地点の座標と、ポップアップに表示する内容を指定することで、ShowCalloutAt が呼ばれる
MyMapView.ShowCalloutAt(e.Location, myCalloutDefinition);
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

 

3.最後に

 

Xamarin でもWeb API を簡単に利用できるのも魅力的ですし、Web API で取得した情報は ArcGIS でも活用できますので、地図アプリのサービスの幅が広がると思います。また、駅すぱあと Web サービスは、今回使用した駅情報 API 以外にも「駅の付加情報」や「路線の運行路線や平均路線情報」などもありますので、それらの API も活用することでもっと面白いアプリが作成できると思いました。

 

次回も Xamarin とサードパーティのサービスを活用したアプリについて紹介したいと思います。

 

今回作成したサンプル アプリケーションは、ESRIジャパンの GitHub にも公開していますので、ぜひ、触ってみてください!

GitHub - EsriJapan/arcgis-samples-dotnet: ArcGIS Runtime SDK for .NET のサンプル集

 

関連リンク

Version history
Last update:
‎11-12-2020 11:11 PM
Updated by: