美文网首页
iOS定位相关功能开发经验总结

iOS定位相关功能开发经验总结

作者: Dungeon | 来源:发表于2017-08-23 14:41 被阅读0次

1. Core Location 与 MapKit

1.1 Core Location —— 用于获取设备当前地理位置信息与朝向

  • 初始化与获取授权
    后台定位需要在Info.plist中添加对应键值

    Info.plist

    工厂环境下在组件配置中写入

    <ios>
      <meta-datas>
        <meta-data xpath="//plist/dict" key="UIBackgroundModes" type="array" file="/ComponentAppBase/Info.plist">
          <![CDATA[
             <string>location</string>
          ]]>
        </meta-data>
      </meta-datas>
    </ios>
    

    初始化

    self.locationManager = [[CLLocationManager] alloc] init];
    self.locationManager.delegate = self;
    self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    self.locationManager.distanceFilter = 10;
    self.locationManager.pausesLocationUpdatesAutomatically = NO;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0) {
        self.locationManager.allowsBackgroundLocationUpdates = YES;
    }
    

    CLLocationManager初始化后,以及app的授权状态改变时,locationManager: didChangeAuthorizationStatus:会被调用。

    - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            if (status == kCLAuthorizationStatusNotDetermined) {
                [self.locationManager requestAlwaysAuthorization];
            } else if (status != kCLAuthorizationStatusRestricted && status != kCLAuthorizationStatusDenied) {
                [self.locationManager startUpdatingLocation]; //开始获取GPS位置
                if ([CLLocationManager headingAvailable]) {
                    [self.locationManager startUpdatingHeading]; //开始获取设备朝向
                }
            } else {
                //无授权处理
            }
        }
    }
    
    typedef NS_ENUM(int, CLAuthorizationStatus) {
      kCLAuthorizationStatusNotDetermined = 0,
      kCLAuthorizationStatusRestricted,
      kCLAuthorizationStatusDenied,
      kCLAuthorizationStatusAuthorizedAlways,
      kCLAuthorizationStatusAuthorizedWhenInUse,
      kCLAuthorizationStatusAuthorized //只在macOS下使用
    };
    
  • 获得位置与朝向 CLLocationManagerDelegate
    - (void)locationManager:(CLLocationManager *)manager 
          didUpdateLocations:(NSArray<CLLocation *> *)locations {
    }
    
    - (void)locationManager:(CLLocationManager *)manager
          didUpdateHeading:(CLHeading *)newHeading {
    }
    
    这里获得的经纬度属于WGS84坐标系,而中国使用的是加密后的GCJ02坐标系,需要进行换算,具体方法参见这里

  • Region Monitoring 监测用户进入或离开特定地理区域
    在iOS中,系统自动对用户的区域变化进行监测,在用户进入或离开我们定义的区域时,相应代理方法会执行。如果事件发生时我们的app并没有运行,系统会在后台唤醒我们的app。可以通过launchOptions字典中的UIApplicationLaunchOptionsKey来判断我们的app是否是由Region Monitoring唤醒的。同一个app最多只能同时监测20个region。


    使用步骤
    1. 创建 CLCircularRegion 对像,用于确定监测的区域。只能为圆形,官方不支持多边形区域。
    2. 注册区域,iOS会持续监测区域,直到我们的代码中停止区域监测,或者手机重启。
      [self.locationManager startMonitoringForRegion:region];
      
    3. 实现 locationManager:didEnterRegion:locationManager:didExitRegion: 代理方法
    4. AppDelegate.m文件的application:didFinishLaunchingWithOptions:函数中判断程序是否由Region Monitoring唤醒,如果是,进行处理。

  • Geocoding 坐标与实际街道名之间的转换
    • 前一个请求未完成时,后续请求会失败。

    • 苹果服务器会对每个app的请求频率做限制,超过限制之后的请求会失败。

    • 使用的坐标为地图提供的坐标系

    • 坐标转街道

      self.geocoder = [CLGeocoder new];
      [self.geocoder reverseGeocodeLocation:location 
                        completionHandler:^(NSArray *placemarks, NSError *error) {
      }];
      
    系统进行异步网络请求,completionHandler会在主线程执行。
    • 街道转坐标
    - (void)geocodeAddressDictionary:(NSDictionary *)addressDictionary completionHandler:(CLGeocodeCompletionHandler)completionHandler;
    - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
    - (void)geocodeAddressString:(NSString *)addressString inRegion:(nullable CLRegion *)region completionHandler:(CLGeocodeCompletionHandler)completionHandler;
    

