『Google Maps SDK for iOS』と標準MapKitの違いまとめ!



標準のMapKitではなく、『Google Maps SDK for iOS』を使用したい時に
MapKitの機能と比較しながらだと、移行しやすいかと考え
記事にまとめました。

日本語の情報はまだ少なく、開発時に苦労するので
今回の記事は中々重宝するのでは無いでしょうか?

対象バージョンは、『Google Maps SDK for iOS(Version 1.3.1 (June 2013))』です。
私がプロジェクトをMapKitから『Google Maps SDK for iOS』へ移行した際に
置き換えた機能ですので、『違い』を全て網羅しているわけではありませんが、
この先も違いが新たに見つかり次第、記事を更新したいと思います。

『Google Maps SDK for iOS』のインストール方法は他のブログで紹介されていますので、
今回は割愛して、ソースコードの違いに焦点を絞り、解説したいと思います。

  1. SDKの読み込みと、置き換えられるクラス
  2. リバースジオコーダーの実装方法の違い
  3. 地図に刺すピン(アノテーション)の扱い方の違い
  4. 地図の移動、カメラワーク構築方法の違い
  5. その他の違い




SDKの読み込みと、置き換えられるクラス



SDKを読み込もう



SDKの読み込みは、勿論『#import』にて行いますが、
標準MapKitでは『<MapKit/MapKit.h>』を読み込み、
『Google Maps SDK for iOS』では『GoogleMaps/GoogleMaps.h』を読み込みます。


// 標準MapKitの読み込み
#import <MapKit/MapKit.h>

// Google Maps SDK for iOSの読み込み
#import <GoogleMaps/GoogleMaps.h>



マップアプリの本命!地図のメインクラス


地図を表すメインとなるクラスです。標準では『MKMapView』を使用しますが、
『Google Maps SDK for iOS』では『GMSMapView』を使用します。
地図の表示方法には特に変更点はありませんので、
『Google Maps SDK for iOS』でも標準MapKitの様に実装します。
クラス名が置き換わった程度に考えていても問題ないでしょう。


// 標準MapKitの地図クラス
MKMapView* mapView = [[[MKMapView alloc] init] autorelease];

// Google Maps SDK for iOSの地図クラス
GMSMapView* mapView = [[[GMSMapView alloc] init] autorelease];




Delegateも置換えです


Delegateも単純に置き換える事が出来ますが、
Delegateメソッドはかなり動作も種類も異なりますので、注意が必要です。
各メソッドの置換えと修正方法の解説は後述いたしますので、
まずはDelegateクラス名の違いを把握して下さい。

// 標準MapKitのDelegate
<MKMapViewDelegate>

// 『Google Maps SDK for iOS』のDelegate
<GMSMapViewDelegate>




緯度経度を元に住所を取得するリバースジオコーダー


リバースジオコーダーの実装方法もかなり標準MapKitとは異なります。
具体的な実装例は後述致しますが、まずは該当クラス名の違いを明記します。

// 標準MapKitのリバースジオコーダー
MKReverseGeocodeer* geocodeer = [[[MKReverseGeocodeer alloc] init] autorelease];

// Google Maps SDK for iOSのリバースジオコーダー
GMSGeocoder* geocodeer = [[[GMSGeocoder alloc] init] autorelease];



ピン(アノテーション)もマーカーへ変更です。


標準MapKitでは、アノテーションと言われるピンを地図に刺す事が出来ました。
Google Maps SDK for iOSでは、同様の機能をマーカーと呼び、
扱い方がかなり異なります。
この違いや、具体的な実装例、注意点等は後述にて詳しく解説致しますが、
『そのまま移行は出来ない』とだけ覚えておいて下さい。


// 標準MapKitのピン
MKAnnotation* annotation = [[[MKAnnotation alloc] init] autorelease];

// Google Maps SDK for iOSのピン
GMSMarker* marker = [[[GMSMarker alloc] init] autorelease];







リバースジオコーダーの実装方法の違い




標準MapKitでは、MKReverseGeocoderに調べたいロケーションをセットして、
デリゲートの通知先を指定すれば、成功時と失敗時に起動される
デリゲートメソッドから住所情報を取得出来ます。
具体的には、下記の様な実装でしょう。



// キャンセルが発行された時に解放されていたら困るので、オートリリースを掛けずに、明示的に解放する
self.reverseGeocoder   = [[MKReverseGeocoder alloc] initWithCoordinate:location_];
self.reverseGeocoder.delegate = self;
[self.reverseGeocoder start];

// プレースマークが取得できた時の処理
-(void)reverseGeocoder:(MKReverseGeocoder*)geocoder_ didFindPlacemark:(MKPlacemark*)placemark_
{
}
// プレースマークが取得できなかったときの処理
-(void)reverseGeocoder:(MKReverseGeocoder*)geocoder_ didFailWithError:(NSError*)error_
{
}




