iOS·采用第三方(百度地图SDK)实现定位等功能开发

1.申请密钥

首先,申请一个baidu账号,接着进入新建密钥入口申请成为baidu地图开发者,填写相关开发者信息和短信验证码。接下来点击创建应用,如官方文档新建密钥文档指南里面的截图所示,注意正确勾选有关项。如果你想要实名认证,点击页面右上角的实名状态,下面是该页面的截图。

Paste_Image.png
  • 创建应用时,注意勾选正确的应用类型

默认是服务端类型,如果没有勾选iOS SDK类型,就不能根据你自己工程BundleID(即百度地图所谓的安全码)设置Key的选项了。如图所示,创建应用没有勾选iOS SDK,当点击设置,进去后根本没有定制化的设置选项。

Paste_Image.png
  • 创建应用时,注意正确填写iOS SDK安全码

在Xcode里面,找到自己工程的安全码,即工程的Bundle Identifier,如下图所示,应该是类似com.baidu.mapdemo等格式的字符串。

Paste_Image.png

2.工程配置

2.1 CocoaPods方法

这种方法,优点是简单,不需要再对工程进行额外的配置。缺点是,没有自己根据需要选择性的加载百度开发包的余地,把整个SDK都导进来了,不管你有没有可能会用到这些包。

打开终端,输入类似下面的命令,cd到你自己工程的目录下

 $ cd /Users/ChenMan/iOSLAB/myMapDemo/

1.创建Podfile:

touch Podfile

2.编辑Podfile内容如下:

pod 'BaiduMapKit' #百度地图SDK

3.在Podfile所在的文件夹下输入命令:

pod install (这个可能比较慢,请耐心等待……)

成功以后,会出现如下记录:

Analyzing dependencies
 
Downloading dependencies
 
Installing BaiduMapKit (2.9.1)
 
Generating Pods project
 
Integrating client project
 
[!] Please close any current Xcode sessions and use `***.xcworkspace` for this project from now on.
Sending stats

恭喜你已成功导入百度地图iOS SDK,现在就可以打开xcworkspace文件,在你的项目中使用百度地图SDK了

2.2 手动拷贝依赖库方法

这种方法的优点是,可以选择性的导入所需开发包,尽可能减小APP工程体积。缺点是步骤相对繁琐,总的来说分两部分工作,一是,选择性拷贝所需开发包到工程目录下并建立引用关系(手动拖拽,并勾选copy if needed,保证所需包被复制到工程目录下,而不是仅仅是引用关系),二是,在工程的TARGETS->Build Phases-> Link Binary With Libaries里面,添加前面添加的开发包。

接下来引用百度地图的文档说明,并作了适当改编:

  • 第一步、根据需要导入 .framework包

百度地图 iOS SDK 采用分包的形式提供 .framework包,请广大开发者使用时确保各分包的版本保持一致。其中BaiduMapAPI_Base.framework为基础包,使用SDK任何功能都需导入,其他分包可按需导入

全部分包和自定义分包的下载地址为 http://lbsyun.baidu.com/index.php?title=iossdk/sdkiosdev-download,如下图所示:

这里我选择下载的是自定义分包,我只需要单纯的定位功能

注: 静态库中采用Objective-C++实现,因此需要您保证您工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm,比如AppDelegate.mm),或者在工程属性中指定编译方式,即在Xcode的Project -> Edit Active Target -> Build Setting 中找到 Compile Sources As,并将其设置为"Objective-C++"

  • 第二步、引入所需的系统库

百度地图SDK中提供了定位功能和动画效果,v2.0.0版本开始使用OpenGL渲染,因此您需要在您的Xcode工程中引入CoreLocation.framework和QuartzCore.framework、OpenGLES.framework、SystemConfiguration.framework、CoreGraphics.framework、Security.framework、libsqlite3.0.tbd(xcode7以前为 libsqlite3.0.dylib)、CoreTelephony.framework 、libstdc++.6.0.9.tbd(xcode7以前为libstdc++.6.0.9.dylib)

(注:粗体标识的系统库为v2.9.0新增的系统库,使用v2.9.0及以上版本的地图SDK,务必增加导入这3个系统库。)

添加方式: 在Xcode的Project -> Active Target ->Build Phases ->Link Binary With Libraries,添加这几个系统库即可。

  • 第三步、引入所需的第三方openssl库:

添加支持HTTPS所需的penssl静态库:libssl.a和libcrypto.a(SDK打好的包存放于thirdlib目录下)

