2014-06-18 66 views
2

我試圖在應用程序處於非活動狀態時(用戶關閉應用程序)獲取位置更新。 2位置更新後,位置更新停止啓動我的應用程序。 指示器是位置服務設置中我的應用中的灰色箭頭。當應用程序處於非活動狀態時獲取位置更新在2次更新後停止

我想要的是startMonitoringSignificantLocationChanges的組合& regionMonitoring

  • 我在iPhone 4 iOS 7.1.1上測試過,2次更新後停止位置更新。
  • 我在iPad mini WiFi + Cellular iOS 7.1.1中測試過,1次更新和區域監控只發送1個位置後停止位置更新。

我在哪裏錯了?

我的代碼:

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 

    [RegionMonitoringService sharedInstance].launchOptions = launchOptions; 
    [[RegionMonitoringService sharedInstance] stopMonitoringAllRegions]; 

    if ([CLLocationManager significantLocationChangeMonitoringAvailable]) { 
     [[RegionMonitoringService sharedInstance] startMonitoringSignificantLocationChanges]; 
    } else { 
     NSLog(@"Significant location change service not available."); 
    } 

    if (launchOptions[UIApplicationLaunchOptionsLocationKey]) { 

     [self application:application handleNewLocationEvet:launchOptions]; // Handle new location event 

     UIViewController *controller = [[UIViewController alloc] init]; 
     controller.view.frame = [UIScreen mainScreen].bounds; 
     UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:controller]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      appDelegate.window.rootViewController = nvc; 
      [appDelegate.window makeKeyAndVisible]; 
     }); 

    } 
    else { 
     // ... 
    } 

    return YES; 
} 

- (void)applicationDidEnterBackground:(UIApplication *)application 
{  
    [defaults synchronize]; 

    [UIApplication sharedApplication].applicationIconBadgeNumber = 0; 

    if ([RegionMonitoringService sharedInstance].launchOptions[UIApplicationLaunchOptionsLocationKey]) { 
     return; 
    } 
}  

- (void)application:(UIApplication *)application handleNewLocationEvet:(NSDictionary *)launchOptions 
{ 
    NSLog(@"%s, launchOptions: %@", __PRETTY_FUNCTION__, launchOptions); 

    if (![launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) return; 
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) return; 

    SendLocalPushNotification(@"handleNewLocationEvet"); 
} 

RegionMonitoringService.h:

#import <Foundation/Foundation.h> 
#import <CoreLocation/CoreLocation.h> 
#import "ServerApiManager.h" 

@interface RegionMonitoringService : NSObject 

@property (strong, nonatomic) CLLocationManager *locationManager; 
@property (strong, nonatomic) NSDictionary *launchOptions; 
@property (strong, nonatomic) NSDate *oldDate; 
@property (strong, nonatomic) CLLocation *oldLocation; 

+ (RegionMonitoringService *)sharedInstance; 
- (void)startMonitoringForRegion:(CLRegion *)region; 
- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius; 
- (void)stopMonitoringAllRegions; 
- (void)startMonitoringSignificantLocationChanges; 
- (void)stopMonitoringSignificantLocationChanges; 
FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state); 

@end 

RegionMonitoringService.m:

#import "RegionMonitoringService.h" 

static CLLocationDistance const kFixedRadius = 250.0; 

@interface RegionMonitoringService() <CLLocationManagerDelegate> 
- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate; 
- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius; 
- (void)sortLastLocation:(CLLocation *)lastLocation; 
@end 

@implementation RegionMonitoringService 

+ (RegionMonitoringService *)sharedInstance 
{ 
    static RegionMonitoringService *_sharedInstance; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _sharedInstance = [[self alloc] init]; 
    }); 
    return _sharedInstance; 
} 

- (instancetype)init 
{ 
    self = [super init]; 
    if (!self) { 
     return nil; 
    } 

    _locationManager = [[CLLocationManager alloc] init]; 
    _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
    _locationManager.distanceFilter = kCLDistanceFilterNone; 
// _locationManager.activityType = CLActivityTypeFitness; 
    _locationManager.delegate = self; 

    return self; 
} 

