部分摘自iOS开发系列–地图与定位

前言:

定位功能一般是由Core Location框架中的API来提供的,而地图功能一般是由Map Kit框架中的API来提供的。

注意:

.在iOS7及以前的版本中,如果在应用程序中使用定位服务只要在程序中调用startUpdatingLocation方法应用就会询问用户是否允许此应用使用定位服务,同时在提示过程中可以通过在info.plist中配置通过配置Privacy-Location Usage Description告诉用户使用的目的,同时这个配置是可选的。
.但是在iOS8中配置项发生了变化,可以通过配置NSLocationAlwaysUsageDescription或者NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。同时,在应用程序中需要根据配置对requestAlwaysAuthorizationlocationServicesEnabled方法进行请求。

使用Core Location一定要进行配置,配置方法:

info.plist中,加入以下的配置:

  • NSLocationAlwaysUsageDescription:类型是String,允许在后台获取GPS的描述
  • NSLocationWhenInUseUsageDescription:类型是String,允许在前台获取GPS的描述

在设置中出现的选项是取决于在info.plist中的配置

1.只配置 NSLocationAlwaysUsageDescription

ios 修改位置 开发调试 ios修改定位原理_定位服务


ios 修改位置 开发调试 ios修改定位原理_定位服务_02


2.只配置NSLocationWhenInUseUsageDescription

ios 修改位置 开发调试 ios修改定位原理_git_03


ios 修改位置 开发调试 ios修改定位原理_地理编码_04


3.同时配置

ios 修改位置 开发调试 ios修改定位原理_定位服务_05


ios 修改位置 开发调试 ios修改定位原理_定位服务_06

当然,以上只是配置,使用哪一项还要取决于用户的请求:

[self.manager requestAlwaysAuthorization];
//[self.manager requestWhenInUseAuthorization];只选择一行写就可以,第一次请求只是配置第一次,以后的授权状态是取决于用户在设置中的选择

概述:

Core Location是iOS SDK中一个提供设备位置的框架,通过这个框架可以实现定位处理。在Core Location中主要包含了定位、地理编码(包括反编码)功能。

一.定位功能

实现定位功能需要使用Core Loaction中CLLocationManager类,下面是这个类的方法和属性:

类方法:

1.+ (BOOL)locationServicesEnabled;

是否启用定位服务,通常如果用户没有启用定位服务可以提示用户打开定位服务

2.+ (CLAuthorizationStatus)authorizationStatus;

定位服务授权状态,返回枚举类型:

  • kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务
  • kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
  • kCLAuthorizationStatusDenied:用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
  • kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态
  • kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务

属性:

1.desiredAccuracy

定位精度,枚举类型:

  • kCLLocationAccuracyBest:最精确定位
  • kCLLocationAccuracyNearestTenMeters:十米误差范围
  • kCLLocationAccuracyHundredMeters:百米误差范围
  • kCLLocationAccuracyKilometer:千米误差范围
  • kCLLocationAccuracyThreeKilometers:三千米误差范围

对象方法:

1.startUpdatingLocation

开始定位追踪,开始定位后将按照用户设置的更新频率执行-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;方法反馈定位信息

2.stopUpdatingLocation

停止定位追踪

3.startUpdatingHeading

开始导航方向追踪

4.stopUpdatingHeading

停止导航方向追踪

5.startMonitoringForRegion:

开始对某个区域进行定位追踪,开始对某个区域进行定位后。如果用户进入或者走出某个区域会调用

- (void)locationManager:(CLLocationManager *)manager
    didEnterRegion:(CLRegion *)region

- (void)locationManager:(CLLocationManager *)manager
    didExitRegion:(CLRegion *)region

代理方法反馈相关信息

6.stopMonitoringForRegion:

停止对某个区域进行定位追踪

7.requestWhenInUseAuthorization

请求获得应用使用时的定位服务授权,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription

8.requestAlwaysAuthorization

请求获得应用一直使用定位服务授权,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription

代理方法:

