I'm making a background tracking GPS app for iOS 7.0+.
I'm having issues when tracking position while in background, it's killed after exactly 5 minutes, even if we are in the middle of a highway, with 1 location per second. It's not killed when constantly in active state.
This seems to occur only on iOS 7.0 version, not on later versions.
I already registered the plist location background activity.
I need maximum accuracy and shortest update time, so I'm not using the significant change method but the basic startUpdatingLocation. This application is used mainly plugged inside a car (no mercy for battery).
I set the location delegate to the app delegate so it's less subject to be deallocated.
Even with all of this done, it's still impossible to take this app alive in background more than 5 minutes.
I'm fighting on iOS which always find a way to terminate my app, even with app state restoration.
So the question is, is there a way to know why my application is killed ?
List of threads that didn't help me or does not respond to my needs, and that I already visited :
How to keep GPS app running in background without pauses
iOS Multi-Tasking Track GPS Location
Periodic iOS background location updates
The system will not tell you why the app was terminated.
I set the location delegate to the app delegate so it's less subject to be deallocated.
The delegate has no effect on whether the location manager is deallocated or not. You must keep a strong reference to the location manager itself.
Related
My app needs the device location with an accuracy of about 10 meters. If the app is launched, it usually takes e.g. 10 sec to get the required accuracy. This delay is OK. However when the app is „in use“ (see below), the delay should be less, e.g. 1 sec.
The problem is the following:
When the user switches off the display, the app transits from the active state to the background state (and the delegate methods applicationWillResignActive and applicationDidEnterBackground are called).
Normally, location updates are not done in background. So, next time the app transits from background to active state (delegate methods applicationWillEnterForeground and applicationDidBecomeActive are called), the location manager needs again e.g. 10 sec to reach the required accuracy. This delay in unfortunately not OK.
To avoid it, the app could do location updates in the background. This works fine.
The disadvantage is that these background location updates continue, even if the app is no longer used, because the user pressed the home button and switched to another app. This is disturbing at least for 2 reasons: The GPS hardware is unnecessarily active and uses power, and the user is notified that my app is using the device location although this is no longer required.
My question thus is:
Is it possible to determine if another app becomes active?
If so, background location updates could be switched off.
Is it possible to determine if another app becomes active?
No, your app only knows if it's in background or in foreground handling delegate events. Know if user opened another app or is in the home screen is not possible.
These background location updates continue, even if the app is no longer used, because the user pressed the home button and switched to another app.
I think you're right. You could start a timer when application goes in background and update localization only for an estabilished period (one minute?). Then, at the end of timer count save last localization coordinates. Timer is used to avoid unnecessary updates, then if user doesn't open again your app after a reasonable time, maybe it's because he's using other apps or he locked the device.
When the app comes to the foreground again, if timer is still active you're good. Otherwise show last localization saved and show a small "banner" to advise user that localization could not be accurated for the first 10 seconds (until when required accuracy has been reached)
Still fighting with iBeacon monitoring for screen-off mode in my iOS app.
In my experiment, when the screen is turned off, the delegate method "locationManager:didRangeBeacons:inRegion:" is still triggered continuously, but, as soon as the screen is off, the signal disappears accordingly(RSSI=0, beacon.accuracy=-1.0), and then, 10 seconds later, there is no beacon found at all.
I found some important information in this post saying that "iOS uses beacons in two different ways: region monitoring and beacon ranging. The latter does NOT work in the background ..., or when the app is terminated.
CLLocationManager will ONLY fire off ONE delegate call when a region is entered. If you start monitoring for a region while inside of that said region, the entry delegate will NOT be called. Your app will have to manually call the CLLocationManager’s requestStateForRegion method. Once you’ve exited the monitored region(s), CLLocationManager will call the didExitRegion approximately 30-45 seconds later."
Now I tried to call the "requestStateForRegion:" method continuously when the screen is off. The result is:
If my iPhone is already in the iBeacon region, the delegate method
"didDetermineState" gives "CLRegionStateInside" continuously;
When I hold my iPhone and walk outside the iBeacon region, or just
shut down the iBeacon's advertising, after 30-45 seconds, the
delegate method "didDetermineState" turns to "CLRegionStateOutside"
and keeps in "outside" state;
When I hold my iPhone and walk inside the iBeacon region, or turn on
the iBeacon's advertising again, the delegate method
"didDetermineState" still gives "outside" continuously and NEVER
TURNS BACK TO "inside".
What I need is, when the screen is off, I can detect as soon as my iOS device enters the iBeacon region. Asking for help...Thanks in advance.
Have you added the NSLocationAlwaysUsageDescription in your info.plist? I can really recommend you to follow this tutorial which goes through all this.
When you start monitoring, there's always an initial call to the didDetermineState delegate. This is how you can figure out if you're already in the beacon region. From then on, you can continue relying on didEnter/didExit (didDetermineState is also called alongside these). The only catch is, if the user turns Bluetooth off and then back on again—you will lose any state transitions that ordinarily would've happened during that time—so it's a good idea to call requestState after you detect Bluetooth is back on, to get caught up on the current state.
All in all, there's no need to call requestState continuously, and you can't ordinarily even do so when the screen is locked—iOS will put your app to sleep, per my answer to your other question. Unless you're using Background Modes to keep the app running in the background, but then you must be able to defend it when you submit your app for review, as Background Modes are reserved for very specific use cases. You should rely on automatic calls to didEnter/didExit/didDetermineState, aided by requestState if Bluetooth is turned off and on.
When I hold my iPhone and walk inside the iBeacon region, or turn on the iBeacon's advertising again, the delegate method "didDetermineState" still gives "outside" continuously and NEVER TURNS BACK TO "inside".
Keep in mind that depending on hardware capabilities of your iOS device (you haven't mentioned which one you're testing with), the "enter" event might take a while to trigger. The guys at Radius did some testing long time ago, and it was up to 15 minutes for iPhone 4S on iOS 7.1. That's b/c iPhone 4S doesn't support offloading BLE scanning to the Bluetooth chip, unlike newer iPhone models. But even on these newer models, there's a limit of how many scans can be offloaded to the chip, which Radius also measured to be 30 (on iOS 8.3 and with 3 different iOS devices).
I am working on an app that records journeys by tracking the GPS. Everything is working fine in background if we start the process from the foreground (by tapping the button "Start Journey").
Now the idea is start record these journeys automatically triggered by a iBeacon. When the iPhone gets inside of a beacon region, the app is detecting this and calls the function LocationManager.StartUpdatingLocation();
PROBLEM:
Using iBeacons from background, we only get 10 seconds ranging and that is the same figure I have got to get location updates from GPS.
All I need is detect I am inside of beacon region, start GPS and keep it running, and only disable the GPS when I am outside of the region.
Unfortunately, you can use CoreLocation geofences in the background, but you can't get fine GPS updates continually. This isn't a Xamarin thing -- it is an iOS restriction.
I wrote the blog post that #RobertN referenced about extending background beacon ranging to 3 minutes. But I don't think this is much help to you because you want to do get GPS updates continually, which Apple simply does not allow.
We actually recently wanted to implement this behavior in one of our apps too, and found that if we start significant location updates (startMonitoringSignificantLocationChanges) in the foreground, then we're able to start regular location updates (startUpdatingLocation) in the background, in our didEnterRegion implementation.
(Naturally, your app needs the "always" authorization to access Location Services, and the "Location updates" Background Mode enabled.)
Our app is still pending review, so whether that's a bug or a feature of Core Location, and whether Apple is okay with that, remains to be seen.
The best explanation to this I seen can extend that 10 seconds to 3 minutes, but that is it... App rejection is an issue with continuous background operation unless your app truly is reviewed as a Navigation app:
A second approach involves tracking the beacon in the background,
noting its estimated distance, and only triggering an action when the
beacon is estimated to be within a specific range. This approach is
problematic on iOS, because CoreLocation generally allows only 10
seconds of ranging time when an app is in the background. If a beacon
is first detected at 50 meters, and a person is approaching the beacon
at one meter per second, the mobile device will still be 40 meters
away when iOS suspends the app and stops it from ranging.
The good news is that it is possible to extend background ranging time
on iOS. If your app is a navigation app, you can specify location
updates in the “Required background modes” in your Info.plist. But
this approach makes it harder to get AppStore approval -- you have to
convince reviewers that your app is providing navigation services to
the user. This probably isn’t true for many apps that simply want to
use beacons to trigger at a specific distance.
Fortunately, you can still extend background ranging time without
requesting special background modes. The time you can get is limited
-- only three minutes. But this clock restarts each time your app is woken up in the background, meaning you can get an extra three minutes
of ranging time each time your app detects a beacon (enters a beacon
region) or stops seeing beacons (exits a beacon region.)
Via: http://developer.radiusnetworks.com/2014/11/13/extending-background-ranging-on-ios.html
So I asked a question about my code relating to didEnterRegion but perhaps I was being too specific, therefore could I ask someone to clarify the order of method calls in more generic terms for region monitoring, specifically when the app is in the background.
My understanding is:
App registers region calling startMonitoringForRegion:
User taps home button or locks device, app goes into the background.
The devices location is monitored at the OS level, separate from the app, the app is never launched by the OS to confirm the users current location.
When the user crosses the boundary into the region, the OS looks for which app originally registered the region and launches that app.
The app is launched in the background, (didFinishLaunchingWithOptions: is not called however), the CLLocationManager delegate is setup and it’s didEnterRegion delegate method is called.
In my case, this sets up a UILocalNotification which is presented immediately (banner displays on home screen if for example another app is in use, or on the lock screen if phone is dormant).
The user actions the notification by swiping in the lock screen or tapping the banner, the app is launched and appWillEnterForeground/appWillBecomeActive is called AND the app delegate didRecieveLocalNotification: method is called if implemented.
This is my understanding, which is probably wrong as my UILocalNotification is never fired if the app is in the background. Could someone clarify which bits are wrong?
After further testing I've come to the conclusion that there's nothing wrong with my code and it's actually appears to be Apples implementation of region monitoring being poor. It seems to be only slightly better than the monitoring of significant location changes, and still relies on changes in wifi networks and cell towers. Even within a major UK city I found didEnterRegion wasn't trigged until you were up to 1000 meters into a mile wide region, if triggered at all. This explains why it works every time when testing though Xcode and forcing the location.
The only work around I've come up with so far is to calculate the distance remaining each time the users location is updated and to manually call the didEnterRegion delegate method when this is less than the regions radius/2. This is supposed to be done automatically by Apples code when you're more than 10m into the boundary, however I found that to be unreliable for the reasons above.
However given you can't get regular updates using the better accuracy of GPS whilst the app is in the background and this is only a problem when the app is in the background, it's not really a solution at all. :o(
First of all I hope don't repeat any topic, I have spent a lot of time reading on internet about this before ask.
I'm developing an app for iOS => 5 and I need get the user location, but I don't need always a great accurate position, so when the app goes to background I change the normal location mode to Significant Location Changes and when the app come to foreground I stop the significant location change mode and get back the normal location mode, that's all goes fine,
my problem is when the app goes to background mode or even the user KILL the app the GPS signal (the purple arrow) still appear ALWAYS, even after restart the device, the only way to make disappear it is un-installing the or disabling the significant location changes when the app goes to background, but I need this mode working when the user goes to background mode, maybe not when the app is killed.
I don't know how to stop the service when the user kill the app... because event "applicationWillTerminate" is not called if you have multitask ON.
My main reason because I don't want the purple arrow appear always, even the app is killed is because I don't want the user think the app is drying the battery... so the user won't want the app installed.
First question: Is normal that the purple arrow appear always, even the app is killed if the Significant location change is enabled for the app?
Second question: Is any way to change this, to stop the service at least when the app is killed to hide the purple arrow?
Thank you all.
Sorry for my english if something is wrong.
After few days researching to be sure about this service, seems like there is NO way to use significant locations change in the background without the arrow in the top bar. I have been testing with different apps and reading through internet and nothing to solve this.
The only ""way to solve"" this is disable multitask mode in the app and disable the significant locations change in the event "applicationWillTerminate" but don't make sense... I'm losing the background location always not only when the app is killed... so is not useful.
It's bad... is a really good service to get locations saving battery but as user and developer I don't want an app that make appear this icon ALWAYS even after the app is killed, as developer I don't want that people uninstall the app for this reason and as normal user I don't know what mean this icon if is normal GPS or Significant locations change and what mean this... if my battery is being drain or not.
The other option to get locations in background task but has a big impact over the battery....
I hope apple fix this in future versions... adding at least a new arrow or showing only when a new location arrive instad of always or allowing to stooped when the app is killed.
All this has been researched over iOS - 6.1
Thanks to all.
When you use the significant location change service, the OS keeps your app running. If the app is in the background and is killed, the OS restarts it, so the purple arrow will always show. When a new location is detected, the app is restarted. From the docs:
If you leave this service running and your app is subsequently suspended or terminated, the service automatically wakes up your app when new location data arrives. At wake-up time, your app is put into the background and given a small amount of time to process the location data. ... To stop the significant change location service, call the stopMonitoringSignificantLocationChanges method.
Hmmm, interesting. I've just seen that problem with another app - seeing the arrow still active made me want to disable location updates for that app so the problem is real. Best thing I can think of is to have some kind of timer to disable the location monitoring after a certain amount of time if that is appropriate for your app.