1.2 MapKit —— 在app中显示地图,在地图上显示景点,添加标记(Annotation),获取导航路径等

  • MKMapViewUIView的子类)
    • 不需要定位用户位置时

      MKMapView *mapView = [MKMapView new];
      mapView.delegate = self;
      [self.view addSubview:mapView];
      [mapView mas_makeConstraints:^(MASConstraintMaker *make) {
          make.edges.equalTo(self.view);
      }];
      
    • 需要定位用户位置时

      1. 创建CLLocationManager申请权限
      2. 在地图上显示用户位置
        self.mapView.showsUserLocation = YES;
        
        也可以通过实现MKMapViewDelegate的代理方法获取用户坐标
        - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
            static BOOL didBeginInitialize = NO;
            if (!didBeginInitialize) {
                didBeginInitialize = YES;
                MKCoordinateSpan span = MKCoordinateSpanMake(0.02, 0.02);
                MKCoordinateRegion region = MKCoordinateRegionMake(userLocation.location.coordinate, span);
                [self.mapView setRegion:region animated:NO];
            }
        }
        
  • MKAnnotationMKAnnotationView

    • 什么是Annotation


    • 添加方法

      MKPointAnnotation *annotation = [MKPointAnnotation new];
      annotation.title = @"title";
      annotation.coordinate = CLLocationCoordinate2DMake(latitude,longitude);
      [self.mapView addAnnotation:annotation];
      
      点击后的气泡中显示title
    • 如何定制

      - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
          if (annotation == self.mapView.userLocation) {
            //用户位置view
            MKAnnotationView *annotationView = [[MKAnnotationView  alloc] initWithAnnotation:annotation reuseIdentifier:nil];
            // ...
            return annotationView;
          } else { 
            //其他Annotation
          }
      }
      

      返回nil则会使用默认样式


      自定义的annotationView
    • 修改已生成的annotationView,以及动效编写

      • annotationannotationView一一对应,修改annotation的属性值,对应的annotationView会有相应变化。
      • 系统会自动缓存已创建的annotationView,手动调用
        [self.mapView viewForAnnotation:annotation]时,如果annotation对应的annotationView已创建过,则不会创建新的annotationView,而是返回已缓存的。
      [self.mapView layoutIfNeeded];
      MKAnnotationView *annotationView = [self.mapView viewForAnnotation:annotation];
      // ...相关视图处理代码
      [UIView animateWithDuration:0.3 animations:^{
          [self.mapView layoutIfNeeded];
      }];
      
  • 区域标记 MKOverlayMKOverlayRenderer

    圆形overlay
    多边形overlay

    圆形区域

    MKCircle *circle = [MKCircle circleWithCenterCoordinate:coordinate radius:1000];
    [self.mapView addOverlay:circle level:MKOverlayLevelAboveLabels];
    

    多边形区域

    CLLocationCoordinate2D *mapPointArray = (CLLocationCoordinate2D *)malloc(sizeof(CLLocationCoordinate2D) * count);
    for (NSInteger i = 0; i < N; i ++) {
        mapPointArray[i] = CLLocationCoordinate2DMake(latitude, longitude);
    }
    MKPolygon *polygon = [MKPolygon polygonWithCoordinates:mapPointArray count:count];
    [self.mapView addOverlay:polygon level:MKOverlayLevelAboveLabels];
    // 记得释放mapPointArray
    

    区域层级ENUM

    typedef NS_ENUM(NSInteger, MKOverlayLevel) {
      MKOverlayLevelAboveRoads = 0, // note that labels include shields and point of interest icons.
      MKOverlayLevelAboveLabels
    } NS_ENUM_AVAILABLE(10_9, 7_0) __TVOS_AVAILABLE(9_2) __WATCHOS_PROHIBITED;
    

    代理中返回对应视图

    - (MKOverlayRenderer *)mapView:(MKMapView *)map rendererForOverlay:(nonnull id<MKOverlay>)overlay {
        if ([overlay isKindOfClass:[MKCircle class]]) {
            MKCircleRenderer *circleRenderer = [[MKCircleRenderer alloc] initWithOverlay:overlay];
            circleRenderer.strokeColor = [[UIColor apf_colorWithHexString:@"ff9d2a"] colorWithAlphaComponent:0.3];
            circleRenderer.lineWidth = 3;
            circleRenderer.fillColor = [[LBSSLHelper colorWithKey:@"color_19"] colorWithAlphaComponent:0.25];
            return circleRenderer;
          
        } else if ([overlay isKindOfClass:[MKPolygon class]]) {
            MKPolygonRenderer *polygonRenderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay];
            polygonRenderer.strokeColor = [[UIColor apf_colorWithHexString:@"ff9d2a"] colorWithAlphaComponent:0.3];
            polygonRenderer.lineWidth = 3;
            polygonRenderer.fillColor = [[LBSSLHelper colorWithKey:@"color_19"] colorWithAlphaComponent:0.25];
            return polygonRenderer;
        }
    }
    
  • 两点间路线 MKDirectionsRequest

    MKDirectionsRequest *directionsRequest = [MKDirectionsRequest new];
    [directionsRequest setTransportType:MKDirectionsTransportTypeWalking];
    [directionsRequest setSource:[[MKMapItem alloc] initWithPlacemark:originPlacemark]];
    [directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:destinationPlacemark]];
    [directionsRequest setRequestsAlternateRoutes:NO];
    MKDirections *direction = [[MKDirections alloc] initWithRequest:directionsRequest];
    
    [direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse * _Nullable response, NSError * _Nullable error) {
        if (!error) {
            //response中还有换乘建议、预计耗时等其他信息
            MKRoute *route = [response.routes firstObject];
            if (route) {
                [self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveLabels];
            }
        }
    }];
    
    - (MKOverlayRenderer *)mapView:(MKMapView *)map rendererForOverlay:(nonnull id<MKOverlay>)overlay {
        if ([overlay isKindOfClass:[MKPolyline class]]) {
            MKPolylineRenderer *polylineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
            polylineRenderer.lineWidth = 4;
            polylineRenderer.strokeColor = [LBSSLHelper colorWithKey:@"color_14"];
            return polylineRenderer;
        }
    }
    