『Google Maps SDK for iOS』では、デリゲートを介さずに取得する事が出来、
その場合はリスナーとしてGMSReverseGeocodeCallbackを実装します。
GMSReverseGeocodeCallbackは、別メソッドへ逃がしても良いですし、ブロック処理にしても構いません。
まずは、下記の実装例をご覧下さい。


// リバースジオコードを起動する
self.reverseGeocoder   = [[[GMSGeocoder alloc] init] autorelease];
[self.reverseGeocoder reverseGeocodeCoordinate:location_
 completionHandler:
  ^(GMSReverseGeocodeResponse* res_, NSError* error )
  {
   // 結果を取得する
   GMSReverseGeocodeResult* results_obj = [res_ firstResult];
   if( results_obj ){

    // 住所文字列を取得する
    NSString* adr1 = [results_obj addressLine1];
    NSString* adr2 = [results_obj addressLine2];
   }
   else{
    NSLog(@"reverseGeocoder Error");
    // 住所情報の取得に失敗
   }
  }
];




GMSGeocoderのインスタンスを作成したら、下記を実装します。
-(void)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate completionHandler:(GMSReverseGeocodeCallback)handler

与える引数は、調査対象の位置情報と返却内容の通知先メソッドです。上記の例ではブロック処理としていますので、
そのまま引数指定の部分に実装しています。

取得出来る情報は、返却情報を格納するGMSReverseGeocodeResponseクラスと、エラー情報です。
GMSReverseGeocodeResponseクラスには、返却値を保持するGMSReverseGeocodeResultクラスを持っています。
GMSReverseGeocodeResultからは、『addressLine1』や『addressLine2』で住所文字列を取得する事が出来ます。

失敗判定は、GMSReverseGeocodeResultが取れるか否かでの判定で問題ないでしょう。
(GMSReverseGeocodeResultが取れないと住所文字列が取れないので、失敗扱いとする)






地図に刺すピン(アノテーション)の扱い方の違い




標準MapKitのアノテーションと『Google Maps SDK for iOS』のマーカーでは、実装方法がまったく異なります。
私的な感覚では、標準MapKitよりも『Google Maps SDK for iOS』の方が
シンプルで分かりやすく、扱いやすくなったと感じます。


標準MapKitでは、アノテーション表示前にデリゲートメソッドとして

-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id)annotation

が呼ばれ、アノテーションの表示する設定を実装しますが、(TableViewの実装方法に近いかも)
GMSMarkerでは、そういった専用メソッド内に全ての実装を集約するのではなく、
GMSMarker毎にプロパティに値をセットする形で作成します。

そういったプロパティは標準MapKitでもありますが、
例えば下記の様な違いがあります。


/*
 アノテーション自身の位置(CLLocationCoordinate2D)
*/
// 標準MapKit
annotation.coordinate = coordinate;

// Google Maps SDK for iOS
marker.position = coordinate;


/**
 サブタイトル
*/
// 標準MapKit
annotation.subtitle = @"サブタイトル";

// Google Maps SDK for iOS
marker.snippet = @"サブタイトル";



アノテーションやマーカー作成時だけでなく、設定内容を確認したい時に
参照するプロパティも上記の様に異なるので、こういった違いは認識しておいた方が良さそうです。

そして、地図への設置方法も異なります。


// 標準MapKit
[self.mapView addAnnotation:annotation];

// Google Maps SDK for iOS
marker.map = self.mapView;




標準MapKitでは、専用のメソッドを叩いてマップへ追加しますが、
『Google Maps SDK for iOS』では『map』プロパティに、追加したいマップのインスタンスを渡す事で
マップとGMSMarkerが関連付けられ、結果として設定した地図へ設置される様になります。


また、地図にて表示されるアイコン画像を変更したい時もあるでしょう。
MKAnnotationでは、通常ピンが使用され、GMSMarkerではバルーンが使用されます。

MKAnnotationのアイコン画像をカスタマイズするには、

-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id)annotation

内にて、viewを変更する等の処理の実装が必要で、MKAnnotation毎に画像を変えたいときは
中で何かしらの判定を行って実装する必要がありました。

しかし、『Google Maps SDK for iOS』ではGMSMarker自体にアイコン画像を保持する
プロパティがありますので、画像を変更したいときは、新しい画像をプロパティにセットするだけです。
GMSMarker毎に変えたい時も、それぞれのプロパティに別々の画像をセットするだけですので、
カスタマイズも簡単で、保守性も増すかと思います。

具体的には、『icon』プロパティにセットします。
実装例は下記の通りです。

marker.icon = [UIImage imageNamed:@"map_location.png"];


簡単ですね。

