iOSでGoogleMaps及び地図アプリを利用した経路検索

アプリからGoogle MapsApple標準の地図アプリを起動し、経路を表示させる方法。

GoogleMapの起動方法

以下のサイトに記載されているURLとパラメータでGoogle Mapsが起動できる。Google Mapsがインストールされていない場合は、後述の方法で、SafariでGoogleMapsを開くことができる。

Google Maps URL Scheme - Google Maps SDK for iOS — Google Developers

//GoogleMapsがインストールされている場合
if ([[UIApplication sharedApplication] canOpenURL:
     [NSURL URLWithString:@"comgooglemaps://"]]) {
  //Google Mapsの起動
  [[UIApplication sharedApplication] openURL:
   [NSURL URLWithString:@"comgooglemaps://?saddr=40.765819,-73.975866&daddr=14&directionsmode=transit"]];

//インストールされていない場合
} else {
  NSLog(@"Can't use comgooglemaps://");
}

saddrは出発地のパラメータで、緯度(latitude),経度(longitude)での指定と東京都新宿区西新宿二丁目8番1号のような住所指定が可能である。但し、住所で指定する場合は、URLEncodeが必要である。何も指定しない場合は、現在地が使われるとあるが、上手く動作しない場合もある?

daddrは目的地のパラメータで、saddrと同じ指定が可能。

directionsmodeは、経路の手段で、公共交通機関を使う場合はtransitを指定する。他に、車、自転車、徒歩の指定が、それぞれdriving, bicycling, walkingで指定可能である。

Safariで起動する場合は、URLを変更してopenURLをするだけで良い。以下はGoogleMapsがインストールされていない場合に、SafariGoogle Mapsを開くように、上記のプログラムを改良したものである。

//GoogleMapsがインストールされている場合
if ([[UIApplication sharedApplication] canOpenURL:
  [NSURL URLWithString:@"comgooglemaps://"]]) {
  //Google Mapsの起動
  [[UIApplication sharedApplication] openURL:
   [NSURL URLWithString:@"comgooglemaps://?saddr=40.765819,-73.975866&daddr=14&directionsmode=transit"]];

//インストールされていない場合
} else {
  //Safariで起動
  [[UIApplication sharedApplication] openURL:
   [NSURL URLWithString:@"https://maps.google.com/maps?saddr=40.765819,-73.975866&daddr=14&directionsmode=transit"]];
}

最後にまとめとして、目的地と出発地を指定して地図アプリを起動するメソッドを載せておく。

/*
source:出発地。@"住所" or @"緯度(latitude),経度(longitude)"を指定。
destination:目的地。@"住所" or @"緯度(latitude),経度(longitude)"を指定。
@""やnilの場合は、現在地が指定されるが上手く動作しない場合もある。

directionsMode:@"transit" or @"driving" or @"bicycling" or @"walking"を指定。
*/
- (void)launchMapApplicatoinToGetDirections:(NSString *)source
                                destination:(NSString *)destination
                             directionsMode:(NSString *)directionsMode
{
    NSString *encodedSource = @"";
    NSString *encodedDestination = @"";
    if ([destination length] > 0) {
        encodedDestination = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                                   (__bridge CFStringRef)destination,
                                                                                                   NULL,
                                                                                                   (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                                                                                   kCFStringEncodingUTF8));
    }
    if ([source length] >0 ) {
        encodedSource = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                              (__bridge CFStringRef)source,
                                                                                              NULL,
                                                                                              (CFStringRef)@"!*'();:@&=+$,/?%#[]",
                                                                                              kCFStringEncodingUTF8));
    }
    
    NSString *url = [NSString stringWithFormat:@"comgooglemaps://?saddr=%@&daddr=%@&directionsmode=%@",
                     encodedSource, encodedDestination, directionsMode];
    NSURL *URL = [NSURL URLWithString:url];
    
    if ([[UIApplication sharedApplication] canOpenURL:URL]) {
        [[UIApplication sharedApplication] openURL:URL];
    } else {
        
        NSString *httpUrl = [NSString stringWithFormat:@"https://maps.google.com/maps?saddr=%@&daddr=%@&directionsmode=%@",
                             encodedSource, encodedDestination, directionsMode];
        NSURL *httpURL = [NSURL URLWithString:httpUrl];
        [[UIApplication sharedApplication] openURL:httpURL];
    }
}