2. 遇到的问题

  1. 单元测试报错



    解决方法:设置单元测试的环境变量,跳过属性设置。



  2. 工厂打包时的权限问题
    解决方法:使用子组件
    <property type="bool" name="showLocationShare" desc_true="需要位置分享" desc_false="不需要位置分享" displayName="是否需要位置分享" value="false">
      <dependency>
        <component namespace="com.nd.social" name="lbs-share-location"/>
      </dependency>
    </property>
    
  3. 请求后台运行权限上架被拒
    解决方法:与苹果审核人员沟通。

相关文章

  • iOS定位相关功能开发经验总结

    1. Core Location 与 MapKit 1.1 Core Location —— 用于获取设备当前地理...

  • iOS开发经验总结

    iOS开发经验总结 iOS开发经验总结

  • iOS开发经验

    多年iOS开发经验总结(一) 多年iOS开发经验总结(二) 多年iOS开发经验总结(三)

  • 多年iOS开发经验总结

    多年iOS开发经验总结 多年iOS开发经验总结

  • 多年iOS开发经验总结汇总

    iOS多年开发经验总结

  • 目录索引

    开发总结1、Java · 后端开发相关总结2、Web应用系统设计开发经验总结3、常规问题定位不完全手册 系统设计1...

  • iOS开发之定位

    iOS开发之定位 iOS开发之定位

  • CoreLocation定位

    定位 -在iOS开发中想要加入定位和地图功能,那么必须基于CoreLocation和MapKit2个框架进行开发-...

  • 百度地图之定位

    iOS中三种定位方式 ioS开发之CoreLocation(GPS定位) iOS自带的GPS 定位 iOS开发 C...

  • iOS开发

    多年iOS开发经验总结(一) 作者:杂物无尘 多年iOS开发经验总结(二) 作者:杂物无尘常看温故而知新,很多小技...

网友评论

      本文标题:iOS定位相关功能开发经验总结

      本文链接:https://www.haomeiwen.com/subject/wlchdxtx.html