前言
iOS系統不允許第三方定位,定位功能是對iOS系統定位的二次封裝。通過封裝,可將原始定位點無偏差的顯示在高德地圖上。目前,有兩種獲取當前位置信息的方法:
- 使用地圖SDK中的定位功能。本文以2D地圖SDK爲例做相關介紹
- 使用iOS定位SDK,目前提供了獨立的”iOS定位SDK”,無需展示地圖即可獲取用戶位置信息,我們會在以後介紹。
1. 地圖定位
1.1 開啓定位
需在info.plist添加NSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription字段
- NSLocationWhenInUseUsageDescription表示應用在前臺的時候可以搜到更新的位置信息。
- NSLocationAlwaysUsageDescription表示應用在前臺和後臺(suspend或terminated)都可以獲取到更新的位置數據。
只要開啓定位開關(MAMapView的showsUserLocation屬性)就可以開始定位。
示例代碼:
#import "ViewController.h"
#import <MAMapKit/MAMapKit.h>
@interface ViewController ()<MAMapViewDelegate>
{
MAMapView *_mapView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_mapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))];
_mapView.delegate = self;
[self.view addSubview:_mapView];
// 地圖SDK定位服務
_mapView.showsUserLocation = YES; //YES 爲打開定位,NO爲關閉定位
[_mapView setUserTrackingMode: MAUserTrackingModeFollow animated:YES]; //地圖跟着位置移動
[_mapView setZoomLevel:16.1 animated:YES];
}
#pragma mark - MAMapViewDelegate
-(void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation
{
if(updatingLocation)
{
//取出當前位置的座標
NSLog(@"latitude : %f,longitude: %f",userLocation.coordinate.latitude,userLocation.coordinate.longitude);
}
// 該方法會頻繁調用多次,但是不能通過關閉定位的方法來解決
// _mapView.showsUserLocation = NO;
}
1.2 設置定位圖層
將 MAMapView 添加到 Subview 中,開啓定位後,會在地圖上顯示定位圖層。高德地圖 iOS SDK 支持自定義定位圖層的樣式。
通過setUserTrackingMode:可改變定位圖層的顯示模式:定位圖層有3種顯示模式,分別爲:
- MAUserTrackingModeNone:僅在地圖上顯示,不跟隨用戶位置。
- MAUserTrackingModeFollow:跟隨用戶位置移動,並將定位點設置成地圖中心點。
- MAUserTrackingModeFollowWithHeading:跟隨用戶的位置和角度移動。
1.3 自定義定位圖層
定位圖層由定位點處的標註(MAUserLocation)和精度圈(MACircle)組成。通過- (void)mapView:(MAMapView )mapView didAddAnnotationViews:(NSArray )views方法自定義定位標註和精度圈的樣式。
示例代碼:
// 添加用戶大頭針
- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MAAnnotationView *view = views[0];
// 放到該方法中用以保證userlocation的annotationView已經添加到地圖上了。
if ([view.annotation isKindOfClass:[MAUserLocation class]])
{
MAUserLocationRepresentation *pre = [[MAUserLocationRepresentation alloc] init];
pre.fillColor = [UIColor colorWithRed:0.9 green:0.1 blue:0.1 alpha:0.3];
pre.strokeColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.9 alpha:1.0];
pre.image = [UIImage imageNamed:@"category_3"];
pre.lineWidth = 3;
pre.lineDashPattern = @[@6, @3];
[_mapView updateUserLocationRepresentation:pre];
view.calloutOffset = CGPointMake(0, 0);
}
}
1.4 開啓後臺定位
高德地圖iOS SDK V2.5.0版本提供後臺持續定位的能力,即便你的app退到後臺,且位置不變動時,也不會被系統掛起,可持久記錄位置信息。該功能適用於記軌跡錄或者出行類App司機端。
注意:後臺定位必須將info.plist的字段改成NSLocationAlwaysUsageDescription字段。
只需要您的做以下幾步操作:
- 添加代碼。
_mapView.pausesLocationUpdatesAutomatically = NO;
_mapView.allowsBackgroundLocationUpdates = YES;//iOS9以上系統必須配置
- 工程配置。
- 左側目錄中選中工程名,開啓 TARGETS->Capabilities->Background Modes
- 在 Background Modes中勾選 Location updates,如下圖所示:
2. 高德定位SDK
高德 iOS 定位 SDK 提供了不依賴於地圖定位的定位功能,開發者可以無地圖顯示的場景中便捷地爲應用程序添加定位功能。 iOS定位SDK提供了單次定位、連續定位、逆地理信息、地理圍欄等功能。
2.1 SDK的集成
第一步:下載開發包並解壓。
從中下載定位包,解壓後得到 AMapLocationKit.framework 。
第二步:引入定位包。
在 TARGETS-Build Phases–Link Binary With Libraries 點擊“+”,彈出添加列表後,點擊“Add Other…”,添加 AMapLocationKit.framework到工程中;
第三步:引入系統庫文件。
在 TARGETS-General-Linked Frameworks and Libraries 中點擊“+”,彈出添加列表後添加如下系統庫: CoreTelephony.framework, SystemConfiguration.framework, CoreLocation.framework, libz.tbd(Xcode7之前,是libz.dylib)。
第四步:環境配置
(1)配置 Other Link Flag。
在 TARGETS-Build Settings-Other Linker Flags 中添加如下內容: -ObjC;
(2)配置Architectures。
在 TARGETS-Build Settings-Architectures 點擊出選擇框,將值修改爲 $(ARCHS_STANDARD)。
第五步:申請應用,獲取註冊appkey
在使用定位SDK時,需要對應用做Key機制驗證,如果不添加Key,定位功能將不能使用: [AMapLocationServices sharedServices].apiKey = @”您的key”;
注意:
- 需要在info.plist中追加 NSLocationWhenInUseUsageDescription 或NSLocationAlwaysUsageDescription 字段,以申請定位權限。
- iOS9爲了增強數據訪問安全,將所有的http請求都改爲了https,爲了能夠在iOS9中正常使用地圖SDK,請在”Info.plist”中進行如下配置,否則影響SDK的使用。
2.2 持續定位
iOS定位SDK提供的持續定位功能獲取定位數據(地圖SDK可以將獲取的數據進行展示),與CLLocationManager的使用方法類似。實現持續定位的步驟如下:
- 初始化AMapLocationManager對象,設置代理。
- 開啓持續定位,調用AMapLocationManager提供的startUpdatingLocation方法實現。停止持續定位調用AMapLocationManager提供的stopUpdatingLocation方法實現。
- 接收位置更新,實現AMapLocationManagerDelegate代理的amapLocationManager:didUpdateLocation: 方法,處理位置更新。
示例代碼:
#import "ViewController.h"
#import <AMapLocationKit/AMapLocationKit.h>
@interface ViewController ()<AMapLocationManagerDelegate>
{
AMapLocationManager *_manager;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[AMapLocationServices sharedServices].apiKey = @"88d606ae8da9c5b8c01e03367526272a";
// 初始化定位管家並設置代理
_manager = [[AMapLocationManager alloc] init];
_manager.delegate = self;
// 開始持續定位
[_manager startUpdatingLocation];
// 停止定位
// [_manager stopUpdatingLocation];
}
#pragma mark - AMapLocationManagerDelegate
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location
{
NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy);
}
@end
2.3 單次定位
iOS定位SDK提供的單次定位方法基於蘋果定位核心,蘋果定位核心會在設備移動時連續返回定位結果,高德在此基礎上封裝了單次定位並適配了iOS 6到iOS 9系統。當設備可以正常聯網時,還可以返回該定位點的位置信息(包括:省、市、區/縣以及詳細地址)。 單次定位區別於連續定位,無需設置代理和實現代理方法,與連續定位一樣需要引入AMapLocationKit.h頭文件。
- 初始化定位管家。
- 設置期望定位精度。
- 請求定位並拿到結果,調用AMapLocationManager的requestLocationWithReGeocode:completionBlock: 方法,請求一次定位。
示例代碼:
#import "ViewController.h"
#import <AMapLocationKit/AMapLocationKit.h>
@interface ViewController ()<AMapLocationManagerDelegate>
{
AMapLocationManager *_manager;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[AMapLocationServices sharedServices].apiKey = @"88d606ae8da9c5b8c01e03367526272a";
// 初始化定位管家並設置代理
_manager = [[AMapLocationManager alloc] init];
// 單次定位
// 帶逆地理信息的一次定位(返回座標和地址信息)
[_manager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];// 設置定位精度
// 定位超時時間,最低2s,
_manager.locationTimeout = 30;
// 逆地理請求超時時間,最低2s,
_manager.reGeocodeTimeout = 30;
// 高精度:kCLLocationAccuracyBest,精度很高的一次定位,偏差在10米以內,耗時在10s左右。
// 帶逆地理(返回座標和地址信息)。
// 獲取單次定位信息,第一個參數設置爲NO,則不會返回地址信息。
[_manager requestLocationWithReGeocode:NO completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
if (error) {
NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
return;
}
NSLog(@"location:%@", location);
if (regeocode) {
NSLog(@"reGeocode:%@", regeocode);
}
}];
}
2.4 後臺定位
iOS定位SDK提供後臺持續定位的能力,可持久記錄位置信息,適用於記軌跡錄。需要引入AMapLocationKit.h頭文件。
更改info.plist
將info.plist的字段改成NSLocationAlwaysUsageDescription字段。
配置後臺定位
左側目錄中選中工程名,開啓 TARGETS->Capabilities->Background Modes 在 Background Modes中勾選 Location updates,如下圖所示:
示例代碼:
#import "ViewController.h"
#import <AMapLocationKit/AMapLocationKit.h>
@interface ViewController ()<AMapLocationManagerDelegate>
{
AMapLocationManager *_manager;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[AMapLocationServices sharedServices].apiKey = @"88d606ae8da9c5b8c01e03367526272a";
// 初始化定位管家並設置代理
_manager = [[AMapLocationManager alloc] init];
_manager.delegate = self;
// 後臺定位
//設置允許後臺定位參數,保持不會被系統掛起
[_manager setPausesLocationUpdatesAutomatically:NO];
[_manager setAllowsBackgroundLocationUpdates:YES];//iOS9(含)以上系統需設置
// 開始持續定位
[_manager startUpdatingLocation];
}
#pragma mark - AMapLocationManagerDelegate
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location
{
NSLog(@"location:{lat:%f; lon:%f; accuracy:%f}", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy);
}
2.5 定位輔助功能
定位SDK爲我們提供了一些輔助功能,主要有一下兩種:
- 區域判斷:判斷目標經緯度是否在大陸及港、澳地區,方便開發者按需切換國內/海外功能,目前支持判斷目標經緯度是否在大陸及港、澳地區,方便開發者按需切換區域功能。
- 地理圍欄:以一個圓形的地理邊界作爲虛擬圍欄,當手機進入、離開該區域時,手機可以接收自動通知。
示例代碼:
#import "ViewController.h"
#import <AMapLocationKit/AMapLocationKit.h>
#import <MAMapKit/MAMapKit.h>
@interface ViewController ()<AMapLocationManagerDelegate>
{
MAMapView *_mapView;
AMapLocationManager *_manager;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[AMapLocationServices sharedServices].apiKey = @"88d606ae8da9c5b8c01e03367526272a";
// 初始化定位管家並設置代理
_manager = [[AMapLocationManager alloc] init];
_manager.delegate = self;
// 輔助功能
// 區域判斷
//設置一個目標經緯度
CLLocationCoordinate2D coodinate = CLLocationCoordinate2DMake(39.948691, 116.492479);
//返回是否在大陸及港、澳地區
BOOL flag= AMapLocationDataAvailableForCoordinate(coodinate);
NSLog(@"%d",flag);
// 地理圍欄
AMapLocationCircleRegion *cirRegion200 = [[AMapLocationCircleRegion alloc] initWithCenter:CLLocationCoordinate2DMake(40, 119) radius:200.0 identifier:@"circleRegion200"];
AMapLocationCircleRegion *cirRegion300 = [[AMapLocationCircleRegion alloc] initWithCenter:CLLocationCoordinate2DMake(40, 119) radius:300.0 identifier:@"circleRegion300"];
//添加地理圍欄
[_manager startMonitoringForRegion:cirRegion200];
[_manager startMonitoringForRegion:cirRegion300];
// 初始化地圖
_mapView = [[MAMapView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_mapView];
//添加Overlay
MACircle *circle200 = [MACircle circleWithCenterCoordinate:CLLocationCoordinate2DMake(40, 119) radius:200.0];
MACircle *circle300 = [MACircle circleWithCenterCoordinate:CLLocationCoordinate2DMake(40, 119) radius:300.0];
[_mapView addOverlay:circle200];
[_mapView addOverlay:circle300];
[_mapView setVisibleMapRect:circle300.boundingMapRect];
}
- (void)amapLocationManager:(AMapLocationManager *)manager didEnterRegion:(AMapLocationRegion *)region {
NSLog(@"進入圍欄:%@", region);
}
- (void)amapLocationManager:(AMapLocationManager *)manager didExitRegion:(AMapLocationRegion *)region {
NSLog(@"走出圍欄:%@", region);
}
@end