准备工作:
一、去百度开发平台注册,并且获得密钥,具体步骤百度开发平台详细说明,并且下载相应的BaiduMapAPI.framework。
二、引入BaiduMapAPI.framework
将所需的BaiduMapAPI.framework拷贝到工程所在文件夹下。在 TARGETS->Build Phases-> Link Binary With Libaries中点击“+”按钮,在弹出的窗口中点击“Add Other”按钮,选择BaiduMapAPI.framework文件添加到工程中。
三、引入所需的系统库
百度地图SDK中提供了定位功能和动画效果,v2.0.0版本开始使用OpenGL渲染,因此您需要在您的Xcode工程中引入CoreLocation.framework和QuartzCore.framework、OpenGLES.framework、SystemConfiguration.framework、CoreGraphics.framework、Security.framework。添加方式:在Xcode的Project -> Active Target ->Build Phases ->Link Binary With Libraries,添加这几个framework即可。
四、环境配置
在TARGETS->Build Settings->Other Linker Flags 中添加-ObjC。
五、引入mapapi.bundle资源文件
如果使用了基础地图功能,需要添加该资源,否则地图不能正常显示
方法:选中工程名,在右键菜单中选择Add Files to “工程名”…,从BaiduMapAPI.framework||Resources文件中选择mapapi.bundle文件,并勾选“Copy items if needed”复选框,单击“Add”按钮,将资源文件添加到工程中。
六、引入头文件
在使用SDK的类引入头文件:
#import <BaiduMapAPI/BMapKit.h>//引入所有的头文件
#import <BaiduMapAPI/BMKMapView.h>//只引入所需的单个头文件
七、在info.plist文件中添加
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescriptionBundle display name等字段。因为百度提供的类中使用了
- (void)requestWhenInUseAuthorization
- (void)requestAlwaysAuthorization,方法。具体原因详见 iOS经典讲解之地图定位请求位置信息时出现的问题
如图所示:
准备工作完成后,下面是具体示例代码:
// // ViewController.m // BaiDuMapSample #import "ViewController.h" #import <BaiduMapAPI/BMapKit.h> @interface ViewController () <BMKGeneralDelegate, BMKMapViewDelegate, BMKLocationServiceDelegate, BMKGeoCodeSearchDelegate, BMKRouteSearchDelegate> // 开始城市 @property (nonatomic, strong) UITextField *startCityTF; // 开始地址 @property (nonatomic, strong) UITextField *startAddressTF; // 终点城市 @property (nonatomic,strong) UITextField *endCityTF; // 终点地址 @property (nonatomic, strong) UITextField *endAddressTF; // 添加地图 @property (nonatomic, strong) BMKMapView *mapView; // 定位服务对象(专门用于定位) @property (nonatomic, strong) BMKLocationService *locationService; //声明地理位置搜索对象(负责地理编码) @property (nonatomic, strong) BMKGeoCodeSearch *geocoder; // 声明路线搜索服务对象 @property (nonatomic, strong) BMKRouteSearch *routeSearch; // 开始路线检索节点 @property (nonatomic, strong) BMKPlanNode *statNode; // 目标路线检索节点 @property (nonatomic, strong) BMKPlanNode *endNode; @end @implementation ViewController -(void)dealloc { self.geocoder.delegate = nil; self.locationService.delegate = nil; self.mapView.delegate = nil; self.routeSearch.delegate = nil; } - (void)viewDidLoad { [super viewDidLoad]; // 因为百度SDK的引擎是使用C++代码写成,所以我们必须保证我们的工程中至少有一个文件是.mm后缀 // 创建百度地图主引擎类(使用百度地图功能之前必须启动引擎) BMKMapManager *manager = [[BMKMapManager alloc] init]; // 启动引擎 // foIpeFfSSd5SGy2fKxLmD0M8百度开发者平台注册的密钥 // 注意要把NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription 字段添加到plist文件中 [manager start:@"foIpeFfSSd5SGy2fKxLmD0M8" generalDelegate:self]; // 设置内边距 if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) { self.edgesForExtendedLayout = UIRectEdgeNone; } // 搭建UI [self addSubViews]; // 创建定位服务对象 self.locationService = [[BMKLocationService alloc] init]; // 设置定位服务对象的代理 self.locationService.delegate = self; // 设置再次定位的最小距离 [BMKLocationService setLocationDistanceFilter:10]; // 创建地理位置搜索对象 self.geocoder = [[BMKGeoCodeSearch alloc] init]; // 设置代理 self.geocoder.delegate = self; // 创建routeSearch服务对象 self.routeSearch = [[BMKRouteSearch alloc] init]; // 设置代理 self.routeSearch.delegate = self; } /** * 搭建UI方法 */ - (void)addSubViews { // 设置barButtonItem UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"开始定位" style:(UIBarButtonItemStylePlain) target:self action:@selector(leftAction:)]; self.navigationItem.leftBarButtonItem = leftButton; UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:@"关闭定位" style:(UIBarButtonItemStylePlain) target:self action:@selector(rightAction:)]; self.navigationItem.rightBarButtonItem = rightButton; // 设置textField // 开始城市 self.startCityTF = [[UITextField alloc] initWithFrame:CGRectMake(20, 30, 100, 30)]; self.startCityTF.text = @"开始城市"; [self.view addSubview:self.startCityTF]; // 开始地址 self.startAddressTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.startCityTF.frame) + 30, CGRectGetMinY(self.startCityTF.frame), CGRectGetWidth(self.startCityTF.frame), CGRectGetHeight(self.startCityTF.frame))]; self.startAddressTF.text = @"开始地址"; [self.view addSubview:self.startAddressTF]; // 目的城市 self.endCityTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.startCityTF.frame), CGRectGetMaxY(self.startCityTF.frame) + 10, CGRectGetWidth(self.startCityTF.frame), CGRectGetHeight(self.startCityTF.frame))]; self.endCityTF.text = @"目的城市"; [self.view addSubview:self.endCityTF]; // 目的地址 self.endAddressTF = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.endCityTF.frame) + 30, CGRectGetMinY(self.endCityTF.frame), CGRectGetWidth(self.endCityTF.frame), CGRectGetHeight(self.endCityTF.frame))]; self.endAddressTF.text = @"目的地址"; [self.view addSubview:self.endAddressTF];; // 添加线路规划按钮 UIButton *roadButton = [UIButton buttonWithType:UIButtonTypeCustom]; roadButton.frame = CGRectMake(CGRectGetMaxX(self.startAddressTF.frame) + 10, CGRectGetMaxY(self.startAddressTF.frame), 100, 30); [roadButton setTitle:@"线路规划" forState:UIControlStateNormal]; [roadButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; // 设置点击方法 [roadButton addTarget:self action:@selector(roadAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:roadButton]; // 添加地图 self.mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(self.endAddressTF.frame) + 5, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - CGRectGetMaxY(self.endAddressTF.frame) - 5)]; // 设置代理 self.mapView.delegate = self; [self.view addSubview:self.mapView]; } // 开始定位方法 - (void)leftAction:(UIBarButtonItem *)leftButton { // 开启定位服务 [self.locationService startUserLocationService]; // 在地图上显示用户位置 self.mapView.showsUserLocation = YES; } // 关闭定位方法 - (void)rightAction:(UIBarButtonItem *)rightButton { // 关闭定位服务 [self.locationService stopUserLocationService]; // 设置地图不显示用户位置 self.mapView.showsUserLocation = NO; // 删除我们添加的标注对象 [self.mapView removeAnnotation:self.mapView.annotations.lastObject]; } // 线路规划点击方法 - (void)roadAction:(UIButton *)button { // 完成正向地理编码 // 1、创建正向地理编码选项对象 BMKGeoCodeSearchOption *geocoderOption = [[BMKGeoCodeSearchOption alloc] init]; // 2、给进行正向地理位置编码的位置赋值 geocoderOption.city = self.startCityTF.text; geocoderOption.address = self.startAddressTF.text; // 执行地理位置编码 [self.geocoder geoCode:geocoderOption]; } #pragma mark - BMKLocationService代理方法 -(void)willStartLocatingUser { NSLog(@"开始定位"); } -(void)didFailToLocateUserWithError:(NSError *)error { NSLog(@"定位失败%@", error); } /** * 定位成功,再次定位的方法(定位成功触发) */ -(void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation { // 完成地理反编码 // 1、创建反向地理编码选项对象 BMKReverseGeoCodeOption *reverseOption = [[BMKReverseGeoCodeOption alloc] init]; // 2、给反向地理编码选项对象坐标点赋值 reverseOption.reverseGeoPoint = userLocation.location.coordinate; // 3、执行反向地理编码操作 [self.geocoder reverseGeoCode:reverseOption]; } #pragma mark - BMKGeoCodeSearch代理方法 //反编码代理方法执行 -(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error { // 定义大头针标注 BMKPointAnnotation *annotation = [[BMKPointAnnotation alloc] init]; // 设置标注位置坐标 annotation.coordinate = result.location; annotation.title = result.address; annotation.subtitle = [NSString stringWithFormat:@"%f-%f", result.location.latitude, result.location.longitude]; // 添加到地图里 [self.mapView addAnnotation:annotation]; // 使地图显示该位置 [self.mapView setCenterCoordinate:result.location animated:YES]; } // 正向编码代理方法 -(void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error { // if ([result.address isEqualToString:self.startAddressTF.text]) { // 当前编码的对象是开始节点 self.statNode = [[BMKPlanNode alloc] init]; //给节点的坐标位置赋值 _statNode.pt = result.location; // 发起对目标节点的地理编码 // 1、创建正向地理编码选项对象 BMKGeoCodeSearchOption *geoOption = [[BMKGeoCodeSearchOption alloc] init]; geoOption.city = self.endCityTF.text; geoOption.address = self.endAddressTF.text; // 执行编码 [self.geocoder geoCode:geoOption]; self.endNode = nil; } else { self.endNode = [[BMKPlanNode alloc] init]; _endNode.pt = result.location; } if (_statNode != nil && _endNode != nil) { // 开始执行路线规划 //1、创建驾车路线规划 这里以自驾模式为例 还可以是公交路线或者步行路线规划 BMKDrivingRoutePlanOption *drivingRouteOption = [[BMKDrivingRoutePlanOption alloc] init]; // 2、指定开始节点和目标节点 drivingRouteOption.from = _statNode; drivingRouteOption.to = _endNode; // 3、让路线搜索服务对象搜索路线 开始执行代理方法 [self.routeSearch drivingSearch:drivingRouteOption]; } } // 获取到自驾路线回调 - (void)onGetDrivingRouteResult:(BMKRouteSearch *)searcher result:(BMKDrivingRouteResult *)result errorCode:(BMKSearchErrorCode)error { // 删除原来的覆盖物 NSArray *array = [NSArray arrayWithArray:self.mapView.annotations]; [self.mapView removeAnnotations:array]; // 删除overlays(原来的痕迹) array = [NSArray arrayWithArray:self.mapView.overlays]; [self.mapView removeOverlays:array]; // if (error == BMK_SEARCH_NO_ERROR) { // 选取获取到所有路线中的一条路线 BMKDrivingRouteLine *plan = [result.routes objectAtIndex:0]; // 计算路线方案中路段的数目 NSUInteger size = [plan.steps count]; // 声明一个整型变量用来计算所有轨迹点的总数 int planPointCounts = 0; for (int i = 0; i < size; i++) { // 获取路线中的路段 BMKDrivingStep *step = plan.steps[i]; if (i == 0) { // 地图显示经纬区域 [self.mapView setRegion:BMKCoordinateRegionMake(step.entrace.location, BMKCoordinateSpanMake(0.001, 0.001))]; } // 累计轨迹点 planPointCounts += step.pointsCount; } // 声明一个结构体数组来保存所有的轨迹点(每一个轨迹点都是一个结构体) // 轨迹点结构体的名字为BMKMapPoint C++写法,必须写在.mm文件中 BMKMapPoint *tempPoints = new BMKMapPoint[planPointCounts]; // 声明一个有planPointCounts个元素的数组,数组名为tempPoints int i = 0; for (int j = 0; j < size; j++) { BMKDrivingStep *transitStep = [plan.steps objectAtIndex:j]; int k = 0; for (k = 0; k < transitStep.pointsCount; k++) { // 获取每个轨迹点的x y放入数组中 tempPoints[i].x = transitStep.points[k].x; tempPoints[i].y = transitStep.points[k].y; i++; } } // 通过轨迹点构造BMKPolyline(折线) BMKPolyline *polyline = [BMKPolyline polylineWithPoints:tempPoints count:planPointCounts]; // 添加到mapView上 // 想要在地图上显示轨迹 只能先添加overlay对象(类似大头针标注)添加好之后,地图就会根据设置的overlay显示出轨迹 [self.mapView addOverlay:polyline]; } } #pragma mark - mapView代理方法 -(BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay { if ([overlay isKindOfClass:[BMKPolyline class]]) { // 创建要显示的折线 BMKPolylineView *view = [[BMKPolylineView alloc] initWithOverlay:overlay]; // 设置该线条的填充颜色 view.fillColor = [UIColor redColor]; // 设置线条颜色 view.strokeColor = [UIColor redColor]; // 设置线条宽度 view.lineWidth = 3; return view; } return nil; } @end
注:静态库中采用ObjectC++实现,因此需要您保证您工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm)。
代码中包含C++语法因此必须写在.mm文件中。例如BMKMapPoint *tempPoints = new BMKMapPoint[planPointCounts];,因此上面代码一定要写在.mm文件中。