iOS百度地图SDK之实时绘制轨迹(后台仍执行)

首先,对于百度地图SDK的配置和环境搭建就不做说明,需要的人可以博客中另一篇文章看 《iOS百度地图SDK基本使用》 ,本文的重点在于实现实时绘制轨迹的功能,并且对细节进行处理和优化

1、在AppDelegate.m文件中
[objc]  view plain copy
  1. #import "AppDelegate.h"  
  2. // BMapKit.h代表导入了所有的头文件  
  3. #import <BaiduMapAPI/BMapKit.h>  
  4. @interface AppDelegate ()<BMKGeneralDelegate>  
  5. {  
  6.     BMKMapManager *mapManager;  
  7. }  
  8. @end  
[objc]  view plain copy
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // 要使用地图,首先需要初始化和启动BMKMapManager  
  3.     mapManager = [[BMKMapManager alloc]init];  
  4.     // 填入验证码, 如需要使用网络和授权验证服务,则需要设置代理信息  
  5.     BOOL ret = [mapManager start:@"在这里填入的是密钥中的安全码" generalDelegate:nil];  
  6.     if (!ret) {  
  7.         NSLog(@"地图管理器初始化失败");  
  8.     }  
  9.     else{  
  10.         NSLog(@"初始化成功");  
  11.     }  
  12.     return YES;  
  13. }  


2、在ViewController.m文件中
[objc]  view plain copy
  1. #import "ViewController.h"  
  2. #import <BaiduMapAPI/BMapKit.h>  
  3.   
  4. #define normalLocationTag 1  
  5. #define compassLocationTag 2  
  6.   
  7. @interface ViewController () <BMKLocationServiceDelegate , BMKMapViewDelegate>  
  8. {  
  9.     BMKMapView *mapView;  
  10.     BMKLocationService *locationService;  
  11.     // 用于手动验证  
  12.     CLLocationManager *locationManager;  
  13.     // 用于记录经过的点  
  14.     NSMutableArray *locationPoint;  
  15.     // 在地图上绘制的折线  
  16.     BMKPolyline *routeLine;  
  17.     // 中间变量->location类型(地理位置)  
  18.     CLLocation *currentLocation;  
  19. }  
  20. @end  

在viewDidLoad中将两个初始化体现出来
[objc]  view plain copy
  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.       
  4.     // 1、所有的初始化操作  
  5.     [self initObjects];  
  6.       
  7.     // 2、所有的地图初始操作  
  8.     [self operationForMap];  
  9. }  

初始化操作的封装后的方法
[objc]  view plain copy
  1. - (void)initObjects  
  2. {  
  3.     // 初始化mapView  
  4.     mapView = [[BMKMapView alloc]initWithFrame:CGRectMake(0120self.view.bounds.size.widthself.view.bounds.size.height)];  
  5.     // 初始化locationService  
  6.     locationService = [[BMKLocationService alloc]init];  
  7. }  

对地图的各个参数进行操作封装后的方法
[objc]  view plain copy
  1. - (void)operationForMap  
  2. {  
  3.     // 设置过滤距离,更新的最小间隔距离  
  4.     [BMKLocationService setLocationDistanceFilter:6.0f];  
  5.       
  6.     // 设置定位精度模式  
  7.     /* tips: 
  8.              以前使用了kCLLocationAccuracyBest--> 表示在使用电池的最高精度 
  9.              现在使用了kCLLocationAccuracyBestForNavigation--> 表示在外接电源的时候的最高精度(有些在AppStore上架的APP由于过度依赖于高精度的定位,所以采用了这种耗电的定位设置) 
  10.      */  
  11.     [BMKLocationService setLocationDesiredAccuracy:kCLLocationAccuracyBestForNavigation];  
  12.       
  13.     // 设置地图类型  
  14.     mapView.mapType = BMKMapTypeSatellite;  
  15.       
  16.     // 设置是否需要热力图显示  
  17.     [mapView setBaiduHeatMapEnabled:NO];  
  18.       
  19.     // 设置是否允许旋转地图  
  20.     mapView.rotateEnabled = YES;<span style="white-space:pre">                                                </span>  
  21.     // .....对于地图还有很多设置,这里不一一列举,需要的话可以在文档中查到<span style="white-space:pre">                             </span>  
  22.     [self.view addSubview:mapView];  
  23. }  

