地图定位


 
一:地图与定位基本框架(MapKit时基于CoreLocation实现的夜可以实现定位)
 
二:开发常用技术
  • LBS:基于位置的服务
  • SoLoMo:社交,本地,移动化
 
 
三:定位授权提示(iOS之前)
 
 
四:每个一段距离定位
 
 
五:后台服务:默认只能在前台服务
plist文件中
 
对应plist文件的值(数组)
 
六:基于基站定位
 
 
七:iOS8以上的服务
  • 前台定位
定位服务开启
开启授权
后台服务(可以不勾选后台模式)
  • 定位服务开
开启后台授权
 
授权改变
// 如果授权状态发生变化时,调用
// status : 当前的授权状态
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户未决定");
             break;
        }
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"受限制");
            break;
        }
        case kCLAuthorizationStatusDenied:
        {
            // 判断当前设备是否支持定位, 并且定位服务是否开启()
            if([CLLocationManager locationServicesEnabled])
            {
                NSLog(@"定位开启,被拒绝");
                // ios8,0- 需要截图提醒引导用户
               
                // iOS8.0+
                NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                if([[UIApplication sharedApplication] canOpenURL:url])
                {
                    [[UIApplication sharedApplication] openURL:url];
                }
               
            }else
            {
                NSLog(@"定位服务关闭");
            }
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:
        {
             NSLog(@"前后台定位授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"前台定位授权");
            break;
        }
           
        default:
            break;
    }
   
}

  

 
八:系统适配
 
1:根据系统的版本
2:根据方法的响应
3:iOS9中版本判断
 
 
 
 
九:提示用户开启定位
 
  • iOS-8之前:需要截图
  • iOS8之后:跳转URL
 
十:关于iOS9定位
 
后台定位需要增加一个属性(在勾选后台活着增加plist属性之后)
 
iOS9中请求一次定位信息
 
十一:id加范型->is Kind of 
 
判断当前位置是否可用
或者
十二:指南针
在创建管理者设置代理

    // 获取当前设备朝向
    [self.locationM startUpdatingHeading];
然后在代理方法中实现下面的代码

// 已经更新到用户设备朝向时调用
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{

    // magneticHeading : 距离磁北方向的角度
    // trueHeading : 真北
    // headingAccuracy : 如果是负数,代表当前设备朝向不可用
    if (newHeading.headingAccuracy < 0) {
        return;
    }
   
    // 角度
    CLLocationDirection angle = newHeading.magneticHeading;
   
    // 角度-> 弧度
    double radius = angle / 180.0 * M_PI;
   
    // 反向旋转图片(弧度)
    [UIView animateWithDuration:0.5 animations:^{
            self.compassView.transform = CGAffineTransformMakeRotation(-radius);
    }];
   
}
 

  

 
十三:区域监听
判断区域类
 
判断区域大小
区域变化
 
十四:监听区域的时候调用的代理方法
1.进入

/**
 *  进入区域调用(是一个动作)
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域");
    self.noticeLabel.text = @"小码哥欢迎你, 给你技术";
}
2.离开


/**
 *  离开某个区域调用
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"离开区域");
      self.noticeLabel.text = @"祝大神三期找到30K";
}
3.判断和区域的位置对应

/**
 *  请求某个区域的状态是调用
 *
 *  @param manager 位置管理者
 *  @param state   状态
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
//    CLRegionStateUnknown,   未知状态
//    CLRegionStateInside, // 在区域内部
//    CLRegionStateOutside // 区域外面
    if(state == CLRegionStateInside)
    {
        self.noticeLabel.text = @"小码哥欢迎你, 给你技术";
    }else if (state == CLRegionStateOutside)
    {
         self.noticeLabel.text = @"祝大神三期找到30K";
    }
}
4.失败

/**
 *  监听区域失败时调用
 *
 *  @param manager 位置管理者
 *  @param region  区域
 *  @param error   错误
 */
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
    // 经验: 一般在这里, 做移除最远的区域
   
