文章原地址:http://lipengxuan.easymorse.com/?p=526
由于没有转发按钮,所以直接复制粘贴了。感觉很好,自己以后应该能用到。
iOS中百度地图API的总结
六月 19, 2012这篇文章记录了:
引入百度地图API
如何显示地图并定位
如何定位获取经纬度
如何通过定位得到城市,国家,街道等信息
如何通过搜索地理名获得坐标
如何实现公交和驾车路线搜索
如何实现当前位置到指定位置的公交和驾车路线搜索
引入百度地图API
首先,需要到http://dev.baidu.com/wiki/imap/index.php?title=iOS平台/相关下载下载全部内容,包括文档,示例代码和开发包。
然后获取自己的API KEY,具体方法按百度的官网申请就行,比较简单。
下载的文件应该有三个
把inc文件夹拖入到项目中去,引入了头文件,然后如果用真机就把Release-iphoneos里面的.a文件拖拽到项目中去,最后别忘了拖入mapapi.bundle文件,路线节点和图钉的图片来源于素材包。
此外还要引入CoreLocation.framework和QuartzCore.framework,这样引入工作就大功告成,但是要注意一点很重要的,静态库中采用ObjectC++实现,因此需要保证工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm),或者在工程属性中指定编译方式,即将XCode的Project -> Edit Active Target -> Build -> GCC4.2 – Language -> Compile Sources As设置为”Objective-C++”。
经过实践,我推荐不这么干,默认是根据文件类型来选择编译的方式,文件要是.m就用Objective-C,要是.mm就是Objective-C++,手动改变会让整个项目都用一种编译方式,很容易出错或者不兼容,比如NavigationItem实例化的时候就会出错,既然百度地图如此特立独行,那么最好的方式就是把地图相关的类改为.mm,其他的依旧,这样只有这个类会用Objective-C++编译方式。
如何显示地图并定位
要让车发动起来先得有引擎,所以在项目的根delegate类里就要通过BMKMapManager这个类来实现地图引擎的启动,具体代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOp
tions:(NSDictionary *)launchOptions {
// 要使用百度地图,请先启动BaiduMapManager
_mapManager = [[BMKMapManager alloc]init];
// 如果要关注网络及授权验证事件,请设定generalDelegate参数
BOOL ret = [_mapManager start:@"C5DCEBF3F591FCB69EE0A0B9
B1BB4C948C3FA3CC" generalDelegate:nil]; if (!ret) {
NSLog(@”manager start failed!”);
}
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:@”ViewController” bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
接下来要做的就是添加地图视图,在需要地图的类头文件里添加如下代码(这个类应该是.mm文件):
#import
#import “BMapKit.h”
@interface testViewController : UIViewController//两个协议要引入
{
BMKSearch* _search;//搜索要用到的
BMKMapView* mapView;//地图视图
IBOutlet UITextField* fromeText;
NSString
NSString *cityName;
CLLocationCoordinate2D startPt;
float localLatitude;
float localLongitude;
BOOL localJudge;
NSMutableArray *pathArray;
}
@end
一些成员后面要用到先不提,这里只是实现地图的显示和定位,然后在.mm文件里,在@implementation testViewController的前面添加这些代码#import “testViewController.h”
#define MYBUNDLE_NAME @ “mapapi.bundle”
#define MYBUNDLE_PATH [[[NSBundle mainBundle] resourcePath] stringByAppendingPathCom
ponent: MYBUNDLE_NAME] #define MYBUNDLE [NSBundle bundleWithPath: MYBUNDLE_PATH]
BOOL isRetina = FALSE;
@interface RouteAnnotation : BMKPointAnnotation
{
int _type; ///<0:起点 1:终点 2:公交 3:地铁 4:驾乘
int _degree;
}
@property (nonatomic) int type;
@property (nonatomic) int degree;
@end
@implementation RouteAnnotation
@synthesize type = _type;
@synthesize degree = _degree;
@end
@interface UIImage(InternalMethod)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees;
@end
@implementation UIImage(InternalMethod)
- (UIImage*)imageRotatedByDegrees:(CGFloat)degrees
{
CGSize rotatedSize = self.size;
if (isRetina) {
rotatedSize.width *= 2;
rotatedSize.height *= 2;
}
UIGraphicsBeginImageCont
ext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentCont
ext(); CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
CGContextRotateCTM(bitmap, degrees * M_PI / 180);
CGContextRotateCTM(bitmap, M_PI);
CGContextScaleCTM(bitmap, -1.0, 1.0);
CGContextDrawImage(bitmap, CGRectMake(-rotatedSize.width/2, -rotatedSize.height/2, rotatedSize.width, rotatedSize.height), self.CGImage);
UIImage* newImage = UIGraphicsGetImageFromCu
rrentImageContext(); UIGraphicsEndImageContex
t(); return newImage;
}
@end
- (NSString*)getMyBundlePath1:(NSString *)filename
{
NSBundle * libBundle = MYBUNDLE ;
if ( libBundle && filename ){
NSString * s=[[libBundle resourcePath ] stringByAppendingPathCom
ponent : filename]; NSLog ( @”%@” ,s);
return s;
}
return nil ;
}
下面才是真正添加地图的地方:
- (void)viewDidLoad
{
[super viewDidLoad];
mapView = [[BMKMapView alloc]initWithFrame:CGRectMake(0, 92, 320, 388)];
[self.view addSubview:mapView];
mapView.delegate = self;
[mapView setShowsUserLocation:YES];//显示定位的蓝点儿
_search = [[BMKSearch alloc]init];//search类,搜索的时候会用到
_search.delegate = self;
fromeText.text=@”新中关”;
CGSize screenSize = [[UIScreen mainScreen] currentMode].size;
if ((fabs(screenSize.width – 640.0f) < 0.1)
&& (fabs(screenSize.height – 960.0f) < 0.1))
{
isRetina = TRUE;
}
pathArray=[[NSMutableArray array] retain];
//用来记录路线信息的,以后会用到 }
然后我在ib拖拽了几个按钮,功能显而易见,编译运行就应该成功了
如何定位获取经纬度 和
这两个问题一段代码就可以解决,所以归并在一起,当添加了地图引擎和设定setShowsUserLocation:YES以后,地图已经在定位了,通过代理方法可以获得经纬度信息,并通过经纬度信息我可以获得街道城市等信息:
//百度定位获取经纬度信息
-(void)mapView:(BMKMapView *)mapView didUpdateUserLocation:(BMKUserLocation *)userLocation{
NSLog(@”!latitude!!!
%f”,userLocation.location.coordinate.latitude);//获取经度 NSLog(@”!longtitude!!!
%f”,userLocation.location.coordinate.longitude);//获取纬度 localLatitude=userLocation.location.coordinate.latitude;//把获取的地理信息记录下来
localLongitude=userLocation.location.coordinate.longitude;
CLGeocoder *Geocoder=[[CLGeocoder alloc]init];//CLGeocoder用法参加之前博客
CLGeocodeCompletionHandl
er handler = ^(NSArray *place, NSError *error) { for (CLPlacemark *placemark in place) {
cityStr=placemark.thoroughfare;
cityName=placemark.locality;
NSLog(@”city %@”,cityStr);//获取街道地址
NSLog(@”cityName %@”,cityName);//获取城市名
break;
}
};
CLLocation *loc = [[CLLocation alloc] initWithLatitude:userLocation.location.coordinate.latitude longitude:userLocation.location.coordinate.longitude];
[Geocoder reverseGeocodeLocation:loc completionHandler:handler];
}