[objc]  view plain copy
  1. - (void)operationForLocation:(BMKUserLocation *)userLocation  
  2. {  
  3.     // 1、检查移动的距离,移除不合理的点  
  4.     if (locationPoint.count > 0) {  
  5.         CLLocationDistance distance = [userLocation.location distanceFromLocation:currentLocation];  
  6.         if (distance < 5)  
  7.             return;  
  8.     }  
  9.       
  10.     // 2、初始化坐标点数组  
  11.     if (nil == locationPoint) {  
  12.         locationPoint = [[NSMutableArray alloc] init];  
  13.     }  
  14.       
  15.     // 3、将合理的点添加到数组  
  16.     [locationPoint addObject:userLocation.location];  
  17.       
  18.     // 4、作为前一个坐标位置辅助操作  
  19.     currentLocation = userLocation.location;  
  20.       
  21.     // 5、开始画线  
  22.     [self configureRoutes];  
  23.       
  24.     // 6、实时更新用户位子  
  25.     [mapView updateLocationData:userLocation];  
  26. }  

[objc]  view plain copy
  1. #pragma mark - 点击两个button触发的事件  
  2. - (IBAction)startLocation:(UIButton *)button  
  3. {  
  4.     // 由于IOS8中定位的授权机制改变 需要进行手动授权(导致程序无法进行定位的主要原因)  
  5.     if ([[UIDevice currentDevice].systemVersion floatValue] >= 8) {  
  6.         locationManager = [[CLLocationManager alloc] init];  
  7.         [locationManager requestAlwaysAuthorization];  
  8.         [locationManager requestWhenInUseAuthorization];  
  9.     }  
  10.     // 开启用户定位  
  11.     [locationService startUserLocationService];  
  12.       
  13.     // 开始先关闭地位图层(也就是定位的小圆点)-->用户体验问题  
  14.     mapView.showsUserLocation = NO;  
  15.       
  16.     // 根据所点击的button来开启不同的定位模式  
  17.     if (button.tag == normalLocationTag) {  
  18.         mapView.userTrackingMode = BMKUserTrackingModeFollow;  
  19.     }else if(button.tag == compassLocationTag) {  
  20.         mapView.userTrackingMode = BMKUserTrackingModeFollowWithHeading;  
  21.     }  
  22.       
  23.     mapView.showsUserLocation = YES;  
  24.       
  25.     // 1、通过比例调试地图的显示  
  26. #if 1  
  27.     [mapView setZoomEnabled:YES];  
  28.     mapView.zoomLevel = 19;// 级别是 3-19  
  29. #endif  
  30.       
  31. #if 0  
  32.     // 2、通过范围调试地图的显示  
  33.     BMKCoordinateRegion adjustRegion = [mapView regionThatFits:BMKCoordinateRegionMake(locationService.userLocation.location.coordinate, BMKCoordinateSpanMake(0.03f,0.03f))];  
  34.     [mapView setRegion:adjustRegion animated:YES];  
  35. #endif  
  36. }  



[objc]  view plain copy
  1. #pragma mark - 视图的出现和消失(在其中设置代理和取消代理,优化内存管理)  
  2. - (void)viewWillAppear:(BOOL)animated  
  3. {  
  4.     [mapView viewWillAppear];  
  5.     mapView.delegate = self;  
  6.     locationService.delegate = self;  
  7. }  
  8.   
  9. - (void)viewWillDisappear:(BOOL)animated  
  10. {  
  11.     [mapView viewWillDisappear];  
  12.     // 一般情况下都需要在这里关闭掉代理,但是由于本程序需要在后台继续绘制轨迹,因为对应的代理方法是绘制轨迹,所以继续设置代理  
  13.     mapView.delegate = self;  
  14.     locationService.delegate = self;  
  15. }  


[objc]  view plain copy
  1. #pragma mark - mapView的协议  
  2. - (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id<BMKOverlay>)overlay  
  3. {  
  4.     if ([overlay isKindOfClass:[BMKPolyline class]]) {  
  5.         BMKPolylineView *polylineView = [[BMKPolylineView alloc]initWithPolyline:overlay];  
  6.         // 设置划出的轨迹的基本属性-->也是使得定位看起来更加准确的主要原因  
  7.         polylineView.strokeColor = [[UIColor blueColor]colorWithAlphaComponent:0.5];  
  8.         polylineView.fillColor = [[UIColor blueColor]colorWithAlphaComponent:0.8];  
  9.         polylineView.lineWidth = 6.0;  
  10.         return polylineView;  
  11.     }  
  12.     return nil;  
  13. }  