//    [manager stopMonitoringForRegion:最远区域]
   
}

  

 
十五:编码与反编码
 
地理编码:位置名称->经纬度

   
    NSString *address = self.addressTV.text;
   
    // 容错
    if([address length] == 0)
        return;
   
    [self.geoC geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
       
        // CLPlacemark : 地标
        // location : 位置对象
        // addressDictionary : 地址字典
        // name : 地址详情
        // locality : 城市
       
        if(error == nil)
        {
            CLPlacemark *pl = [placemarks firstObject];
            self.addressTV.text = pl.name;
            self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue;
            self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue;
        }else
        {
            NSLog(@"错误");
        }

       
    }];
    
 
反地理编码:经纬度->位置名称

   
    // 获取用户输入的经纬度
    double latitude = [self.latitudeTF.text doubleValue];
    double longitude = [self.longitudeTF.text doubleValue];
   
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
   
    // 反地理编码(经纬度---地址)
    [self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if(error == nil)
        {
            CLPlacemark *pl = [placemarks firstObject];
            self.addressTV.text = pl.name;
            self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue;
            self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue;
        }else
        {
            NSLog(@"错误");
        }

    }];
   
    
 
 
 
 
注:double快速转string
 

  

十六:第三方->LocationManager
基本使用

    INTULocationManager *locMgr = [INTULocationManager sharedInstance];
   
    // delayUntilAuthorized 超时计时从什么时候开始
    INTULocationRequestID requestID = [locMgr requestLocationWithDesiredAccuracy:INTULocationAccuracyCity
                                       timeout:3.0
                          delayUntilAuthorized:NO
                                         block:^(CLLocation *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {
                                             if (status == INTULocationStatusSuccess) {
                                               
                                                 NSLog(@"---%@", currentLocation);
                                                
                                             }else
                                             {
                                                 NSLog(@"错误 %zd", status);
                                             }
                                         }];
   
    // 会执行block内容
//    [[INTULocationManager sharedInstance] forceCompleteLocationRequest:requestID];
    // 取消位置请求
    [[INTULocationManager sharedInstance] cancelLocationRequest:requestID];
 
 
 

  

 
 
在使用的时候爆了一个错误
解决办法:
 
十七:经典实战,将代理转Blcok
 
定义一个Block
typedef void(^ResultBlock)(CLLocation *location, CLPlacemark *pl, NSString *error);
 
 
声明一个带Block方法
- (void)getCurrentLocation:(ResultBlock)block;
 
实现方法



- (void)getCurrentLocation:(ResultBlock)block
{
    // 记录代码块
    self.block = block;
   
   
    // 获取用户位置信息
    if([CLLocationManager locationServicesEnabled])
    {
        [self.locationM startUpdatingLocation];
    }else
    {
        self.block(nil, nil, @"定位服务未开启");
    }
 
}
在创建位置管理者的时候实现项目内部文件对应属性值的判断,根据不同的值提示开发者

    if (!_locationM) {
        _locationM = [[CLLocationManager alloc] init];
        _locationM.delegate = self;
       
        // iOS8.0之后, 必须手动请求定位授权
        // 获取info.plist 里面的键值对
        NSDictionary *infoDic = [NSBundle mainBundle].infoDictionary;
       
//        NSLog(@"%@", infoDic);
       
        if (isIOS(8.0)) {
//            [_locationM requestAlwaysAuthorization];
//            [_locationM requestWhenInUseAuthorization];

           
            // 获取前后台定位描述(看其他开发者到底有没有添加这个key)
            NSString *alwaysStr = infoDic[@"NSLocationAlwaysUsageDescription"];
           
            // 获取前后台定位描述(看其他开发者到底有没有添加这个key)
            NSString *whenInUseStr = infoDic[@"NSLocationWhenInUseUsageDescription"];
           
            // 判断其它开发者, 到底填写的是哪个key
            if([alwaysStr length] > 0)
            {
                [_locationM requestAlwaysAuthorization];
            }
            else if ([whenInUseStr length] > 0)
            {
                [_locationM requestWhenInUseAuthorization];
                // 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates
                NSArray *backModes = infoDic[@"UIBackgroundModes"];
                if (![backModes containsObject:@"location"]) {
                    NSLog(@"当前授权模式是前台定位授权, 如果想要在后台获取位置, 需要勾选后台模式location updates");
                }else // 代表当前勾选后台模式, 而且是前台定位授权
                {
                    if(isIOS(9.0))
                    {
                        _locationM.allowsBackgroundLocationUpdates = YES;
                    }
                }
      
            }else
            {
                NSLog(@"如果在iOS8.0之后获取用户位置, 必须主动填写info.plist文件中的key NSLocationAlwaysUsageDescription 或者NSLocationWhenInUseUsageDescription");
            }
           
           
        }else // ios8.0之前
        {
            // 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates
            NSArray *backModes = infoDic[@"UIBackgroundModes"];
            if (![backModes containsObject:@"location"]) {
                NSLog(@"当前授权模式, 如果想要在后台获取位置, 需要勾选后台模式location updates");
            }

        }
       
    }
    return _locationM;
 
 
 
实现位置更新方法


#pragma mark -CLLocationManagerDelegate
/**
 *  定位到之后调用
 *
 *  @param manager   位置管理者
 *  @param locations 位置数组
 */
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    CLLocation *location = [locations lastObject];
   
    // 判断位置是否可用
    if (location.horizontalAccuracy >= 0) {
        [self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
           
            if (error == nil) {
                CLPlacemark *pl = [placemarks firstObject];
                self.block(location, pl, nil);
            }else
            {
                self.block(location, nil, @"反地理编码失败");
            }
   
        }];
 
    }
   
    // 如果只需要获取一次位置, 那么在此处停止获取用户位置
    [manager stopUpdatingLocation];
   

}
 
 
 