しかし、アイコ画像をマーカーへセットするのは簡単ですが、
注意すべき落とし穴がありまして、
アイコンに設定する画像の原点はMKAnnotationでは画像の中心でしたが、
GMSMarkerでは画像の一番下側となります。

例えば、MKAnnotationでピンの画像を作ろうとした場合、地図に刺さるピンの先端を
画像の中央としなければいけませんでしたが、GMSMarkerでは、地図に刺さるピンの先端を
画像の一番下にしなければいけません。

標準MapKitから『Google Maps SDK for iOS』へ移行する際には、
画像リソースの作り直しも必要になりますので、注意してください。
うっかり同じ画像を使用するとと、期待する表示位置よりも上の方にピンが刺さる事となってしまい、
座標の処理を疑い始め、中々リソースの違いに気が付かないものです。

注意点として覚えて頂ければ幸いです。


それでは、一旦整理してみましょう。

コレまでのGMSMarkerの内容を纏めますと、
GMSMarkerを作成して地図へ追加するには下記の様な実装になるかと思います。


GMSMarker* marker  = [[[GMSMarker alloc] init] autorelease];
marker.title   = @"タイトル";
marker.snippet   = @"サブタイトル";
marker.icon    = [UIImage imageNamed:@"map_location.png"];
marker.position   = coordinate;
marker.map    = self.mapView;



地図へ追加した後は、プログラム側から特定のGMSMarkerを選択状態にしたい事もあるでしょう。
標準MapKitでは、専用メソッドが用意されていましたが、
『Google Maps SDK for iOS』ではマップのプロパティに選択状態となっているマーカーを
保持するプロパティが用意されていますので、そのプロパティへ
選択状態としたいマーカーをセットする事で、選択状態とさせます。


// 標準MapKit
[self.mapView selectAnnotation:annotation animated:NO];

// Google Maps SDK for iOS
self.mapView.selectedMarker = marker;



また、選択状態プロパティに対して『0』をセットする事で、
選択状態を解除する事が出来ます。

self.mapView.selectedMarker = 0;



地図へ追加したマーカーの削除は、アノテーションの頃ですと
『removeAnnotation』メソッドにて削除させていましたが、
GMSMarkerではプロパティにてマップと『関連付け』られているだけですので、
プロパティに対して『nil』をセットする事で、地図からマーカーを取り去る事が出来ます。

marker.map = nil;


プロパティ制御の良い所は、それぞれのマーカーに対する設定を行うスタイルで開発するので、
細やかな違いや、纏まった状態を把握しやすさですが、
全てに対して同じ事を行いたい時はループで回す等、少し面倒です。

しかし、削除はマップとの関連付けですので、
全てのマーカーを取り去るメソッドが用意されています。

全てのマーカーを消してリフレッシュさせたい時等に使用すると良いでしょう。


[self.mapView clear];



MKAnnotationとGMSMarkerでは、実装方法がとても異なるので、
移行の際にはしっかりと違いを意識した上で構築したいですね。










地図の移動、カメラワーク構築方法の違い




『Google Maps SDK for iOS』の表示機能は、標準MapKitとは違ってカメラという概念を用います。
カメラワークのポジション取り等は、専用のスタティックメソッドにて要素を算出し、
作成したカメラワークを地図へ渡す事によって、地図を表示すべきカメラ位置が決まり、
結果として表示位置が変わった様に見せる事が出来ます。

たとえば、全てのピンが収まる縮尺と表示位置へカメラを移動させたい時は
標準MapKitでは下記の様に実装します。



MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(
 center_coordinate, max_distance *2.0, max_distance *2.0);
[self.mapView setRegion:region animated:YES];



MKCoordinateRegionを作成して、専用メソッドで設定する方法を用います。

『Google Maps SDK for iOS』では、まず中心点と、距離と範囲を指定して、最適なズームレベルを算出します。
次に、その算出した縮尺と中心位置を元に、カメラの位置を作成します。
マップには、カメラを保持するプロパティが用意されていますので、作成したカメラワークを
プロパティへセットする事で、指定の縮尺と位置へカメラを切り替える事が出来ます。



// ZOOMレベルを算出
CGFloat zoom_level = [GMSCameraPosition zoomAtCoordinate:center_coordinate forMeters:max_distance*2 perPoints:320];

// 縮尺と位置を指定してカメラを作成
GMSCameraPosition* camera = [GMSCameraPosition cameraWithTarget:center_coordinate zoom:zoom_level];

// カメラをマップへ当てはめる
self.mapView.camera = camera;



距離を基準に、最適な縮尺を算出するメソッドは良く使用しますので、
覚えておいてください。

後は基本的に、カメラを作ってカメラを地図へ渡すといったイメージですので、
それほど難しくはないと思います。

しかし結局の所、処理が二つ必要となってしまします。

