iOS6以降でのMapアプリの起動方法

はじめに

ここでは、アプリ内部で使用する Map 機能(MapKit)のことは特に言及せず、アプリから外部の Map アプリ(標準 Map.app と GoogleMap.app)の起動について書きます。

現状

標準 Map.app と GoogleMap.app

iOS 6 以前までは純正の Map.app は内部では Google が使用されていました。iOS 6 からは Apple 独自に切り替えられました。2013/02/15 時点では改善をされてきてはいるものの以前の Google ベースの Map.app と比べると内容的に見劣りする状況です。そこで Google から 3rd Party アプリとして GoogleMap.app がリリースされました。このアプリは標準インストールされていたころの Map.app よりもパワーアップしていて評判の高いものになっています。

ニーズ

こうなるとやはりニーズとしては以下のようになります。

  • 使いやすい GoogleMap.app を呼び出して使いたい
  • GoogleMap.app をインストールしていないユーザー向けにも考慮して標準 Map.app も使いたい

対応方法

GoogleMap.app を開く挙動に関して

  • iOS バージョン問わず
    • GoogleMap.app がインストールされているかを canOpenURL: で確認し、GoogleMap.app で今まで同じような挙動をさせることができました。

iOS 標準 Map.app を開く挙動に関して

  • iOS 6 以前の場合
    • Map.app は内部実装が Google のものなので昔と同じ挙動(既存の実装)で Map.app を開く
  • iOS 6 以降の場合
    • 比較的単純なパラメータなら iOS 6 以前と同じでも問題はないが一部以前まで使えていたパラメータが使えないものもある
    • iOS 6 から追加された MKMapItem クラスの機能を使ってより細かいオプションを設定して iOS 標準 Map.app (Apple) を開く

コード例

iOS の標準 Map.app を開く

    /**
     MKMapItem が使えるか確認し、使える場合はそれを利用(事実上 iOS 6 以前か以降かの判定)
     使えない場合(事実上 iOS 6.x 以前)の場合は昔からの挙動
     */
    Class itemClass = [MKMapItem class];
    if (itemClass) {
        /// MKPlacemark を作る
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(self.place.latitude, self.place.longitude);
        MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:self.place.addressDictionary];
        
        /// MKPlacemark から MKMapItem を作る
        MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placemark];
        item.name = self.place.name;
        
        /// Apple Map.app に渡すオプションを準備
        /// Span を指定して Map 表示時の拡大率を調整
        MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate, 250, 250);
        MKCoordinateSpan span = region.span;
        
        /// Apple Map.app を開く
        BOOL result = [item openInMapsWithLaunchOptions:@{
                             MKLaunchOptionsMapSpanKey : [NSValue valueWithMKCoordinateSpan:span],
                           MKLaunchOptionsMapCenterKey : [NSValue valueWithMKCoordinate:coordinate]
                       }];
        
        if (result == NO) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                            message:@"Apple Map.app を開けませんでした"
                                                           delegate:nil
                                                  cancelButtonTitle:@"閉じる"
                                                  otherButtonTitles:nil];
            [alert show];
        }
    } else {
        NSString *url = [NSString stringWithFormat:@"http://maps.apple.com/?ll=%f,%f&q=%@", self.place.latitude, self.place.longitude, self.place.escapedName];
        NSURL *URL = [NSURL URLWithString:url];
        [[UIApplication sharedApplication] openURL:URL];
    }

MKMapItemopenInMapsWithLaunchOptions: を使うとある程度細かい指定を Apple Map.app に対して渡せます。openInMapsWithLaunchOptions: で span をしていすると表示された時の大きさ(ズーム具合)を調整できます。MKCoordinateSpan の値は文系の私にはよく分からない感じです。実際の利用シーン的には「任意の地点を軸に 500m くらいの範囲で表示したい」というのが多いと思います。このメートルで指定するには球体である地球を考慮してうんぬんかんぬんと私にとってはよく分からない計算をしないといけないです。簡単に済ませる方法としては MKCoordinateRegionMakeWithDistance 関数を使って得られる MKCoordinateRegion から MKCoordinateSpan を取得するのが簡単でわかりやすいです。

Google Map.app を開く

こちらを参考に URL Scheme を使って Google Map.app を開く。

    NSString *url = [NSString stringWithFormat:@"googlemaps://?q=%f,%f(%@)", self.place.latitude, self.place.longitude, self.place.escapedName];
    NSURL *URL = [NSURL URLWithString:url];
    if ([[UIApplication sharedApplication] canOpenURL:URL]) {
        [[UIApplication sharedApplication] openURL:URL];
    } else {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                        message:@"Google Map.app がインストールされていません"
                                                       delegate:nil
                                              cancelButtonTitle:@"閉じる"
                                              otherButtonTitles:nil];
        [alert show];
    }

サンプルコード

ここにサンプルコードをおいておきます。