- (void)startMonitoringForRegion:(CLRegion *)region 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 
    [_locationManager startMonitoringForRegion:region]; 
} 

- (void)startMonitoringRegionWithCoordinate:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDirection)radius 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    if (![CLLocationManager regionMonitoringAvailable]) { 
     NSLog(@"Warning: Region monitoring not supported on this device."); 
     return; 
    } 

    if (__iOS_6_And_Heigher) { 
     CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coordinate 
                    radius:radius 
                   identifier:[self identifierForCoordinate:coordinate]]; 
     [_locationManager startMonitoringForRegion:region]; 
    } 
    else { 
     CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinate 
                    radius:radius 
                   identifier:[self identifierForCoordinate:coordinate]]; 
     [_locationManager startMonitoringForRegion:region]; 
    } 

    SendLocalPushNotification([NSString stringWithFormat:@"StartMonitor: {%f, %f}", coordinate.latitude, coordinate.longitude]); 
} 

- (void)stopMonitoringAllRegions 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    if (_locationManager.monitoredRegions.allObjects.count > 1) { 
     for (int i=0; i<_locationManager.monitoredRegions.allObjects.count; i++) { 
      if (i == 0) { 
       NSLog(@"stop monitor region at index %d", i); 
       CLRegion *region = (CLRegion *)_locationManager.monitoredRegions.allObjects[i]; 
       [_locationManager stopMonitoringForRegion:region]; 
      } 
     } 
    } 
} 

- (void)startMonitoringSignificantLocationChanges 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    [_locationManager startMonitoringSignificantLocationChanges]; 
} 

- (void)stopMonitoringSignificantLocationChanges 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    [_locationManager stopMonitoringSignificantLocationChanges]; 
} 

- (NSString *)identifierForCoordinate:(CLLocationCoordinate2D)coordinate 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    return [NSString stringWithFormat:@"{%f, %f}", coordinate.latitude, coordinate.longitude]; 
} 

FOUNDATION_EXPORT NSString *NSStringFromCLRegionState(CLRegionState state) 
{ 
    NSLog(@"%s", __PRETTY_FUNCTION__); 

    if (__iOS_6_And_Heigher) { 
     return @"Support only iOS 7 and later."; 
    } 

    if (state == CLRegionStateUnknown) { 
     return @"CLRegionStateUnknown"; 
    } else if (state == CLRegionStateInside) { 
     return @"CLRegionStateInside"; 
    } else if (state == CLRegionStateOutside) { 
     return @"CLRegionStateOutside"; 
    } else { 
     return [NSString stringWithFormat:@"Undeterminded CLRegionState"]; 
    } 
} 

- (CLLocationDistance)getFixRadius:(CLLocationDistance)radius 
{ 
    if (radius > _locationManager.maximumRegionMonitoringDistance) { 
     radius = _locationManager.maximumRegionMonitoringDistance; 
    } 
    return radius; 
} 

