Developing Virtual Earth iPhone Applications with Objective-C
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.
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
Anonymous
November 13, 2008
Great work guys. I hope you get to create some cool apps.Anonymous
November 15, 2008
This is awesome, functionality of this sort should be useful to any developer using location based services (no need to exit your .app to get useful mapping anymore!). However, it is still a bit daunting for developers new to the platform -- is the image above compiled from the code snippet here? If possible, I'd love to take a look at the whole code used to build that image - it looks like many elements that would be useful to developers trying to paste this into apps are already present and perhaps the code may be useful in its entirety? If this is possible, it would be greatly appreciated!Anonymous
November 19, 2008
The comment has been removedAnonymous
March 09, 2009
I agree, this is awesome! Thank you. Quick question, the sample desktop app seems to retrieve a static image. When folks have implemented this on the iPhone did they have to calculate which tiles to fetch next, or did I miss that functionality in the VEKit? Thanks again!Anonymous
March 11, 2009
The comment has been removedAnonymous
March 16, 2009
I have tried using this framework for the iPhone but I've had trouble when creating my project. I get this error. dyld: Library not loaded: /Users/ryan/Library/Frameworks/VirtualEarthKit.framework/Versions/A/VirtualEarthKit Referenced from: /Users/ryan/Library/Application Support/iPhone Simulator/User/Applications/7E47FE9A-FFFA-4C0B-ADE2-CFE4382C6673/Hello.app/Hello Reason: image not found Any ideas someone might be able to help me with? Thanks, RyanAnonymous
May 28, 2010
Thank you very much for your article. It's great!! I have a commercial question: I need to use only geocode service, is it free?Anonymous
May 28, 2010
Thank you very much for your article, it's great! I have a commercial question: I need to use Geocode service, is it free?