Developing Virtual Earth iPhone Applications with Objective-C

image You’ve been waiting for this post. If you’ve tried doing any iPhone development with Virtual Earth you’ve probably been swearing up a storm, beating down your computer, and lost hours of sleep wondering how Loopt, Weather Central and now NMobile got their iPhone apps working. Well, Colin Cornaby from Consonance Software may just be your new best friend. He’s the one who build the NMobile application I posted to the blog yesterday - “Mobile Speed Trap Mapping with iPhone” – which uses 100% supported code from Microsoft Virtual Earth to get the road and aerial map tiles via the Virtual Earth Web Services and use them for your iPhone applications.

image

Before we begin I want to address the challenges so you have an appreciation for just how HUGE this it.

  • First, you’ll have to write against the Virtual Earth Web Service which communicates using SOAP XML, so you can’t use JavaScript. Um, ok.
  • Next, Apple forgot to include iPhone support for SOAP (oops), so you’ll have to create request packets and parse response packets to and from the service, respectively.
  • Then, with the Virtual Earth Imagery Service you only get a single quad key back (a part of the tile URL); and, with that you need put together the entire tile URL.
  • Next, you’ll have to reconstruct the Virtual Earth tile pyramid extrapolated out from the quad key returned from VEWS. The tile pyramid schema is documented in the MSDN Technical Article, “Virtual Earth Tile System.”
  • Finally, you’ll have to put it all together into a pretty iPhone-ish interface.

Wow! This sounds treacherous (but very doable). And, well, it would be treacherous but there’s always someone out there who has the drive to make stuff happen. Colin from Consonance just so happens to be that someone you’ve been looking for. Ready?

Consonance Software has created the VirtualEarthKit for ObjC / Cocoa developers. The VirtualEarthKit contains a set of APIs that you can reference for your iPhone projects to develop iPhone applications using Microsoft Virtual Earth. So, download the VirtualEarthKit (in SVN Repository | trunk | English.lproj | InfoPlist.strings), add a reference to the library from your project, then access the VirtualEarthKit APIs which automatically wrap the Virtual Earth Web Service requests and parse the responses for your application. The VirtualEarthKit supports many of the VEWS features, in addition to getting maps, including geocoding, reverse geocoding, adding pushpins and user profile elements (device type and distance unit enumerations).

Here’s a little sample to whet you Cocoa / ObjC devs on how to access VE tiles:

//
// VEImageryService.m
// MapView
//
// Created by Colin Cornaby on 10/12/08.
// Copyright 2008 __Consonance Software__. All rights reserved.
//

#import "VEImageryService.h"
#import "VEImageryResult.h"
#import "VEGetMapURIResponse.h"
#import "VEServicePrivate.h"

@implementation VEImageryService

-(VEServiceResponse *)getImageryMetadata:(VEImageryMetadataRequest *)request
{
xmlNodePtr xmlRequest;
[request serializeToXMLQuery:&xmlRequest];
NSString *server = @"https://dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc";
    if(self.realm==kVEStagingRealm)
server = @"https://staging.dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc";
    xmlNodePtr result = [super sendVERequestWithBody:xmlRequest action:@"https://dev.virtualearth.net/webservices/v1/geocode/contracts/IImageryService/GetImageryMetadata" server:[NSURL URLWithString:server] error:nil];
xmlNodePtr body = nil;
for(body = result->children; body; body = body->next)
{
if(!strcmp((char *)body->name, "GetImageryMetadataResult"))
break;
}
VEServiceResponse *response = nil;
if(body)
response = [[VEServiceResponse alloc] initWithXMLNode:body resultClass:[VEImageryResult class]];
return response;
}

-(VEGetMapURIResponse *)getMapURI:(VEGetMapURIRequest *)request
{
xmlNodePtr xmlRequest;
[request serializeToXMLQuery:&xmlRequest];
NSString *server = @"https://dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc";
    if(self.realm==kVEStagingRealm)
server = @"https://staging.dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc";
    xmlNodePtr result = [super sendVERequestWithBody:xmlRequest action:@"https://dev.virtualearth.net/webservices/v1/imagery/contracts/IImageryService/GetMapUri" server:[NSURL URLWithString:server] error:nil];
xmlNodePtr body = nil;
for(body = result->children; body; body = body->next)
{
if(!strcmp((char *)body->name, "GetMapUriResult"))
break;
}
VEGetMapURIResponse *response = nil;
if(body)
response = [[VEGetMapURIResponse alloc] initWithXMLNode:body resultClass:[VEImageryResult class]];
return response;
}

@end

A little about the VirtualEarthKit from the Consonance web site:

VirtualEarthKit is a framework to allow Cocoa developers to communicate with Microsoft Virtual Earth . Microsoft Virtual Earth provides a wide range of services, including geocoding, reverse geocoding, map imagery, route guidance, and business lookup.

Dependencies for VirtualEarthKit have also been minimized in order to keep VirtualEarthKit portable for different OS X platforms. VirtualEarthKit uses LibXML for constructing all SOAP requests. To facilitate clean integration with Cocoa and the iPhone SDK, VirtualEarthKit requires the CoreLocation framework. Fortunately, VirtualEarthKit for Mac OS X uses Philippe Casgrain's re-implementation of CoreLocation for Mac OS X . Integration with CoreLocation allows developers for the iPhone platform to use VirtualEarthKit cleanly with the phone's GPS implementation.

Okay, so this is just game changing for mobile mapping. iPhone has completely taken off and I receive inquiries every day for iPhone developer support and licensing. Well, let’s get developing! Can adding maps to your iPhone app get any easier now? If you still need a license, contact me so we can get that out of the way. Download the VirtualEarthKit now and get cranking!

CP