例如,我需要的是单纯的定位功能,选择自定义分包下载后,会看到如下图文件目录结构,静态库:libssl.a和libcrypto.a就在thirdlibs文件夹下面。

thirdlibs文件夹

添加方法: 在 TARGETS->Build Phases-> Link Binary With Libaries中点击“+”按钮,在弹出的窗口中点击“Add Other”按钮,选择libssl.a和libcrypto.a添加到工程中

  • 第四步、环境配置

在TARGETS->Build Settings->Other Linker Flags 中添加-ObjC。

  • 第五步、引入mapapi.bundle资源文件

如果使用了基础地图功能,需要添加该资源,否则地图不能正常显示mapapi.bundle中存储了定位、默认大头针标注View及路线关键点的资源图片,还存储了矢量地图绘制必需的资源文件。如果您不需要使用内置的图片显示功能,则可以删除bundle文件中的image文件夹。您也可以根据具体需求任意替换或删除该bundle中image文件夹的图片文件。

方法:选中工程名,在右键菜单中选择Add Files to “工程名”…,从BaiduMapAPI_Map.framework||Resources文件中选择mapapi.bundle文件,并勾选“Copy items if needed”复选框,单击“Add”按钮,将资源文件添加到工程中。

  • 第六步、引入头文件

在使用SDK的类 按需 引入下边的头文件:

#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
 
#import <BaiduMapAPI_Map/BMKMapComponent.h>//引入地图功能所有的头文件
 
#import <BaiduMapAPI_Search/BMKSearchComponent.h>//引入检索功能所有的头文件
 
#import <BaiduMapAPI_Cloud/BMKCloudSearchComponent.h>//引入云检索功能所有的头文件
 
#import <BaiduMapAPI_Location/BMKLocationComponent.h>//引入定位功能所有的头文件
 
#import <BaiduMapAPI_Utils/BMKUtilsComponent.h>//引入计算工具所有的头文件
 
#import <BaiduMapAPI_Radar/BMKRadarComponent.h>//引入周边雷达功能所有的头文件
 
#import <BaiduMapAPI_Map/BMKMapView.h>//只引入所需的单个头文件

具体的应用位置,一般是两个地方,一个是AppDelegate文件,一个是调用定位功能的ViewController文件。接下来两节会讲到怎么用。

3.AppDelegate文件配置

假设我现在的需求是,APP需要定位当前所在位置经纬度,并根据经纬度反地理编码,得到所在地址,包括省市区,街道等详细地址信息。

并假设,已经申请得到了一个密钥如下(拷这个没用,自己根据BundleID申请吧):

B266f735e43ab207ec152deff44fec8b

首先,需要在AppDelegate.mm文件导入所需头文件:

//百度地图
#define BMK_KEY @"B266f735e43ab207ec152deff44fec8b"//百度地图的key
#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件

其次,声明一个BMKMapManager属性:

@interface AppDelegate ()

@property (nonatomic, strong) BMKMapManager *mapManager;

@end

然后,在AppDelegate的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}代理方法中初始化百度地图,代码如下:

    //百度地图
    _mapManager = [BMKMapManager new];
    BOOL ret = [_mapManager start:BMK_KEY generalDelegate:nil];
    if (!ret)
    {
        NSLog(@"百度地图启动失败");
    }
    else
    {
        NSLog(@"百度地图启动成功");
    }

这样,当APP启动就会启动百度地图相关模块,以便后续VC调用。

4.用到百度定位功能所在VC的配置

首先,导入相关头文件,及key的宏定义

//百度地图
#import <BaiduMapAPI_Base/BMKBaseComponent.h>//引入base相关所有的头文件
#import <BaiduMapAPI_Location/BMKLocationComponent.h>//引入定位功能所有的头文件
#import <BaiduMapAPI_Search/BMKSearchComponent.h>//引入检索功能所有的头文件
#define BMK_KEY @"B266f735e43ab207ec152deff44fec8b"//百度地图的key

其次,声明该VC服从百度相关模块的代理如下,其它代理自选:

//百度地图·代理
@interface TestViewController ()<UITableViewDataSource, UITableViewDelegate,CLLocationManagerDelegate,BMKGeneralDelegate,BMKLocationServiceDelegate,BMKGeoCodeSearchDelegate>
{
}

然后,声明相关属性如下:

//百度地图
@property (nonatomic, strong)BMKLocationService *locService;
@property (nonatomic, strong)BMKGeoCodeSearch *geocodesearch;
@property BOOL isGeoSearch;

接着,在VC的- (void)viewDidLoad {}方法里面,对相关模块进行初始化操作。

    //百度地图
    //启动LocationService
    _locService = [[BMKLocationService alloc]init];//定位功能的初始化
    _locService.delegate = self;//设置代理位self
    [_locService startUserLocationService];//启动定位服务

最后,实现百度地图相关代理方法,并进行自定义的一些操作。

#pragma mark - BMK_LocationDelegate 百度地图
/**
 *定位失败后,会调用此函数
 *@param error 错误号
 */
- (void)didFailToLocateUserWithError:(NSError *)error
{
    NSLog(@"地图定位失败======%@",error);
}

//处理位置坐标更新
- (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation
{
    NSLog(@"didUpdateUserLocation lat %f,long %f",userLocation.location.coordinate.latitude,
          userLocation.location.coordinate.longitude);
    
    //从manager获取左边
    CLLocationCoordinate2D coordinate = userLocation.location.coordinate;//位置坐标
    //存储经纬度
    [self.userLocationInfoModel SaveLocationCoordinate2D:coordinate];
    
    if ((userLocation.location.coordinate.latitude != 0 || userLocation.location.coordinate.longitude != 0))
    {
        
        
        //发送反编码请求
        //[self sendBMKReverseGeoCodeOptionRequest];
        
        NSString *latitude = [NSString stringWithFormat:@"%f",userLocation.location.coordinate.latitude];
        NSString *longitude = [NSString stringWithFormat:@"%f",userLocation.location.coordinate.longitude];
        [self reverseGeoCodeWithLatitude:latitude withLongitude:longitude];
        
    }else{
        NSLog(@"位置为空");
    }
    
    //关闭坐标更新
    [self.locService stopUserLocationService];
}

//地图定位
- (BMKLocationService *)locService
{
    if (!_locService)
    {
        _locService = [[BMKLocationService alloc] init];
        _locService.delegate = self;
    }
    return _locService;
}

//检索对象
- (BMKGeoCodeSearch *)geocodesearch
{
    if (!_geocodesearch)
    {
        _geocodesearch = [[BMKGeoCodeSearch alloc] init];
        _geocodesearch.delegate = self;
    }
    return _geocodesearch;
}

#pragma mark ----反向地理编码
- (void)reverseGeoCodeWithLatitude:(NSString *)latitude withLongitude:(NSString *)longitude
{
    
    //发起反向地理编码检索
    
    CLLocationCoordinate2D coor;
    coor.latitude = [latitude doubleValue];
    coor.longitude = [longitude doubleValue];
    
    BMKReverseGeoCodeOption *reverseGeocodeSearchOption = [[BMKReverseGeoCodeOption alloc] init];
    reverseGeocodeSearchOption.reverseGeoPoint = coor;
    BOOL flag = [self.geocodesearch reverseGeoCode:reverseGeocodeSearchOption];;
    if (flag)
    {
        NSLog(@"反地理编码成功");//可注释
    }
    else
    {
        NSLog(@"反地理编码失败");//可注释
    }
}

//发送反编码请求
- (void)sendBMKReverseGeoCodeOptionRequest{
    
    self.isGeoSearch = false;
    CLLocationCoordinate2D pt = (CLLocationCoordinate2D){0, 0};//初始化
    if (_locService.userLocation.location.coordinate.longitude!= 0
        && _locService.userLocation.location.coordinate.latitude!= 0) {
        //如果还没有给pt赋值,那就将当前的经纬度赋值给pt
        pt = (CLLocationCoordinate2D){_locService.userLocation.location.coordinate.latitude,
            _locService.userLocation.location.coordinate.longitude};
    }
    
    BMKReverseGeoCodeOption *reverseGeocodeSearchOption = [[BMKReverseGeoCodeOption alloc]init];//初始化反编码请求
    reverseGeocodeSearchOption.reverseGeoPoint = pt;//设置反编码的店为pt
    BOOL flag = [_geocodesearch reverseGeoCode:reverseGeocodeSearchOption];//发送反编码请求.并返回是否成功
    if(flag)
    {
        NSLog(@"反geo检索发送成功");
    }
    else
    {
        NSLog(@"反geo检索发送失败");
    }
}


//发送成功,百度将会返回东西给你
-(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher
                           result:(BMKReverseGeoCodeResult *)result
                        errorCode:(BMKSearchErrorCode)error
{
    
    if (error == BMK_SEARCH_NO_ERROR) {
        NSString *address1 = result.address; // result.addressDetail ///层次化地址信息
        NSLog(@"我的位置在 %@",address1);
        
        //保存位置信息到模型
        [self.userLocationInfoModel saveLocationInfoWithBMKReverseGeoCodeResult:result];
        
        //进行缓存处理,上传到服务器等操作
}

需要提到的是,可以合理利用BMKReverseGeoCodeResult类型的对象result,比如取出它的某些属性存到自己定义的模型中去。该对象的类型是百度地图SDK的类,里面包含了根据经纬度返回的地址信息。它的类文件如下:

/*
 *  BMKGeocodeType.h
 *  BMapKit
 *
 *  Copyright 2011 Baidu Inc. All rights reserved.
 *
 */

#import <BaiduMapAPI_Base/BMKTypes.h>

///反地址编码结果
@interface BMKReverseGeoCodeResult : NSObject
{
    BMKAddressComponent* _addressDetail;
    NSString* _address;
    CLLocationCoordinate2D _location;
    NSArray* _poiList;
}
///层次化地址信息
@property (nonatomic, strong) BMKAddressComponent *addressDetail;
///地址名称
@property (nonatomic, strong) NSString* address;
///商圈名称
@property (nonatomic, strong) NSString* businessCircle;
///结合当前位置POI的语义化结果描述
@property (nonatomic, strong) NSString* sematicDescription;
///地址坐标
@property (nonatomic) CLLocationCoordinate2D location;
///地址周边POI信息,成员类型为BMKPoiInfo
@property (nonatomic, strong) NSArray* poiList;

@end

///地址编码结果
@interface BMKGeoCodeResult : NSObject
{
    CLLocationCoordinate2D _location;
    NSString* _address;
}
///地理编码位置
@property (nonatomic) CLLocationCoordinate2D location;
///地理编码地址
@property (nonatomic,strong) NSString* address;

@end

其中,result对象包含了一个层次化地址信息,如@property (nonatomic, strong) BMKAddressComponent *addressDetail;所示。它的addressDetail属性包含的信息可从BMKAddressComponent类的代码了解更多:

///线路检索节点信息,一个路线检索节点可以通过经纬度坐标或城市名加地名确定
@interface BMKPlanNode : NSObject{
    NSString*              _cityName;
    NSString*              _name;
    CLLocationCoordinate2D _pt;
}

///节点所在城市
@property (nonatomic, strong) NSString* cityName;
///节点所在城市ID
@property (nonatomic, assign) NSInteger cityID;
///节点名称
@property (nonatomic, strong) NSString* name;
///节点坐标
@property (nonatomic) CLLocationCoordinate2D pt;
@end

///室内路线检索节点信息
@interface BMKIndoorPlanNode : NSObject

///节点所在楼层
@property (nonatomic, retain) NSString* floor;
///节点坐标
@property (nonatomic) CLLocationCoordinate2D pt;

@end

///此类表示地址结果的层次化信息
@interface BMKAddressComponent : NSObject

/// 街道号码
@property (nonatomic, strong) NSString* streetNumber;
/// 街道名称
@property (nonatomic, strong) NSString* streetName;
/// 区县名称
@property (nonatomic, strong) NSString* district;
/// 城市名称
@property (nonatomic, strong) NSString* city;
/// 省份名称
@property (nonatomic, strong) NSString* province;
/// 国家
@property (nonatomic, strong) NSString* country;
/// 国家代码
@property (nonatomic, strong) NSString* countryCode;

@end

正如上面的代码中看到,里面包含了国家,省市区,街道及街道号等层次化信息。在实际的开发中,可以按需取出这些信息,这种操作可以写在下面的代理方法中去。

//发送成功,百度将会返回东西给你
-(void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher
                           result:(BMKReverseGeoCodeResult *)result
                        errorCode:(BMKSearchErrorCode)error
{
   //取出层次化信息操作
}

附1:可能的问题

百度地图反geo检索发送失败

可能因为,key是其它样例Demo的,或者以前申请的过期了。检查一下,用自己工程的Bundle Identifer重新申请key,在真机上进行测试,反检索发起成功。这时候需要重新申请密钥key。

附2:参考文献

  1. 百度地图iOS SDK开发指南
  2. 百度地图iOS地图SDK
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容