zoukankan      html  css  js  c++  java
  • 【iOS】7.4 定位服务->2.1.2 定位

    本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正。


    本文相关目录:
    ================== 所属文集:【iOS】07 设备工具 ==================
    7.4 定位服务->1.0 简介
    7.4 定位服务->2.1.1 定位 - 官方框架CoreLocation: 请求用户授权
    7.4 定位服务->2.1.2 定位 - 官方框架CoreLocation: CLLocationManager位置管理器
    7.4 定位服务->2.1.3.1 定位 - 官方框架CoreLocation 功能1:地理定位
    7.4 定位服务->2.1.3.2 定位 - 官方框架CoreLocation 功能2:地理编码和反地理编码
    7.4 定位服务->2.1.3.3 定位 - 官方框架CoreLocation 功能3:区域监听
    7.4 定位服务->2.1.4 定位 - 官方框架CoreLocation 案例:指南针效果
    7.4 定位服务->2.2 定位 - locationManager框架
    7.4 定位服务->3.1 地图框架MapKit 功能1:地图展示
    7.4 定位服务->3.2 地图框架MapKit 功能2:路线规划(导航)
    7.4 定位服务->3.3 地图框架MapKit 功能3:3D视图
    7.4 定位服务->3.4 地图框架MapKit 功能4:地图截图
    7.4 定位服务->3.5 地图框架MapKit 功能5:POI检索
    ================== 所属文集:【iOS】07 设备工具 ==================


    定位目录:

    官方框架CoreLocation目录:

    本文目录:


    1.0 简介


    2.0 属性方法

    CLLocationCoordinate2D:是一个用来表示经纬度的结构体

    关于经纬度:
    关于经纬度

    distanceFilter:每隔多少米定位一次

    desiredAccuracy:设置定位精确度


    3.0 requestLocation:单次定位请求,获取一次位置信息


    4.0 两种定位服务

    4.1 标准定位服务

    下面介绍下 CLLocation 对象:

    CLLocation 对象属性方法:

    主要方法:distanceFromLocation

    4.2 显著位置变化的定位服务


    代码示例:根据以上知识写一个"单次定位"的 demo

    编译环境:Xcode 8.0
    模拟器版本:iOS 10
    Swift版本:3.0

    【OC语言】
    #import "ViewController.h"
    #import <CoreLocation/CoreLocation.h>
    
    @interface ViewController () <CLLocationManagerDelegate> // 代理
    @property(nonatomic, strong) CLLocationManager *locationM; // 位置管理者
    @end
    
    @implementation ViewController
    
    #pragma mark - 懒加载对象,并在懒加载方法中进行部分初始化操作
    - (CLLocationManager *)locationM {
        if (!_locationM) {
            // 1. 创建位置管理者(需要强引用,否则一出现就会消失)强引用后,UI控件创建时会添加到subviews数组里,作用域结束时也不会释放
            _locationM = [[CLLocationManager alloc] init];
            
            // 2. 设置代理, 接收位置数据(其他方式:block、通知)
            _locationM.delegate = self;
            
            // 3. 请求用户授权 --- ios8之后才有(配置info.plist文件)
            
            //方法1:判断系统版本
            if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0){
                
                [_locationM requestAlwaysAuthorization];    //持续授权
                //[_locationM requestWhenInUseAuthorization];      //使用期间授权
            }
            
            //方法2:
            /*
             if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
             
             [_locationM requestAlwaysAuthorization];//持续授权
             [_locationM requestWhenInUseAuthorization];//使用期间授权
             }
             */
            
            // 4. 设置定位的过滤距离(单位:米), 表示用户位置移动了x米时调用对应的代理方法
            // 本次定位 与 上次定位 位置之间的物理距离 > 下面设置的数值时,就会通过代理,将当前位置告诉外界
            _locationM.distanceFilter = 500; //在用户位置改变500米时调用一次代理方法
            
            // 5. 设置定位的精确度 (单位:米),(定位精确度越高, 越耗电, 定位的速度越慢)
            // _locationM.desiredAccuracy = 100; // 当用户在100米范围内,系统会默认将100米范围内都当作一个位置
            _locationM.desiredAccuracy = kCLLocationAccuracyBest;
        }
        return _locationM;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    
    #pragma mark - 点击屏幕,开始更新用户位置
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        [self compareDistance]; //比较两点间的距离
        
        // 判断定位服务是否开启
        if ([CLLocationManager locationServicesEnabled]) {
            NSLog(@"已经开启定位服务,即将开始定位...");
    
    #pragma mark - 开始定位
            // 方法1:标准定位服务(使用位置管理器进行定位)
            // 开始更新位置信息(一旦调用了这个方法, 就会不断的刷新用户位置,然后告诉外界)
            // 以下代码默认只能在前台获取用户的位置信息,如果想要在后台获取用户的位置信息, 那么需要勾选后台模式 location updates
            // 小经验: 如果以后使用位置管理者这个对象, 实现某个服务,可以用startXX开始某个服务,stopXX停止某个服务
            // [self.locationM startUpdatingLocation];
            
            // 方法2:监听重大位置变化的服务(基于基站进行定位)(显著位置变化定位服务)
            //  [self.locationM startMonitoringSignificantLocationChanges];
            
            // 单次定位请求
            // 必须实现代理的定位失败方法
            // 不能与startUpdatingLocation方法同时使用
            [self.locationM requestLocation];
        } else {
            NSLog(@"没有开启定位服务");
        }
    }
    
    #pragma mark - 比较两点间的距离(直线距离)
    - (void)compareDistance {
        // 北京位置
        CLLocation *location1 = [[CLLocation alloc] initWithLatitude:39.26 longitude:115.25];
        // 上海位置
        CLLocation *location2 =[[CLLocation alloc] initWithLatitude:30.4 longitude:120.51];
        
        // 两个地方的距离(单位:米)
        CGFloat distance = [location2 distanceFromLocation:location1];
        
        NSLog(@"比较两个点的距离:%f", distance / 1000);
    }
    
    #pragma mark - 代理方法:当位置管理器获取到用户位置后,就会调用此方法
    // 参数: (manager:位置管理者) (locations: 位置对象数组)
    -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
        
        NSLog(@"位置信息:%@", locations);
        
        // 停止定位(代理方法一直调用,会非常耗电,除非特殊需求,如导航)
        // 只想获取一次用户位置信息,那么在获取到位置信息之后,停止更新用户的位置信息
        // 应用场景: 获取用户所在城市
        [manager stopUpdatingLocation];
    }
    
    -(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
        NSLog(@"定位失败");
    }
    
    #pragma mark - 代理方法:当用户授权状态发生变化时调用
    -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
        
        switch (status) {
                
            case kCLAuthorizationStatusNotDetermined:{
                NSLog(@"1.用户还未决定");
                break;
            }
            case kCLAuthorizationStatusRestricted:{
                NSLog(@"2.访问受限(苹果预留选项,暂时没用)");
                break;
            }
                // 定位关闭时 and 对此APP授权为never时调用
            case kCLAuthorizationStatusDenied:{
                // 定位是否可用(是否支持定位或者定位是否开启)
                if([CLLocationManager locationServicesEnabled]){
                    NSLog(@"3.定位服务是开启状态,需要手动授权,即将跳转设置界面");
                    // 在此处, 应该提醒用户给此应用授权, 并跳转到"设置"界面让用户进行授权在iOS8.0之后跳转到"设置"界面代码
                    NSURL *settingURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                    
                    if([[UIApplication sharedApplication] canOpenURL:settingURL]){
                        
                        //  [[UIApplication sharedApplication] openURL:settingURL]; // 方法过期
                        
                        [[UIApplication sharedApplication]openURL:settingURL options:nil completionHandler:^(BOOL success) {
                            NSLog(@"已经成功跳转到设置界面");
                        }];
                    }
                    else{
                        NSLog(@"定位关闭,不可用");
                    }
                    break;
                }
            case kCLAuthorizationStatusAuthorizedAlways:{
                NSLog(@"4.获取前后台定位授权");
                break;
            }
            case kCLAuthorizationStatusAuthorizedWhenInUse:{
                NSLog(@"5.获得前台定位授权");
                break;
            }
            default:
                break;
            }
        }
    }
    
    -(void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    
    @end
    
    

    打印结果:

    OC - 单次定位[11287:835597] 比较两个点的距离:1093.824596
    OC - 单次定位[11287:835597] 已经开启定位服务,即将开始定位...
    OC - 单次定位[11287:835597] 3.定位服务是开启状态,需要手动授权,即将跳转设置界面
    OC - 单次定位[11287:835597] 已经成功跳转到设置界面
    OC - 单次定位[11287:835597] 5.获得前台定位授权
    OC - 单次定位[11287:835597] 4.获取前后台定位授权
    OC - 单次定位[11287:835597] 位置信息:("<+39.78583000,+116.40641700> +/- 5.00m (speed -1.00 mps / course -1.00) @ 2016/9/21 U4e2dU56fdU6807U51c6U65f6U95f4 U4e0bU53485:19:01")
    
    【Swift 语言】
    import UIKit
    import CoreLocation
    
    class ViewController: UIViewController {
        
        // MARK: - 懒加载
        lazy var locationM : CLLocationManager = {
            
            // 1. 创建位置管理者(需要强引用,否则一出现就会消失)强引用后,UI控件创建时会添加到subviews数组里,作用域结束时也不会释放
            let locationM : CLLocationManager = CLLocationManager()
            
            // 2. 设置代理, 接收位置数据(其他方式:block、通知)
            locationM.delegate = self
            
            // 3. 请求用户授权 --- ios8之后才有(配置info.plist文件)
            // 判断系统版本
            if (Float(UIDevice.current.systemVersion)! >= 8.0){
                locationM.requestAlwaysAuthorization()// 前后台定位授权
                // locationM.requestWhenInUseAuthorization()  // 前台定位授权
            }
            
            // 4. 设置过滤距离
            // 如果当前位置, 距离上一次的位置之间的物理距离大于以下数值时, 就会通过代理, 将当前位置告诉外界
            locationM.distanceFilter = 100   // 每隔100 米定位一次
            
            // 5. 设置定位的精确度(定位精确度越高, 越耗电, 定位的速度越慢)
            locationM.desiredAccuracy = kCLLocationAccuracyBest
            
            return locationM
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
        }
        
        // MARK: - 点击屏幕,开始更新用户位置
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            
            // 方法1:标准定位服务(使用位置管理器进行定位)
            // 开始更新位置信息(一旦调用了这个方法, 就会不断的刷新用户位置, 然后告诉外界)
            // 以下代码默认只能在前台获取用户的位置信息, 如果想要在后台获取用户的位置信息, 那么需要勾选后台模式 location updates
            // 小经验: 如果以后使用位置管理者这个对象, 实现某个服务, 可以用startXX开始某个服务,stopXX停止某个服务
            // locationM.startUpdatingLocation()
            
            // 方法2:监听重大位置变化的服务(基于基站进行定位)(显著位置变化定位服务)
            // locationManager.startMonitoringSignificantLocationChanges()
            
            // 单次定位请求
            // 必须实现代理的定位失败方法
            // 不能与startUpdatingLocation方法同时使用
            locationM.requestLocation()
        }
        
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }
    
    // 类扩展(CLLocationManager的代理方法)
    extension ViewController: CLLocationManagerDelegate {
        
        // 代理方法:当位置管理器获取到用户位置后,就会调用此方法
        // 参数: (manager:位置管理者) (locations: 位置对象数组)
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            
            print("位置信息:%@", locations)
            
            // 停止定位(代理方法一直调用,会非常耗电,除非特殊需求,如导航)
            // 只想获取一次用户位置信息,那么在获取到位置信息之后,停止更新用户的位置信息
            // 应用场景: 获取用户所在城市
            manager.stopUpdatingLocation()
        }
    
        func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
            print("定位失败--(error.localizedDescription)")
        }
        
        // 代理方法:当用户的定位授权状态发生变化时调用
        func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
            
            switch status {
                
            case CLAuthorizationStatus.notDetermined:
                print("1.用户还未决定定")
            case CLAuthorizationStatus.restricted:
                print("2.访问受限(苹果预留选项,暂时没用)")
            // 定位关闭时 and 对此APP授权为never时调用
            case CLAuthorizationStatus.denied:
                // 定位是否可用(是否支持定位或者定位是否开启)
                if (CLLocationManager.locationServicesEnabled()){
                    print("3.定位服务是开启状态,需要手动授权,即将跳转设置界面")
                    
                    // 在此处, 应该提醒用户给此应用授权, 并跳转到"设置"界面让用户进行授权在iOS8.0之后跳转到"设置"界面代码
                    var settingURL:URL?
                    
                    if (Float(UIDevice.current.systemVersion)! >= 8.0){
                        settingURL = URL(string: UIApplicationOpenSettingsURLString)
                    }else{
                        // 设置app scheme
                        settingURL = URL(string: "prefs:root=LOCATION_SERVICES")
                    }
                    
                    if (UIApplication.shared.canOpenURL(settingURL!)){
                        UIApplication.shared.openURL(settingURL!)
                        print("已经成功跳转到设置界面")
                    }
                }else{
                    print("定位关闭,不可用")
                }
            case CLAuthorizationStatus.authorizedAlways:
                print("4.获取前后台定位授权")
            case CLAuthorizationStatus.authorizedWhenInUse:
                print("5.获得前台定位授权")
            }
        }
    }
    

    打印结果:

    3.定位服务是开启状态,需要手动授权,即将跳转设置界面
    已经成功跳转到设置界面
    5.获得前台定位授权
    4.获取前后台定位授权
    位置信息:%@ [<+39.78583000,+116.40641700> +/- 5.00m (speed -1.00 mps / course -1.00) @ 2016/9/21 中国标准时间 下午5:59:01]
    
    


    本文源码 Demo 详见 Github
    https://github.com/shorfng/iOS_7.0_Device-Tools


    作者:蓝田(Loto)
    【作品发布平台】

    简书
    博客园
    Gitbook(如果觉得文章太长,请阅读此平台发布的文章)

    【代码托管平台】

    Github

    【如有疑问,请通过以下方式交流】

    评论区回复
    发送邮件shorfng@126.com


    本文版权归作者和本网站共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。


    如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
    • 支付宝扫一扫 向我打赏

    • 你也可以微信 向我打赏

  • 相关阅读:
    nested exception is java.lang.IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}
    Thrift Expected protocol id ffffff82 but got 0
    idea
    Activity工作流入门之HelloWorld
    Thrift 入门之helloWorld
    Thrift入门之mac下的安装流程
    netty的解码器与粘包和拆包
    java反射(一)
    使用Spring报错:No default constructor found;
    jpa关联映射(一)
  • 原文地址:https://www.cnblogs.com/shorfng/p/6566330.html
Copyright © 2011-2022 走看看