LocationTracker.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //
  2. // LocationTracker.m
  3. // Location
  4. //
  5. // Created by Rick
  6. // Copyright (c) 2014 Location All rights reserved.
  7. //
  8. #import "LocationTracker.h"
  9. #define LATITUDE @"latitude"
  10. #define LONGITUDE @"longitude"
  11. #define ACCURACY @"theAccuracy"
  12. #define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
  13. @implementation LocationTracker
  14. + (CLLocationManager *)sharedLocationManager {
  15. static CLLocationManager *_locationManager;
  16. @synchronized(self) {
  17. if (_locationManager == nil) {
  18. _locationManager = [[CLLocationManager alloc] init];
  19. _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
  20. _locationManager.pausesLocationUpdatesAutomatically = NO;
  21. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
  22. //[_locationManager requestWhenInUseAuthorization];//?只在前台开启定位
  23. [_locationManager requestAlwaysAuthorization];//?在后台也可定位
  24. }
  25. // 5.iOS9新特性:将允许出现这种场景:同一app中多个location manager:一些只能在前台定位,另一些可在后台定位(并可随时禁止其后台定位)。
  26. if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
  27. _locationManager.allowsBackgroundLocationUpdates = YES;
  28. }
  29. }
  30. }
  31. return _locationManager;
  32. }
  33. - (id)init {
  34. if (self = [super init]) {
  35. //Get the share model and also initialize myLocationArray
  36. self.shareModel = [LocationShareModel sharedModel];
  37. self.shareModel.myLocationArray = [NSMutableArray array];
  38. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
  39. }
  40. return self;
  41. }
  42. -(void)applicationEnterBackground{
  43. CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
  44. locationManager.delegate = self;
  45. locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
  46. locationManager.distanceFilter = kCLDistanceFilterNone;//不需要移动都可以刷新
  47. if(IS_OS_8_OR_LATER) {
  48. [locationManager requestAlwaysAuthorization];
  49. }
  50. [locationManager startUpdatingLocation];
  51. //Use the BackgroundTaskManager to manage all the background Task
  52. self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
  53. [self.shareModel.bgTask beginNewBackgroundTask];
  54. }
  55. - (void) restartLocationUpdates
  56. {
  57. //NSLog(@"restartLocationUpdates");
  58. if (self.shareModel.timer) {
  59. [self.shareModel.timer invalidate];
  60. self.shareModel.timer = nil;
  61. }
  62. CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
  63. locationManager.delegate = self;
  64. locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
  65. locationManager.distanceFilter = kCLDistanceFilterNone;//不需要移动都可以刷新
  66. if(IS_OS_8_OR_LATER) {
  67. [locationManager requestAlwaysAuthorization];
  68. }
  69. [locationManager startUpdatingLocation];
  70. }
  71. - (void)startLocationTracking {
  72. //NSLog(@"startLocationTracking");
  73. if ([CLLocationManager locationServicesEnabled] == NO) {
  74. //NSLog(@"locationServicesEnabled false");
  75. [RQ_SHARE_FUNCTION showAlertWithTitle:@"启用位置服务" message:@"您必须启用位置服务(设置-隐私-定位服务-极速驾培-始终)" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil];
  76. } else {
  77. CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];
  78. if(authorizationStatus == kCLAuthorizationStatusDenied || authorizationStatus == kCLAuthorizationStatusRestricted){
  79. //NSLog(@"authorizationStatus failed");
  80. } else {
  81. //NSLog(@"authorizationStatus authorized");
  82. CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
  83. locationManager.delegate = self;
  84. locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
  85. locationManager.distanceFilter = kCLDistanceFilterNone;//不需要移动都可以刷新
  86. if(IS_OS_8_OR_LATER) {
  87. [locationManager requestAlwaysAuthorization];
  88. }
  89. [locationManager startUpdatingLocation];
  90. }
  91. }
  92. }
  93. - (void)stopLocationTracking {
  94. //NSLog(@"stopLocationTracking");
  95. if (self.shareModel.timer) {
  96. [self.shareModel.timer invalidate];
  97. self.shareModel.timer = nil;
  98. }
  99. CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
  100. [locationManager stopUpdatingLocation];
  101. }
  102. #pragma mark - CLLocationManagerDelegate Methods
  103. -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
  104. //NSLog(@"locationManager didUpdateLocations");
  105. for(int i=0;i<locations.count;i++){
  106. CLLocation * newLocation = [locations objectAtIndex:i];
  107. CLLocationCoordinate2D theLocation = newLocation.coordinate;
  108. CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
  109. NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
  110. if (locationAge > 30.0)
  111. {
  112. continue;
  113. }
  114. //Select only valid location and also location with good accuracy
  115. if(newLocation!=nil&&theAccuracy>0
  116. &&theAccuracy<2000
  117. &&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){
  118. self.myLastLocation = theLocation;
  119. self.myLastLocationAccuracy= theAccuracy;
  120. NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
  121. [dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@"latitude"];
  122. [dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@"longitude"];
  123. [dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@"theAccuracy"];
  124. //Add the vallid location with good accuracy into an array
  125. //Every 1 minute, I will select the best location based on accuracy and send to server
  126. [self.shareModel.myLocationArray addObject:dict];
  127. }
  128. }
  129. //If the timer still valid, return it (Will not run the code below)
  130. if (self.shareModel.timer) {
  131. return;
  132. }
  133. self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
  134. [self.shareModel.bgTask beginNewBackgroundTask];
  135. //Restart the locationMaanger after 1 minute
  136. self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self
  137. selector:@selector(restartLocationUpdates)
  138. userInfo:nil
  139. repeats:NO];
  140. //Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
  141. //The location manager will only operate for 10 seconds to save battery
  142. if (self.shareModel.delay10Seconds) {
  143. [self.shareModel.delay10Seconds invalidate];
  144. self.shareModel.delay10Seconds = nil;
  145. }
  146. self.shareModel.delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target:self
  147. selector:@selector(stopLocationDelayBy10Seconds)
  148. userInfo:nil
  149. repeats:NO];
  150. }
  151. //Stop the locationManager
  152. -(void)stopLocationDelayBy10Seconds{
  153. CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
  154. [locationManager stopUpdatingLocation];
  155. //NSLog(@"locationManager stop Updating after 10 seconds");
  156. }
  157. - (void)locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error
  158. {
  159. // NSLog(@"locationManager error:%@",error);
  160. switch([error code])
  161. {
  162. case kCLErrorNetwork: // general, network-related error
  163. {
  164. [RQ_SHARE_FUNCTION showAlertWithTitle:@"网络错误" message:@"请检查网络连接" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil];
  165. }
  166. break;
  167. case kCLErrorDenied:{
  168. [RQ_SHARE_FUNCTION showAlertWithTitle:@"启用位置服务" message:@"您必须启用位置服务(设置-隐私-定位服务-极速驾培-始终)" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil];
  169. }
  170. break;
  171. default:
  172. {
  173. }
  174. break;
  175. }
  176. }
  177. //Send the location to Server
  178. - (void)updateLocationToServer {
  179. //NSLog(@"updateLocationToServer");
  180. // Find the best location from the array based on accuracy
  181. NSMutableDictionary * myBestLocation = [[NSMutableDictionary alloc]init];
  182. for(int i=0;i<self.shareModel.myLocationArray.count;i++){
  183. NSMutableDictionary * currentLocation = [self.shareModel.myLocationArray objectAtIndex:i];
  184. if(i==0)
  185. myBestLocation = currentLocation;
  186. else{
  187. if([[currentLocation objectForKey:ACCURACY]floatValue]<=[[myBestLocation objectForKey:ACCURACY]floatValue]){
  188. myBestLocation = currentLocation;
  189. }
  190. }
  191. }
  192. //NSLog(@"My Best location:%@",myBestLocation);
  193. //If the array is 0, get the last location
  194. //Sometimes due to network issue or unknown reason, you could not get the location during that period, the best you can do is sending the last known location to the server
  195. if(self.shareModel.myLocationArray.count==0)
  196. {
  197. //NSLog(@"Unable to get location, use the last known location");
  198. self.myLocation=self.myLastLocation;
  199. self.myLocationAccuracy=self.myLastLocationAccuracy;
  200. }else{
  201. CLLocationCoordinate2D theBestLocation;
  202. theBestLocation.latitude =[[myBestLocation objectForKey:LATITUDE]floatValue];
  203. theBestLocation.longitude =[[myBestLocation objectForKey:LONGITUDE]floatValue];
  204. self.myLocation=theBestLocation;
  205. self.myLocationAccuracy =[[myBestLocation objectForKey:ACCURACY]floatValue];
  206. }
  207. //NSLog(@"Send to Server: Latitude(%f) Longitude(%f) Accuracy(%f)",self.myLocation.latitude, self.myLocation.longitude,self.myLocationAccuracy);
  208. //TODO: Your code to send the self.myLocation and self.myLocationAccuracy to your server
  209. //After sending the location to the server successful, remember to clear the current array with the following code. It is to make sure that you clear up old location in the array and add the new locations from locationManager
  210. [self.shareModel.myLocationArray removeAllObjects];
  211. self.shareModel.myLocationArray = nil;
  212. self.shareModel.myLocationArray = [NSMutableArray array];
  213. }
  214. @end