angularjs - Cordova katzer plugin background mode not working on iOS-9 -
in ionic/angularjs application use https://github.com/katzer/cordova-plugin-background-mode/ backgrounding application.
it's working quiet on ios-8 new ios-9 not working more. did few tests , looks app working in background user gets no information it. on ios-8 message "yourapp using location" or on top of display. on ios-9 message missing.
did same experience plugin?
i found out there changes in core location functions on ios9: allowsbackgroundlocationupdates in cllocationmanager in ios9
like suggested in post add default property allowsbackgroundlocationupdates value yes org.apache.cordova.geolocation plugin.
with fix on cdvlocation.m located in /plugins/org.apache.cordova-geolocation/src/ios/
works.
to bring work removed platform ios cordova platform remove ios
, added again cordova platform add ios
builds plugins new.
now i'm getting blue bar on display again :-)
this fix break geolocation support on ios < 9.0. bring work older versions 9.0 use cdvlocation.m file:
the code changed marked with: //edited kingalione
/* licensed apache software foundation (asf) under 1 or more contributor license agreements. see notice file distributed work additional information regarding copyright ownership. asf licenses file under apache license, version 2.0 (the "license"); may not use file except in compliance license. may obtain copy of license @ http://www.apache.org/licenses/license-2.0 unless required applicable law or agreed in writing, software distributed under license distributed on "as is" basis, without warranties or conditions of kind, either express or implied. see license specific language governing permissions , limitations under license. */ #import "cdvlocation.h" #import <cordova/nsarray+comparisons.h> #pragma mark constants #define kpglocationerrordomain @"kpglocationerrordomain" #define kpglocationdesiredaccuracykey @"desiredaccuracy" #define kpglocationforcepromptkey @"forceprompt" #define kpglocationdistancefilterkey @"distancefilter" #define kpglocationfrequencykey @"frequency" //edited kingalione: start #define system_version_equal_to(v) ([[[uidevice currentdevice] systemversion] compare:v options:nsnumericsearch] == nsorderedsame) #define system_version_greater_than(v) ([[[uidevice currentdevice] systemversion] compare:v options:nsnumericsearch] == nsordereddescending) #define system_version_greater_than_or_equal_to(v) ([[[uidevice currentdevice] systemversion] compare:v options:nsnumericsearch] != nsorderedascending) #define system_version_less_than(v) ([[[uidevice currentdevice] systemversion] compare:v options:nsnumericsearch] == nsorderedascending) #define system_version_less_than_or_equal_to(v) ([[[uidevice currentdevice] systemversion] compare:v options:nsnumericsearch] != nsordereddescending) //edited kingalione: end #pragma mark - #pragma mark categories @implementation cdvlocationdata @synthesize locationstatus, locationinfo, locationcallbacks, watchcallbacks; - (cdvlocationdata*)init { self = (cdvlocationdata*)[super init]; if (self) { self.locationinfo = nil; self.locationcallbacks = nil; self.watchcallbacks = nil; } return self; } @end #pragma mark - #pragma mark cdvlocation @implementation cdvlocation @synthesize locationmanager, locationdata; - (cdvplugin*)initwithwebview:(uiwebview*)thewebview { self = (cdvlocation*)[super initwithwebview:(uiwebview*)thewebview]; if (self) { self.locationmanager = [[cllocationmanager alloc] init]; //edited kingalione: start if (system_version_greater_than_or_equal_to(@"9.0")) { self.locationmanager.allowsbackgroundlocationupdates = yes; } //edited kingalione: end self.locationmanager.delegate = self; // tells location manager send updates object __locationstarted = no; __highaccuracyenabled = no; self.locationdata = nil; } return self; } - (bool)isauthorized { bool authorizationstatusclasspropertyavailable = [cllocationmanager respondstoselector:@selector(authorizationstatus)]; // ios 4.2+ if (authorizationstatusclasspropertyavailable) { nsuinteger authstatus = [cllocationmanager authorizationstatus]; #ifdef __iphone_8_0 if ([self.locationmanager respondstoselector:@selector(requestwheninuseauthorization)]) { //ios 8.0+ return (authstatus == kclauthorizationstatusauthorizedwheninuse) || (authstatus == kclauthorizationstatusauthorizedalways) || (authstatus == kclauthorizationstatusnotdetermined); } #endif return (authstatus == kclauthorizationstatusauthorized) || (authstatus == kclauthorizationstatusnotdetermined); } // default, assume yes (for ios < 4.2) return yes; } - (bool)islocationservicesenabled { bool locationservicesenabledinstancepropertyavailable = [self.locationmanager respondstoselector:@selector(locationservicesenabled)]; // ios 3.x bool locationservicesenabledclasspropertyavailable = [cllocationmanager respondstoselector:@selector(locationservicesenabled)]; // ios 4.x if (locationservicesenabledclasspropertyavailable) { // ios 4.x return [cllocationmanager locationservicesenabled]; } else if (locationservicesenabledinstancepropertyavailable) { // ios 2.x, ios 3.x return [(id)self.locationmanager locationservicesenabled]; } else { return no; } } - (void)startlocation:(bool)enablehighaccuracy { if (![self islocationservicesenabled]) { [self returnlocationerror:permissiondenied withmessage:@"location services not enabled."]; return; } if (![self isauthorized]) { nsstring* message = nil; bool authstatusavailable = [cllocationmanager respondstoselector:@selector(authorizationstatus)]; // ios 4.2+ if (authstatusavailable) { nsuinteger code = [cllocationmanager authorizationstatus]; if (code == kclauthorizationstatusnotdetermined) { // return position_unavailable need coordinate other platforms message = @"user undecided on application's use of location services."; } else if (code == kclauthorizationstatusrestricted) { message = @"application's use of location services restricted."; } } // permissiondenied positionerror makes sense when authorization denied [self returnlocationerror:permissiondenied withmessage:message]; return; } #ifdef __iphone_8_0 nsuinteger code = [cllocationmanager authorizationstatus]; if (code == kclauthorizationstatusnotdetermined && ([self.locationmanager respondstoselector:@selector(requestalwaysauthorization)] || [self.locationmanager respondstoselector:@selector(requestwheninuseauthorization)])) { //ios8+ __highaccuracyenabled = enablehighaccuracy; if([[nsbundle mainbundle] objectforinfodictionarykey:@"nslocationalwaysusagedescription"]){ [self.locationmanager requestalwaysauthorization]; } else if([[nsbundle mainbundle] objectforinfodictionarykey:@"nslocationwheninuseusagedescription"]) { [self.locationmanager requestwheninuseauthorization]; } else { nslog(@"[warning] no nslocationalwaysusagedescription or nslocationwheninuseusagedescription key defined in info.plist file."); } return; } #endif // tell location manager start notifying of location updates. // first stop, , start updating ensure @ least 1 // update, if our location did not change. [self.locationmanager stopupdatinglocation]; [self.locationmanager startupdatinglocation]; __locationstarted = yes; if (enablehighaccuracy) { __highaccuracyenabled = yes; // set distance filter 5 high accuracy. setting "kcldistancefilternone" provide // higher accuracy, it's spamming callback useless reports drain battery. self.locationmanager.distancefilter = 5; // set desired accuracy best. self.locationmanager.desiredaccuracy = kcllocationaccuracybest; } else { __highaccuracyenabled = no; // todo: set distance filter 10 meters? , desired accuracy nearest ten meters? arbitrary. self.locationmanager.distancefilter = 10; self.locationmanager.desiredaccuracy = kcllocationaccuracynearesttenmeters; } } - (void)_stoplocation { if (__locationstarted) { if (![self islocationservicesenabled]) { return; } [self.locationmanager stopupdatinglocation]; __locationstarted = no; __highaccuracyenabled = no; } } - (void)locationmanager:(cllocationmanager*)manager didupdatetolocation:(cllocation*)newlocation fromlocation:(cllocation*)oldlocation { cdvlocationdata* cdata = self.locationdata; cdata.locationinfo = newlocation; if (self.locationdata.locationcallbacks.count > 0) { (nsstring* callbackid in self.locationdata.locationcallbacks) { [self returnlocationinfo:callbackid andkeepcallback:no]; } [self.locationdata.locationcallbacks removeallobjects]; } if (self.locationdata.watchcallbacks.count > 0) { (nsstring* timerid in self.locationdata.watchcallbacks) { [self returnlocationinfo:[self.locationdata.watchcallbacks objectforkey:timerid] andkeepcallback:yes]; } } else { // no callbacks waiting on anymore, turn off listening. [self _stoplocation]; } } - (void)getlocation:(cdvinvokedurlcommand*)command { nsstring* callbackid = command.callbackid; bool enablehighaccuracy = [[command argumentatindex:0] boolvalue]; if ([self islocationservicesenabled] == no) { nsmutabledictionary* poserror = [nsmutabledictionary dictionarywithcapacity:2]; [poserror setobject:[nsnumber numberwithint:permissiondenied] forkey:@"code"]; [poserror setobject:@"location services disabled." forkey:@"message"]; cdvpluginresult* result = [cdvpluginresult resultwithstatus:cdvcommandstatus_error messageasdictionary:poserror]; [self.commanddelegate sendpluginresult:result callbackid:callbackid]; } else { if (!self.locationdata) { self.locationdata = [[cdvlocationdata alloc] init]; } cdvlocationdata* ldata = self.locationdata; if (!ldata.locationcallbacks) { ldata.locationcallbacks = [nsmutablearray arraywithcapacity:1]; } if (!__locationstarted || (__highaccuracyenabled != enablehighaccuracy)) { // add callbackid array can call when data if (callbackid != nil) { [ldata.locationcallbacks addobject:callbackid]; } // tell location manager start notifying of heading updates [self startlocation:enablehighaccuracy]; } else { [self returnlocationinfo:callbackid andkeepcallback:no]; } } } - (void)addwatch:(cdvinvokedurlcommand*)command { nsstring* callbackid = command.callbackid; nsstring* timerid = [command argumentatindex:0]; bool enablehighaccuracy = [[command argumentatindex:1] boolvalue]; if (!self.locationdata) { self.locationdata = [[cdvlocationdata alloc] init]; } cdvlocationdata* ldata = self.locationdata; if (!ldata.watchcallbacks) { ldata.watchcallbacks = [nsmutabledictionary dictionarywithcapacity:1]; } // add callbackid dictionary can call whenever data [ldata.watchcallbacks setobject:callbackid forkey:timerid]; if ([self islocationservicesenabled] == no) { nsmutabledictionary* poserror = [nsmutabledictionary dictionarywithcapacity:2]; [poserror setobject:[nsnumber numberwithint:permissiondenied] forkey:@"code"]; [poserror setobject:@"location services disabled." forkey:@"message"]; cdvpluginresult* result = [cdvpluginresult resultwithstatus:cdvcommandstatus_error messageasdictionary:poserror]; [self.commanddelegate sendpluginresult:result callbackid:callbackid]; } else { if (!__locationstarted || (__highaccuracyenabled != enablehighaccuracy)) { // tell location manager start notifying of location updates [self startlocation:enablehighaccuracy]; } } } - (void)clearwatch:(cdvinvokedurlcommand*)command { nsstring* timerid = [command argumentatindex:0]; if (self.locationdata && self.locationdata.watchcallbacks && [self.locationdata.watchcallbacks objectforkey:timerid]) { [self.locationdata.watchcallbacks removeobjectforkey:timerid]; if([self.locationdata.watchcallbacks count] == 0) { [self _stoplocation]; } } } - (void)stoplocation:(cdvinvokedurlcommand*)command { [self _stoplocation]; } - (void)returnlocationinfo:(nsstring*)callbackid andkeepcallback:(bool)keepcallback { cdvpluginresult* result = nil; cdvlocationdata* ldata = self.locationdata; if (ldata && !ldata.locationinfo) { // return error result = [cdvpluginresult resultwithstatus:cdvcommandstatus_error messagetoerrorobject:positionunavailable]; } else if (ldata && ldata.locationinfo) { cllocation* linfo = ldata.locationinfo; nsmutabledictionary* returninfo = [nsmutabledictionary dictionarywithcapacity:8]; nsnumber* timestamp = [nsnumber numberwithdouble:([linfo.timestamp timeintervalsince1970] * 1000)]; [returninfo setobject:timestamp forkey:@"timestamp"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.speed] forkey:@"velocity"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.verticalaccuracy] forkey:@"altitudeaccuracy"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.horizontalaccuracy] forkey:@"accuracy"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.course] forkey:@"heading"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.altitude] forkey:@"altitude"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.coordinate.latitude] forkey:@"latitude"]; [returninfo setobject:[nsnumber numberwithdouble:linfo.coordinate.longitude] forkey:@"longitude"]; result = [cdvpluginresult resultwithstatus:cdvcommandstatus_ok messageasdictionary:returninfo]; [result setkeepcallbackasbool:keepcallback]; } if (result) { [self.commanddelegate sendpluginresult:result callbackid:callbackid]; } } - (void)returnlocationerror:(nsuinteger)errorcode withmessage:(nsstring*)message { nsmutabledictionary* poserror = [nsmutabledictionary dictionarywithcapacity:2]; [poserror setobject:[nsnumber numberwithunsignedinteger:errorcode] forkey:@"code"]; [poserror setobject:message ? message:@"" forkey:@"message"]; cdvpluginresult* result = [cdvpluginresult resultwithstatus:cdvcommandstatus_error messageasdictionary:poserror]; (nsstring* callbackid in self.locationdata.locationcallbacks) { [self.commanddelegate sendpluginresult:result callbackid:callbackid]; } [self.locationdata.locationcallbacks removeallobjects]; (nsstring* callbackid in self.locationdata.watchcallbacks) { [self.commanddelegate sendpluginresult:result callbackid:callbackid]; } } - (void)locationmanager:(cllocationmanager*)manager didfailwitherror:(nserror*)error { nslog(@"locationmanager::didfailwitherror %@", [error localizedfailurereason]); cdvlocationdata* ldata = self.locationdata; if (ldata && __locationstarted) { // todo: have once on various error codes , return 1 of: // positionerror.permission_denied = 1; // positionerror.position_unavailable = 2; // positionerror.timeout = 3; nsuinteger positionerror = positionunavailable; if (error.code == kclerrordenied) { positionerror = permissiondenied; } [self returnlocationerror:positionerror withmessage:[error localizeddescription]]; } if (error.code != kclerrorlocationunknown) { [self.locationmanager stopupdatinglocation]; __locationstarted = no; } } //ios8+ -(void)locationmanager:(cllocationmanager *)manager didchangeauthorizationstatus:(clauthorizationstatus)status { if(!__locationstarted){ [self startlocation:__highaccuracyenabled]; } } - (void)dealloc { self.locationmanager.delegate = nil; } - (void)onreset { [self _stoplocation]; [self.locationmanager stopupdatingheading]; } @end
Comments
Post a Comment