前言

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以上系统必须配置
  • 工程配置。
  1. 左侧目录中选中工程名,开启 TARGETS->Capabilities->Background Modes
  2. 在 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到工程中;

android高德地图service定位 高德地图定位服务_高德地图


第三步:引入系统库文件。

在 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)。

android高德地图service定位 高德地图定位服务_地图_02


第五步:申请应用,获取注册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,如下图所示:

android高德地图service定位 高德地图定位服务_高德地图_03

示例代码:

#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