美文网首页iOS技术交流收藏第三方应用IOS | MAC
iOS·采用第三方(百度地图SDK)实现定位等功能开发

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

作者: 小码僧 | 来源:发表于2017-05-01 01:06 被阅读4748次

    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

    相关文章

      网友评论

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

      本文链接:https://www.haomeiwen.com/subject/luhftxtx.html