Sunday, 15 March 2015

ios - Getting location updates when app is inactive stops after 2 updates -



ios - Getting location updates when app is inactive stops after 2 updates -

i'm trying location updates while app inactive (user closed app). after 2 location updates, location updates stops launching app. indicator grayness arrow in app in location services settings.

what i'm trying combination of startmonitoringsignificantlocationchanges & regionmonitoring.

i tested on iphone 4 ios 7.1.1 , location updates stops after 2 updates. i tested in ipad mini wifi+cellular ios 7.1.1 , location updates stops after 1 update , part monitoring send 1 location.

where i'm wrong?

my code:

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 alter 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 { // ... } homecoming 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]; }); homecoming _sharedinstance; } - (instancetype)init { self = [super init]; if (!self) { homecoming nil; } _locationmanager = [[cllocationmanager alloc] init]; _locationmanager.desiredaccuracy = kcllocationaccuracybestfornavigation; _locationmanager.distancefilter = kcldistancefilternone; // _locationmanager.activitytype = clactivitytypefitness; _locationmanager.delegate = self; homecoming 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: part monitoring not supported on 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) { (int i=0; i<_locationmanager.monitoredregions.allobjects.count; i++) { if (i == 0) { nslog(@"stop monitor part @ 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__); homecoming [nsstring stringwithformat:@"{%f, %f}", coordinate.latitude, coordinate.longitude]; } foundation_export nsstring *nsstringfromclregionstate(clregionstate state) { nslog(@"%s", __pretty_function__); if (__ios_6_and_heigher) { homecoming @"support ios 7 , later."; } if (state == clregionstateunknown) { homecoming @"clregionstateunknown"; } else if (state == clregionstateinside) { homecoming @"clregionstateinside"; } else if (state == clregionstateoutside) { homecoming @"clregionstateoutside"; } else { homecoming [nsstring stringwithformat:@"undeterminded clregionstate"]; } } - (cllocationdistance)getfixradius:(cllocationdistance)radius { if (radius > _locationmanager.maximumregionmonitoringdistance) { radius = _locationmanager.maximumregionmonitoringdistance; } homecoming radius; } - (void)sortlastlocation:(cllocation *)lastlocation { nslog(@"%s, %@", __pretty_function__, lastlocation); self.olddate = lastlocation.timestamp; // 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 if ([lastlocation distancefromlocation:self.oldlocation] >= 200 || minutes >= 30) { // distance > 200 or 30 minutes passed [[serverapimanager sharedinstance] savelocation:lastlocation]; // send location server } } else { // starting location updates [[serverapimanager sharedinstance] savelocation:lastlocation]; // send new location 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

edit 1:

i did a lot of real time tests auto several devices (iphone 5s, ipad mini, iphone 4) after several tests came this:

in 1 case, ipad mini & iphone 4 stops updating location after several minutes when app not running , little arrow become gray. when wifi off, accuracy terrible , locations updated rarely.

edit 2:

ok, after lot of driving , walking around , testing it works charm far. managed create work, combining significantlocationchanges & part monitoring, register geofence around current location , starting important location changes when new uiapplicationlaunchoptionslocationkey come. note turning off wifi create accuracy low , not working.

any bugs in code?

from apple docs can seen updates not sent more every 5 minutes , 500 meters of location change:

apps can expect notification device moves 500 meters or more previous notification. should not expect notifications more 1 time every 5 minutes. if device able retrieve info network, location manager much more deliver notifications in timely manner.

you going receive updates when app inactive. hint might oyu can test location in simulator instead using real device, way don't have go outside testing , can still check logs too. in simulator menu, chose debug --> location.

ios objective-c cllocationmanager

No comments:

Post a Comment