实现授权改变


/**
 *  当前授权状态发生改变时调用
 *
 *  @param manager 位置管理者
 *  @param status  状态
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
            // 用户还未决定
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户还未决定");
            break;
        }
            // 问受限
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            self.block(nil, nil, @"访问受限");
            break;
        }
            // 定位关闭时和对此APP授权为never时调用
        case kCLAuthorizationStatusDenied:
        {
            // 定位是否可用(是否支持定位或者定位是否开启)
            if([CLLocationManager locationServicesEnabled])
            {
                NSLog(@"定位开启,但被拒");
                self.block(nil, nil, @"被拒绝");
            }else
            {
                NSLog(@"定位关闭,不可用");
                self.block(nil, nil, @"定位关闭,不可用");
            }
            break;
        }
            // 获取前后台定位授权
        case kCLAuthorizationStatusAuthorizedAlways:
            //        case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
        {
            NSLog(@"获取前后台定位授权");
            break;
        }
            // 获得前台定位授权
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"获得前台定位授权");
            break;
        }
        default:
            break;
    }

}

  


 
总结
 
开发经验
  • 1:start开启服务,stop停止服务
  • 2:用户隐私提示说明(交给产品经理)
  • 3:重大位置-基站
 
 
关于地图术语:
 
1.方位简写
  • E东
  • W西
  • N北
  • S南
2.位置的计算
  • 1’ = 111km
 
3.术语
  • coordinate:经纬度
  • altitude:海拔高度
  • course航向
  • distanceFromLocation。计算距离
 
4.返回数值
  • 负值代表不可用
 
5.指南针方向
  • megneticHeading:磁北
  • tureHeading:真北
  • headingAcceracy:负则不可用
 
 
使用总结
 
  • 地图简单总
  • 转弧
 
 
Xcode模拟器安装
解压
解压后放倒对应的路径中
 
posted @ 2015-11-05 19:29  Apolla  阅读(331)  评论(0编辑  收藏  举报