- (void)sortLastLocation:(CLLocation *)lastLocation 
{ 
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, lastLocation); 

    self.oldDate = lastLocation.timestamp; // Get new date 

    NSTimeInterval seconds = fabs([self.oldLocation.timestamp timeIntervalSinceDate:self.oldDate]); // Calculate how seconds passed 
    NSInteger minutes = seconds * 60; // Calculate how minutes passed 

    if (lastLocation && self.oldLocation) { // New & old location are good 
     if ([lastLocation distanceFromLocation:self.oldLocation] >= 200 || minutes >= 30) { // Distance > 200 or 30 minutes passed 
      [[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send location to server 
     } 
    } 
    else { // We just starting location updates 
     [[ServerApiManager sharedInstance] saveLocation:lastLocation]; // Send new location to server 
    } 
    self.oldLocation = lastLocation; // Set old location 
} 

#pragma mark - CLLocationManagerDelegate Methods 

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
{ 
    NSLog(@"%s, %@", __PRETTY_FUNCTION__, locations); 
    CLLocation *lastLocation = (CLLocation *)locations.lastObject; 
    CLLocationCoordinate2D coordinate = lastLocation.coordinate; 

    if (lastLocation == nil || coordinate.latitude == 0.0 || coordinate.longitude == 0.0) { 
     return; 
    } 

    [self startMonitoringRegionWithCoordinate:coordinate andRadius:[self getFixRadius:kFixedRadius]]; 

    [self sortLastLocation:lastLocation]; 
} 

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region 
{ 
    NSLog(@"%s, currentLocation: %@, regionState: %@, region: %@", 
      __PRETTY_FUNCTION__, manager.location, NSStringFromCLRegionState(state), region); 
} 

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region 
{ 
    NSLog(@"%s, REGION: %@", __PRETTY_FUNCTION__, region); 
    [manager requestStateForRegion:region]; 
} 

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region 
{ 
} 

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region 
{ 
    NSLog(@"%s, REGION: %@", __PRETTY_FUNCTION__, region); 

    [self stopMonitoringAllRegions]; 
    [self startMonitoringRegionWithCoordinate:manager.location.coordinate andRadius:[self getFixRadius:kFixedRadius]]; 

    CLLocation *lastLocation = manager.location; 
    CLLocationCoordinate2D coordinate = lastLocation.coordinate; 
    if (lastLocation == nil || coordinate.latitude == 0.0 || coordinate.longitude == 0.0) { 
     return; 
    } 

    [self sortLastLocation:manager.location]; 
} 

@end 

enter image description here

enter image description here

編輯1:

我一大把的經過多次測試實時測試與汽車用幾臺設備(iPhone 5S,iPad的迷你,iPhone 4)我來到了這一點:

  1. 在一種情況下,iPad mini & iPhone 4在應用程序未運行且小箭頭變灰後數分鐘後停止更新位置。
  2. WiFi關閉時,準確性很差,位置更新很少。

編輯2:

OK,很多駕駛和走動和測試它,它就像一個魅力至今之後。 我設法使其工作,結合significantLocationChanges &區域監控,總是在我的當前位置周圍註冊地理圍欄,並始終在新的UIApplicationLaunchOptionsLocationKey到來時開始顯着的位置更改。 請注意,關閉wifi會使準確度非常低,甚至有時無法正常工作。

我的代碼中的任何錯誤?

+1

只是一個想法'startMonitoringSignificantLocationChanges'只監視重大更改。你有沒有嘗試移動到不同的地方來增加距離? –

+0

約2公里。 –

+0

對於iOS 7.0,爲了持續獲取位置更新,您必須知道何時重新啓動locationManager以使應用始終處於活動模式。我聽說,對於iOS 7.1,即使它處於非活動狀態,您也可以獲取位置更新,但我還沒有找到任何可靠的方法來使其工作。對於iOS 7.0,您可以在這裏看到我的解決方案:http://stackoverflow.com/questions/18946881/background-location-services-not-working-in-ios-7/21966662#21966662此解決方案適用於iOS 7.1好,但它會耗盡一些電池。 – Ricky

回答

1

從Apple docs可以看出,更新不超過每5分鐘500米位置變化發送更頻繁:

Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.

你要接收即使應用程序處於非活動狀態也會更新另一個提示可能是oyu可以使用真實設備在模擬器中測試位置,這樣您就不必到外面進行測試,並且仍然可以檢查日誌。在模擬器菜單中,選擇調試 - >位置

+0

對您有幫助嗎?讓我知道你是否仍然在與這個問題鬥爭! – nburk

+0

再次檢查上次報告的座標與我何時停止跟蹤的距離差不多是1公里。 –

+0

那時候呢?您必須等待5分鐘,直到收到下一個位置更新。 – nburk

相關問題