- 位置情報を取得する
- 位置情報を住所の文字列に変換する
方法について書きます。
1. 位置情報の取得
現在の位置情報を取得
Namespace Windows.Devices.Geolocation にあるGeolocator Class を使います。
// Appの初期化の辺りで一発Geolocatorを作成しておき、 this.geolocator = new Geolocator(); ... // 位置情報が必要な時にGetGeopositionAsyncを呼ぶ。 var pos = await this.geolocator.GetGeopositionAsync();
ここで要注意なのは、
- 位置情報を取得するアプリは、AppxManifest.xml内で位置情報の使用を宣言する必要があること
- 起動後初回の使用では「位置情報の取得」の確認メッセージが出ること
- GetGeopositionAsync では緯度経度のみが取得でき、住所データは取得出来ない事(今のところ)
1. については、VSのManifest Designerでチェックを入れるだけです。又、ストア上にはこのアプリが位置情報を使用する旨が表示されます。
2. これはAPIをCallしたところ(上の例だとGetGeopositionAsync)で問答無用に表示されます。
このため、なるべく、Userの操作の結果(ボタン押下のハンドラ等)…「○○をやろうとした結果」として呼ばれるところでAPIをCallすべきと思います。
Userの操作の無い所…初期化中等…でいきなりこれを出すのはあまり上品では無いように思います。そういうアプリたまに見ますが。
3. GetPositionAsync の返り値 として帰るGeoposition Classには以下二つのProperty…
- CivicAddress
- Coordinate
があり、前者には住所文字列、後者には緯度経度が入る、事になっています。
が、前者CivicAddressは、Address Provider、緯度経度を住所に変換するプロバイダがインストールされていない場合常に空文字列で返ります。
そして、現在のところAddress Providerは何処からも提供されていないです。
画像の位置情報を取得
JPEG画像にEXIF データとして位置情報が埋め込まれている場合があります。
これは大変に簡単で、画像ファイルのStorageFileからImagePropertiesを取得します。もし緯度経度データが存在すれば、ImageProperties.LatitudeとLongitudeにデータが詰まっています。
※ 画像が「ファイル」である場合…Storage上のFileにはこれでいけるのですが…例えば、一度OpenFileAsyncしてStreamに全部ガーっと呼んだメモリ上のデータや、Httpか何かでがーっとDLしてまだファイルに落として無いデータ、に対して使用することは出来ないです。困った。
2. 位置情報を住所文字列に変換する
上で触れたようにWinRT組み込みのGeolocator Classだけでは不可能で、Bing.Maps APIを使う事になります。
緯度経度をAPI経由でBingに投げると、住所に変換して返してくれるという感じです。
Bing APIの使用には
- アカウント登録とAPI Keyの作成
- Bing Maps SDKのインストールと参照の追加
が必要になります。方法はMSのサイトでも見て頂ければいいのですが、無料の場合、
- キーは3つまで
- 50,000 Transaction/Day
となっています。間違えていると怖いのでご自分でご確認下さい。
※ Bing Maps API は Architecture毎のNative BinaryとしてBuildされています。このため、このAPIを「使う」Moduleは(.NETで書いたC#であっても)「Any CPU」としてBuildすることが出来なくなります。
Bing Maps API を使用した住所の取得
ここまで行くとソース見たほうが早いべ、という事でソースを貼って終わります。
注意点としては、LocationData は複数返ってくるので、中の属性を見て必要なものだけ拾う、という所です。
※ 以下の例は、アプリ「ごみ出しカレンダー」で使っているCodeです。
ごみ種別の入力画面でアプリバー上の「検索」ボタンを押すと、PCの現在地を使ってごみ収集ページを検索してあげる、という機能です。(自治体ごとに千差万別のごみ出しページをスクレイピングとかやってられないので、そこから先は手動です)
ごみ出しカレンダー
http://apps.microsoft.com/windows/app/c3cdaa23-5b99-4b28-803f-00b90c86a601
private async void GetAddressAppBarButton_Click(object sender, RoutedEventArgs e) { //「PCの位置情報から自治体のごみ出しページを検索してあげる」 var loader = new Windows.ApplicationModel.Resources.ResourceLoader(); var pos = await this.geolocator.GetGeopositionAsync(); Bing.Maps.Search.ReverseGeocodeRequestOptions requestOptions = new Bing.Maps.Search.ReverseGeocodeRequestOptions(new Location(pos.Coordinate.Point.Position.Latitude, pos.Coordinate.Point.Position.Longitude)); var searchManager = this.bingMaps.SearchManager; var response = await searchManager.ReverseGeocodeAsync(requestOptions); string query = ""; Bing.Maps.Search.GeocodeAddress addr = null; if (null != response && 0 < response.LocationData.Count) { for (int i = 0; i < response.LocationData.Count; i++) { /// 住所表示に使うLocationDataを探すCode /// Bing.Mapsでは、Responseに複数のLocationDataが詰まって返ってくることがある。(普通は一個だが、たまに二つ) /// 一つは地図上での住所表示用データ ... GeocodeLocationUsageType 'Display' /// もう一つはナビ用の道路情報。 ... GeocodeLocationUsageType 'Route' または 'Both'. /// 後者については住所の文字列が入っていないので、今回は必要が無いデータとなる。それを弾いて住所表示用だけをPickする。 /// (後者は大体Nameに「MajorRoad」とかが入ってる) if (null != response.LocationData[i].GeocodeLocations && 0 < response.LocationData[i].GeocodeLocations.Count) { if (Bing.Maps.Search.GeocodeLocationUsageType.Display == response.LocationData[i].GeocodeLocations[0].UsageType) { /// 'Display'が複数ある場合は… 知らないし 最初の一つだけPickする addr = response.LocationData[i].Address; break; } } } if( null != addr ) { /// StrWebQuery ... "ごみ+収集日+" /// AdminDistrict ... "神奈川県" 大体県まで /// AdminDistrict2 ... データ見たこと無いのだけど 郡とか? /// Locality ... "川崎市高津区" 大体市+区まで /// AddressLine ... "foo町bar丁目1-2-3" 最後のアドレス ごみ収集日検索では却って結果出なくなるので使わない query = loader.GetString("StrWebQuery"); if( 0 < addr.AdminDistrict.Count() ) query += (addr.AdminDistrict + "+"); if( 0 < addr.AdminDistrict2.Count() ) query += (addr.AdminDistrict2 + "+"); if( 0 < addr.Locality.Count() ) query += (addr.Locality ); } // URL形式にエンコ %1234...みたいなやつ query = System.Net.WebUtility.UrlEncode(query); // ブラウザ起動 await Windows.System.Launcher.LaunchUriAsync(new Uri( "http://www.google.com/search?q=" + query)); } else { // 何もすることが無い // Errormsgも出さなくていいかなと } } }
0 件のコメント:
コメントを投稿