[objc]  view plain copy
  1. #pragma mark - 绘制轨迹  
  2. -(void)configureRoutes  
  3. {  
  4.     // 1、分配内存空间给存储经过点的数组  
  5.     BMKMapPoint* pointArray = (BMKMapPoint *)malloc(sizeof(CLLocationCoordinate2D) * locationPoint.count);  
  6.       
  7.     // 2、创建坐标点并添加到数组中  
  8.     for(int idx = 0; idx < locationPoint.count; idx++)  
  9.     {  
  10.         CLLocation *location = [locationPoint objectAtIndex:idx];  
  11.         CLLocationDegrees latitude  = location.coordinate.latitude;  
  12.         CLLocationDegrees longitude = location.coordinate.longitude;  
  13.         CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);  
  14.         BMKMapPoint point = BMKMapPointForCoordinate(coordinate);  
  15.         pointArray[idx] = point;  
  16.     }  
  17.     // 3、防止重复绘制  
  18.     if (routeLine) {  
  19.         //在地图上移除已有的坐标点  
  20.         [mapView removeOverlay:routeLine];  
  21.     }  
  22.       
  23.     // 4、画线  
  24.     routeLine = [BMKPolyline polylineWithPoints:pointArray count:locationPoint.count];  
  25.       
  26.     // 5、将折线(覆盖)添加到地图  
  27.     if (nil != routeLine) {  
  28.         [mapView addOverlay:routeLine];  
  29.     }  
  30.       
  31.     // 6、清楚分配的内存  
  32.     free(pointArray);  
  33. }  

[objc]  view plain copy
  1. #pragma mark - 更新用户位置时所调用的三种方法  
  2. // 更新位置  
  3. - (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation  
  4. {  
  5.     // 说明:由于开启了“无限后台”的外挂模式(^-^)所以可以直接写操作代码,然后系统默认在任何情况执行,但是为了已读,规划代码如下  
  6.     // 1、活跃状态  
  7.     if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {  
  8.         [self operationForLocation:userLocation];  
  9.     }else if([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)  
  10.     // 2、后台模式  
  11.     {  
  12.         [self operationForLocation:userLocation];  
  13.     }  
  14.     // 3、不活跃模式  
  15.     else if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)  
  16.     {  
  17.         [self operationForLocation:userLocation];  
  18.     }  
  19. }  
  20.   
  21. // 更新方向  
  22. - (void)didUpdateUserHeading:(BMKUserLocation *)userLocation  
  23. {  
  24.     [mapView updateLocationData:userLocation];  
  25. }  
  26.   
  27. // 定位失败了会调用  
  28. - (void)didFailToLocateUserWithError:(NSError *)error  
  29. {  
  30.     NSLog(@"did failed locate,error is %@",[error localizedDescription]);  
  31. }  

到这里,代码就结束了,在viewWillDisappear中,依然没有关掉代理,是想让程序在锁屏后,或者是点击home键返回到桌面后仍然执行轨迹的绘制,但是仅仅设置代理是不够的,在没有进行配置的情况下,iOS系统最多可以让一个APP在有5秒钟的时间,用来进行保存和清理资源等任务。如果应用调用了UIApplication的beginBackgroundTaskWithExpirationHandler的方法,可以让APP在后台有10分组的运行时间,用来清理本地的缓存或者是进行数据的处理。超过了时间,APP便会被强制挂起

但是,就拿本例中所涉及的实时绘制轨迹来说,比如要开发一款跑步时绘制自己轨迹的应用,总不能跑步的时候都要将手机屏幕开着,并且还不能切换到其他地方,这样无疑增加了大量的电量消耗,所以,苹果也是为以下的几种提供了所谓的“无限后台”的外挂模式

1、Audio(音频播放)
2、Location/GPS(定位的实时更新)
3、Newsstand(杂志下载)
4、VoIP(网络电话)

所以,对于本例来说,苹果是允许启动外挂模式的,下面说明应该怎么配置这种模式

在info.plist文件中添加这样一项,Required background modes,然后这一项默认是数组类型,需要再在这项中添加一个item,默认生成了一项key为item0,接着将这个item0的value变为App registers for location updates
下面给出图例示范:


但是有人会想,那这样的话每个程序都可以开外挂了咯?话虽如此,但是在AppStore审核的时候,如果在plist文件中配置了这样的属性,那么AppStore会检测应用程序是否属于这种类型,如果不是的话,那么这样的APP就会被拒绝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值