単純な位置の移動だけでしたら、GMSMapViewが持っている視点移動メソッドを使用する事で
簡単に視点移動する事も可能です。
下記に標準MapKitと並べて例を示します。
(coordinateには、既に位置情報としてCLLocationCoordinate2Dを保持しているものとします。)



// MKMapView
[self.mapView setCenterCoordinate:coordinate animated:YES];

// GMSMapView
[self.mapView animateToLocation:coordinate];




他にも、縮尺だけの変更でしたら上記の様なGMSMapViewのインスタンスメソッドで
『animateToZoom』にて縮尺を設定するだけですが、
緯度、経度、縮尺を同時に設定するとしたら、下記の様に実装します。

// 緯度、経度、縮尺を元にカメラを作成
GMSCameraPosition* camera = [GMSCameraPosition cameraWithLatitude:location.latitude longitude:location.longitude zoom:zoom_level];
self.mapView.camera = camera;




カメラワークについて色々と出来る用になると、それだけでダイナミックな演出が可能となりますので、是非とも習得して下さい。
ほかにも、沢山面白い演出が用意されおり、実用的ですので興味のある方は公式リファレンスも参照してください。







その他の違い




マップ上の現在位置を保持するプロパティ名も違います。
移行する際にうっかりと見落としやすいので、気をつけましょう。


// MKMapView
MKUserLocation* coordinate = mapView.userLocation;

// GMSMapView
CLLocation* coordinate = mapView.myLocation;



現在表示中のマップの中心位置を緯度経度の座標で取得するには、
やはりプロパティから得る事が出来ますが、そのプロパティも変更が必要です。


// MKMapView
CLLocationCoordinate2D coordinate = mapView.centerCoordinate;

// GMSMapView
CLLocationCoordinate2D coordinate = mapView.camera.target;


GMSMapViewでは、視点はカメラが制御しますので、カメラの中から取得する必要がある点が肝です。




そして、マップのドラッグを検知するデリゲートメソッドも異なります。
マップをドラッグして視点変更字の移動完了(移動中)で通知されるメソッド名は下記の通りです。


// MKMapViewDelegate
-(void)mapView:(MKMapView*)map_view_ regionDidChangeAnimated:(BOOL)animated_

// GMSMapViewDelegate
-(void)mapView:(GMSMapView*)map_view_ didChangeCameraPosition:(GMSCameraPosition *)position_



他にも、異なる点は沢山有るかと思いますが、殆どが新しい機能や、
『Google Maps SDK for iOS』独自の機能ですので、移行の際は修正というよりも新規実装になるかと思います。


もし、ささいな違いがあって引っかかるポイントが他にもある場合や、
認識違いがありましたらコメント頂ければ幸いです。

まだまだ新しいSDKですので、バージョンアップも頻繁に行われていますので、
必ず使用予定のバージョンと見比べて下さい。


本記事執筆時のバージョンは『Google Maps SDK for iOS(Version 1.3.1 (June 2013))』です。


この『Google Maps SDK for iOS』と標準MapKitの違いまとめ!が
移行の際のお役に立てれば何よりです。





4 Responses to 『Google Maps SDK for iOS』と標準MapKitの違いまとめ!

  1. 非常に参考になりました。ありがとうございます!

    返信削除
    返信
    1. 佐藤光 様

      この度はコメント頂き、誠に有難う御座います。
      引き続き有益な情報を公開して参りますので、
      今後とも何卒よろしくお願い致します。

      削除
    2. よろしくお願いします!
      おかげさまでiPhoneアプリリリースできました!

      削除
    3. 佐藤光 様

      この度はコメント頂き、誠に有難う御座います。
      無事にリリース出来たようで何よりです。
      引き続き有益な情報を公開して参りますので、
      今後とも何卒よろしくお願い致します。

      削除

人気の投稿

Category

Algorithm (2) Android (8) ASP/aspx (1) Blogger (2) C/C++ (1) Chrome (5) CSS (9) Firefox (4) Fortran (1) Google (9) GoogleMap (2) HTML (12) IE (3) Information (4) iOS (2) iPhone/iPad/iPod (2) Java (6) JavaScript (16) jQuery (9) JSP (1) LifeRecipe (5) Linux (2) Macintosh (2) MapKit (4) Marketing (7) MySQL (3) NAMAZU (2) Objective-C (7) Other (7) Perl (1) PHP (9) Python (1) RSS/Atom (2) Ruby (1) Safari (2) SEO (11) Smarty (2) SQL (2) Tex (1) Three.js (1) Twitter (1) TwitterLog (313) UIKit (5) Unix (1) VBA/VBS (1) Windows (5) WordPress (3) Writing (5) XAMPP (1) XML (1) Yahoo (2) ZendFramework2 (14)

Archives