iOS·採用第三方(百度地圖SDK)實現定位等功能開發
2017.05.01 01:06* 字數 2212 閱讀 6818評論 7喜歡 133
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。