if (!flag) {
NSLog(@”search failed”);
}
geocode第一个参数是fromeText,默认我写的是新中关,withCity是定位获得的城市,调用这个方法以后,结果会传给代理方法:- (void)onGetAddrResult:(BMKAddrInfo*)result errorCode:(int)error{
NSLog(@”11111
%f”,result.geoPt.latitude);//获得地理名“新中关”的纬度 NSLog(@”22222
%f”,result.geoPt.longitude);//获得地理名“心中关”的经度 NSLog(@”33333 %@”,result.strAddr);//街道名
NSLog(@”4444 %@”,result.addressComponent.province);//所在省份
NSLog(@”555 %@”,result.addressComponent.city);
startPt = (CLLocationCoordinate2D){0, 0};
startPt = result.geoPt;//把坐标传给startPt保存起来
}
这里可以看到好像百度地图api的结果都不是直接获得的,而是传给对应的代理方法。接下来的路线获取也一样
如何实现公交和驾车路线搜索
当textfield里面默认是新中关的时候,我的驾乘按钮代码如下:
大致就是这样的逻辑,通过geocode函数得到地名坐标,然后通过drivingSearch函数设定起始点和结束点,并调用代理方法来利用这个路线结果,下面就是代理方法-(IBAction)onClickDriveSearch
{
//清除之前的路线和标记
NSArray* array = [NSArray arrayWithArray:mapView.annotations];
[mapView removeAnnotations:array];
array = [NSArray arrayWithArray:mapView.overlays];
[mapView removeOverlays:array];
//清楚路线方案的提示信息
[pathArray removeAllObjects];
//如果是从当前位置为起始点
if (localJudge) {
BMKPlanNode* start = [[BMKPlanNode alloc]init];
startPt.latitude=localLatitude;
startPt.longitude=localLongitude;
start.pt = startPt;
start.name = cityStr;
BMKPlanNode* end = [[BMKPlanNode alloc]init];
end.name = @”三里屯”;
BOOL flag1 = [_search drivingSearch:cityName startNode:start endCity:@"北京市" endNode:end];
if (!flag1) {
NSLog(@”search failed”);
}
[start release];
[end release];
}else {
//如果从textfield获取起始点,不定位的话主要看这里
BOOL flag = [_search geocode:fromeText.text withCity:cityStr];//通过搜索textfield地名获得地名的经纬度,之前已经讲过了,并存储在变量startPt里
if (!flag) {
NSLog(@”search failed”);
}
BMKPlanNode* start = [[BMKPlanNode alloc]init];
start.pt = startPt;//起始点坐标
start.name = fromeText.text;//起始点名字
BMKPlanNode* end = [[BMKPlanNode alloc]init];
end.name = @”三里屯”;//结束点名字
BOOL flag1 = [_search drivingSearch:cityName startNode:start endCity:@"北京市" endNode:end];//这个就是驾车路线查询函数,利用了startPt存储的起始点坐标,会调用代理方法onGetDrivingRouteResult
if (!flag1) {
NSLog(@”search failed”);
}
[start release];
[end release];
}
}
//驾车的代理方法
- (void)onGetDrivingRouteResult:(BMKPlanResult*)result errorCode:(int)error
{
NSLog(@”onGetDrivingRouteResult:error:%d”, error);
if (error == BMKErrorOk) {
BMKRoutePlan* plan = (BMKRoutePlan*)[result.plans objectAtIndex:0];
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = result.startNode.pt;
item.title = @”起点”;
item.type = 0;
[mapView addAnnotation:item];
[item release];
int index = 0;
int size = [plan.routes count];
for (int i = 0; i < 1; i++) {
BMKRoute* route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
index += len;
}
}
BMKMapPoint* points = new BMKMapPoint[index];
index = 0;
for (int i = 0; i < 1; i++) {
BMKRoute* route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];
memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));
index += len;
}
size = route.steps.count;
for (int j = 0; j < size; j++) {
BMKStep* step = [route.steps objectAtIndex:j];
item = [[RouteAnnotation alloc]init];
item.coordinate = step.pt;
item.title = step.content;
item.degree = step.degree * 30;
item.type = 4;
[mapView addAnnotation:item];
[item release];
//把每一个步骤的提示信息存储到pathArray里,以后可以用这个内容实现文字导航
[pathArray addObject:step.content];
}
}
item = [[RouteAnnotation alloc]init];
item.coordinate = result.endNode.pt;
item.type = 1;
item.title = @”终点”;
[mapView addAnnotation:item];
[item release];
BMKPolyline* polyLine = [BMKPolyline polylineWithPoints:points count:index];
[mapView addOverlay:polyLine];
delete []points;
//打印pathArray,检验获取的文字导航提示信息
for (NSString *string in pathArray) {
NSLog(@”patharray2 %@”,string);
}
}
}
这样驾车的路线就应该可以获取了,编译运行可以看到路线图,同时可以从打印的数组信息得到提示信息,内容就是地图上点击节点弹出的内容
同理,公交按钮的代码:
-(IBAction)onClickBusSearch
{
//清空路线
NSArray* array = [NSArray arrayWithArray:mapView.annotations];
[mapView removeAnnotations:array];
array = [NSArray arrayWithArray:mapView.overlays];
[mapView removeOverlays:array];
[pathArray removeAllObjects];
if (localJudge) {
//开始搜索路线,transitSearch调用onGetTransitRouteResult
BMKPlanNode* start = [[BMKPlanNode alloc]init];
startPt.latitude=localLatitude;
startPt.longitude=localLongitude;
start.pt = startPt;
start.name = cityStr;
BMKPlanNode* end = [[BMKPlanNode alloc]init];
end.name = @”三里屯”;
BOOL flag1 = [_search transitSearch:cityName startNode:start endNode:end];
if (!flag1) {
NSLog(@”search failed”);
}
[start release];
[end release];
}else{
//由textfield内容搜索,调用onGetAddrResult函数,得到目标点坐标startPt
BOOL flag = [_search geocode:fromeText.text withCity:cityStr];
if (!flag) {
NSLog(@”search failed”);
}
//开始搜索路线,transitSearch调用onGetTransitRouteResult
BMKPlanNode* start = [[BMKPlanNode alloc]init];
start.pt = startPt;
start.name = fromeText.text;
BMKPlanNode* end = [[BMKPlanNode alloc]init];
end.name = @”三里屯”;
BOOL flag1 = [_search transitSearch:cityName startNode:start endNode:end];//公交路线对应的代理方法是onGetTransitRouteResult
if (!flag1) {
NSLog(@”search failed”);
}
[start release];
[end release];
}
}
- (void)onGetTransitRouteResult:(BMKPlanResult*)result errorCode:(int)error
{
NSLog(@”onGetTransitRouteResult:error:%d”, error);
if (error == BMKErrorOk) {
BMKTransitRoutePlan* plan = (BMKTransitRoutePlan*)[result.plans objectAtIndex:0];
RouteAnnotation* item = [[RouteAnnotation alloc]init];
item.coordinate = plan.startPt;
item.title = @”起点”;
item.type = 0;
[mapView addAnnotation:item];
[item release];
item = [[RouteAnnotation alloc]init];
item.coordinate = plan.endPt;
item.type = 1;
item.title = @”终点”;
[mapView addAnnotation:item];
[item release];
int size = [plan.lines count];
int index = 0;
for (int i = 0; i < size; i++) {
BMKRoute* route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
index += len;
}
BMKLine* line = [plan.lines objectAtIndex:i];
index += line.pointsCount;
if (i == size – 1) {
i++;
route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
index += len;
}
break;
}
}
BMKMapPoint* points = new BMKMapPoint[index];
index = 0;
for (int i = 0; i < size; i++) {
BMKRoute* route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];
memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));
index += len;
}
BMKLine* line = [plan.lines objectAtIndex:i];
memcpy(points + index, line.points, line.pointsCount * sizeof(BMKMapPoint));
index += line.pointsCount;
item = [[RouteAnnotation alloc]init];
item.coordinate = line.getOnStopPoiInfo.pt;
item.title = line.tip;
// NSLog(@”2222
%@”,line.tip);//上车信息,和下车信息加入数组的速度会配合,按顺序加入,不用考虑顺序问题 [pathArray addObject:line.tip];
if (line.type == 0) {
item.type = 2;
} else {
item.type = 3;
}
[mapView addAnnotation:item];
[item release];
route = [plan.routes objectAtIndex:i+1];
item = [[RouteAnnotation alloc]init];
item.coordinate = line.getOffStopPoiInfo.pt;
item.title = route.tip;
// NSLog(@”2222
%@”,line.tip); // NSLog(@”3333
%@”,item.title);//下车信息 [pathArray addObject:item.title];
if (line.type == 0) {
item.type = 2;
} else {
item.type = 3;
}
[mapView addAnnotation:item];
[item release];
if (i == size – 1) {
i++;
route = [plan.routes objectAtIndex:i];
for (int j = 0; j < route.pointsCount; j++) {
int len = [route getPointsNum:j];
BMKMapPoint* pointArray = (BMKMapPoint*)[route getPoints:j];
memcpy(points + index, pointArray, len * sizeof(BMKMapPoint));
index += len;
}
break;
}
}
BMKPolyline* polyLine = [BMKPolyline polylineWithPoints:points count:index];
[mapView addOverlay:polyLine];
delete []points;
for (NSString *string in pathArray) {
NSLog(@”bus %@”,string);
}
}
}