Appleの地図アプリの起動

Appleの地図アプリでは、(少なくともiOS7までは)経路は車ないし徒歩での経路しか表示できないが、一応起動方法をかく。

iOS5以前の場合はこの方法では起動しないので注意。

sourceCoordinate及びdestinationCoordinateを指定すれば動作する。sourcePlace及びdestinationPlaceは出発地と目的地の名称で、ピンに付与される。

  //出発地の緯度、経度
    CLLocationCoordinate2D sourceCoordinate =  CLLocationCoordinate2DMake(35.69384, 139.703549);
    //目的地の緯度、経度
    CLLocationCoordinate2D destinationCoordinate = CLLocationCoordinate2DMake(35.689185, 139.691648);
    //出発地の名称
    NSString *sourcePlace = @"新宿";
    //目的地の名称
    NSString *destinationPlace = @"東京都新宿区西新宿二丁目8番1号";
    Class itemClass = [MKMapItem class];
    //iOS5以前は実行されない
    if (itemClass) {
        //出発地の作成
        MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:sourceCoordinate
                                                                  addressDictionary:nil];
        MKMapItem *source = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark];
        source.name = sourcePlace;
        
        //目的地の作成
        MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoordinate
                                                       addressDictionary:nil];
        MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark:destinationPlacemark];
        destination.name = destinationPlace;
        
        /// option
        NSDictionary *options = @{
                                  //車の場合はMKLaunchOptionsDirectionsModeDriving
                                  MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeWalking
                                  };
        
        NSArray *array = [NSArray arrayWithObjects:source, destination, nil];
        //開く
        BOOL result = [MKMapItem openMapsWithItems:array
                                     launchOptions:options];
        
        if (result == NO) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                            message:@"Apple Map.app を開けませんでした"
                                                           delegate:nil
                                                  cancelButtonTitle:@"閉じる"
                                                  otherButtonTitles:nil];
            [alert show];
        }
    }

現在位置の取得

現在地の取得は、CLLocationManagerクラスを使う。startUpdatingLocationで位置情報の取得を開始する。

位置情報は、delegateで指定した- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locationsがcallbackとして呼ばれるので、位置情報取得後の処理はそちらに書く。このメソッドは、位置情報が更新される度に呼ばれるので、一度で良い場合は、stopUpdatingLocationで更新を停止させる。

locationsには、- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locationsが呼ばれるまでに取得された位置情報がCLLocationクラスで記録される。最後に取得された位置情報は、[locations lastObject]で取得される。

- (void)someMethod{

    if (self.locationManager == nil) {
        self.locationManager = [[CLLocationManager alloc] init];
    }
    self.locationManager.distanceFilter = kCLDistanceFilterNone;
    //精度
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    //CLLocationManagerDelegate
    self.locationManager = self;
    [self.locationManager startUpdatingLocation];
}

/*
callbackとして呼ばれる。
manager:startUpdatingLocationを実行したCLLocationManager
locations:以前の更新から現在までに新しく取得された位置情報。1個から複数個
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
  //位置情報の更新をやめる
  [self.locationManager stopUpdatingLocation];

  //現在位置
  CLLocation *location = [locations lastObject];

  /*
  locationを使った処理
  */
}

CLLocationsManagerは、クラスのインスタンス変数として保持した方が良い。startUpdatingLocationメソッドは、GPSに位置情報の取得を依頼するだけですぐ処理が終了するので、someMethod内で宣言している変数は破棄される。

参考サイト

iOS6以降でのMapアプリの起動方法 - griffin-stewieのブログ

CLLocationManager その1 位置情報取得