(I)
-(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations;

位置发生改变后执行(第一次定位到某个位置之后也会执行)

(II)
-(void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)newHeading;

向发生变化后执行

(III)
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region

进入某个区域之后执行

(IIII)
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region

走出某个区域之后执行

总结:

iOS 8 还提供了更加人性化的定位服务选项。App 的定位服务不再仅仅是关闭或打开,现在,定位服务的启用提供了三个选项,「永不」「使用应用程序期间」和「始终」。同时,考虑到能耗问题,如果一款 App 要求始终能在后台开启定位服务,iOS 8 不仅会在首次打开 App 时主动向你询问,还会在日常使用中弹窗提醒你该 App 一直在后台使用定位服务,并询问你是否继续允许。

代码展示:

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface KCMainViewController ()<CLLocationManagerDelegate>{

    CLLocationManager *_locationManager;
}

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //定位管理器
    _locationManager=[[CLLocationManager alloc]init];

    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"定位服务当前可能尚未打开,请设置打开!");
        return;
    }

    //如果没有授权则请求用户授权
        [_locationManager requestWhenInUseAuthorization];//当应用使用期间请求运行定位


if([CLLocationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedWhenInUse){
        //设置代理
        _locationManager.delegate=self;
        //设置定位精度
        _locationManager.desiredAccuracy=kCLLocationAccuracyBest;
        //定位频率,每隔多少米定位一次
        CLLocationDistance distance=10.0;//十米定位一次
        _locationManager.distanceFilter=distance;
        //启动跟踪定位
        [_locationManager startUpdatingLocation];
    }
}

#pragma mark - CoreLocation 代理
#pragma mark 跟踪定位代理方法,每次位置发生变化即会执行(只要定位到相应位置)
//可以通过模拟器设置一个虚拟位置,否则在模拟器中无法调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    CLLocation *location=[locations firstObject];//取出第一个位置
    CLLocationCoordinate2D coordinate=location.coordinate;//位置坐标
    NSLog(@"经度:%f,纬度:%f,海拔:%f,航向:%f,行走速度:%f",coordinate.longitude,coordinate.latitude,location.altitude,location.course,location.speed);
    //如果不需要实时定位,使用完即使关闭定位服务
    [_locationManager stopUpdatingLocation];
}

@end

@end

二.地理编码

除了提供位置跟踪功能之外,在定位服务中还包含CLGeocoder类用于处理地理编码和逆地理编码(又叫反地理编码)功能。

  • 地理编码:根据给定的位置(通常是地名)确定地理坐标(经、纬度)
  • 逆地理编码:可以根据地理坐标(经、纬度)确定位置信息(街道、门牌等)

CLGeocoder最主要的两个方法就是

  • - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;用于地理编码
  • - (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;用于逆地址编码

使用代码展示

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface KCMainViewController ()<CLLocationManagerDelegate>{

    CLGeocoder *_geocoder;
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    _geocoder=[[CLGeocoder alloc]init];
    [self getCoordinateByAddress:@"北京"];
    [self getAddressByLatitude:39.54 longitude:116.28];
}

#pragma mark 根据地名确定地理坐标
-(void)getCoordinateByAddress:(NSString *)address{
    //地理编码
    [_geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
        //取得第一个地标,地标中存储了详细的地址信息,注意:一个地名可能搜索出多个地址
        CLPlacemark *placemark=[placemarks firstObject];

        CLLocation *location=placemark.location;//位置
        CLRegion *region=placemark.region;//区域
        NSDictionary *addressDic= placemark.addressDictionary;//详细地址信息字典,包含以下部分信息
//        NSString *name=placemark.name;//地名
//        NSString *thoroughfare=placemark.thoroughfare;//街道
//        NSString *subThoroughfare=placemark.subThoroughfare; //街道相关信息,例如门牌等
//        NSString *locality=placemark.locality; // 城市
//        NSString *subLocality=placemark.subLocality; // 城市相关信息,例如标志性建筑
//        NSString *administrativeArea=placemark.administrativeArea; // 州
//        NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政区域信息
//        NSString *postalCode=placemark.postalCode; //邮编
//        NSString *ISOcountryCode=placemark.ISOcountryCode; //国家编码
//        NSString *country=placemark.country; //国家
//        NSString *inlandWater=placemark.inlandWater; //水源、湖泊
//        NSString *ocean=placemark.ocean; // 海洋
//        NSArray *areasOfInterest=placemark.areasOfInterest; //关联的或利益相关的地标
        NSLog(@"位置:%@,区域:%@,详细信息:%@",location,region,addressDic);
    }];
}

#pragma mark 根据坐标取得地名
-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{
    //反地理编码
    CLLocation *location=[[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
    [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        CLPlacemark *placemark=[placemarks firstObject];
        NSLog(@"详细信息:%@",placemark.addressDictionary);
    }];
}

@end