Is there a way to manually tell the device to dispatch a significant location change notification that will wake up any applications registered for this notification?
This is for testing only, and I realize this private API call would get rejected upon submission to the app store.
So two answers:
A) Hop on a train :-)
B) Use the simulator. In iOS 5.x simulator, there is a debug menu that has a location submenu. Choose freeway drive. This will start the simulator on an imaginary journey down the scenic 280 in Northern California. It gives you everything but the view: your app will get Significant Location Change updates, and will also be launched in the background if it has been suspended.
To verify that you are actually moving, launch safari in the simulator, and go to maps.google.com and click the little track my location button. You should be moving.
Awesome! Now how to debug the lifecycle problem of being launched by the system? Easy! Have xCode wait for your app to be launched to start debugging. From the Scheme menu, choose edit scheme. In the Run Scheme, and the Info tab, for the "Launch" setting choose : "Wait for My.app to launch".
Run your app once in the simulator, so that it starts monitoring for location updates, then force quit it, so that it is suspended. Add a break point in your application did finish launching function, and wait. As soon as your simulator has gone far enough, your application will be woken up, your breakpoint hit, and you are in the money.
But really, the train ride is more fun.
Well, I've found that I can do this by toggling on and off Airplane mode and/or WiFi. Perhaps start the app with the device in airplane mode, then close the app and turn airplane mode off. That will turn the GPS on and force a location update to be dispatched.
I also wanted to test the relaunch of my terminated app which uses significant change monitoring. I wrote a piece of code so that it would display a local notification when it gets launched by a location key in the launch options dictionary.
I ran my app in the simulator. Then killed it from the multitasking bar. Then I set the location of the iOS simulator to a custom location. I quit the simulator and started it again. My app received the significant location update and showed the local notification.
I was struggling with the same issue, how to test 'startMonitoringSignificantLocationChanges' and check if my app is receiving location updates when suspended.
I couldn't manage to catch the execution on a breakpoint but I managed to see the results of my implementation working by sending the new location data to the server.
The whole flow:
- Implemented with 'startMonitoringSignificantLocationChanges' and an API call to my server to update the location latitude and longitude
- Set the location updates background mode capability to true
- Run the app so the location manager is initiated and the app is listening for location changes
- Force closed the app
- Set the debug->location on simulator to freeway drive
- Opened maps to see if the location is changing
- Waited on the server to see for location updates and was getting new results every about 3 minutes
However, I'm still not sure if this is fine enough on a real device.
I'm working on Xcode Version 6.0.1 (6A317); tested on Simulator iPhone 5s (8.0).
Adding to MagicSeth's answer, if you need to test this on a real device instead of a simulator, you can trigger a background launch with UIApplication.LaunchOptionsKey.location key by disabling and re-enabling Location Services in General > Privacy screen in the Settings app.
Depending on your scenario I would suggest two solutions:
Use a Timer or LocalNotification that periodically calls stopMonitoringSignificantLocationChanges followed by startMonitoringSignificantLocationChanges which should trigger a new location to be sent to your code (might be the same Location as before).
Build your own GPS Simulator that you start in debug builds and that will call the same delegate methods like CLLocationManager would do.
One thing I noticed in iOS 7 and Xcode 5.1.1 - If you are expecting SLC events to fire up your app into background mode, it may or may not hit the breakpoints you set. For me, sometimes the NSLog message are not even showing.
If that's the case for you, you can view NSLog outputs from the System Log. You can open the System Log from iOS Simulator's Debug menu.
In iOS 4, you can register for significant location changes. From the Apple docs: With this service, location updates are generated only when the user’s location changes significantly; thus, it is ideal for social applications or applications that provide the user with noncritical, location-relevant information. If the application is suspended when an update occurs, the system wakes it up in the background to handle the update. If the application starts this service and is then terminated, the system relaunches the application automatically when a new location becomes available. This service is available in iOS 4 and later, only on devices that contain a cellular radio.
See the Apple docs here and here.
Here is some example code to register for signification location updates:
- (void)startSignificantChangeUpdates {
// Create the location manager if it doesn't exist
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startMonitoringSignificantLocationChanges];
}
The docs say: if you leave this service running and your application is subsequently suspended or terminated, the service automatically wakes up your application when new location data arrives. At wake-up time, your application is put into the background and given a small amount of time to process the location data. Because your application is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your application may be terminated.
Freeway drive
// MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
guard let location = userLocation.location else { return }
print(location.speed)
}
Well, this is not possible as the application scope is limited to its own space and such kind of notification cannot be generated with Apple Documented APIs list.
Of course.. if any undocumented API is used, application will get rejection from apple due to the use of undocumented/private API.
Related
My application uses the core location also after the application terminates with the method startMonitoringSignificantLocationChanges in CLLocationManager class.
My application launches with a location key in iOS 5 and 6 in the method:
- (BOOL) application:application didFinishLaunchingWithOptions:launchOptions;
in AppDelegate class and everything works well.
But in iOS-7 betas the application doesn't launch with a location key after a significant location change.
Has anybody encountered this problem?
I tried it on a simulator and in the device.
Thanks for the help.
I have the same problem in my app, when the app was terminated by user from app switcher.
But it does launch with location key if it was terminated by OS for low memory or other reason.
It is the expected result from iOS7 unfortunately. An official apple response I got from one of their evangelists:
If a user swipes up in the app switcher then the OS will not launch
the app unless explicitly told to do so by the user. So no, SLC will
not be launching the app, nor will silent notifications. The only
thing that will launch the app at that point is the user tapping the
icon. The intention here is that the user has expressed their choice
of not having that app running any more for any reason, so we honor
that. In this situation, there's really nothing that you can do. The
next time the user launches the app you can let them know that some of
the data may be missing, although you really cannot tell whether
there's missing data or not (i.e. you might have been killed by the OS
in the background and the user may not have moved thereby not
triggering any SLC notifications). My suggestion would be to gather
the data you can within the policies of the OS and if the user has
manually killed the app then respect that wish and don't do anything.
By all means, feel free to file a bug report if this change in
behavior winds up causing problems for you or (especially) confusion
for your users.
Attach link to Apple DEV forums:
https://devforums.apple.com/message/882691#882691
I am developing an app which uses CLLocationManager to track user's current location.
As soon as I launch app, it works well till the end of the day, I used to get the user's location till evening 5'o clock.
I want my app to start automatically on the next day morning, without launching the app but my app is running in the background.
I just want to work like alarm manager in android. Any suggestions?
I want CLLocationManager to startUpdatingLocation even when the device is rebooted without launching the app [while switching off the device, the app is running in background]
How to implement this?
iOS will relaunch apps that sign up for location changes! This works under ios6 already! BUT to the background only. So that the location can be tracked
see e.g. the 'Moves' app that will track your location
the idea is that you're app wakes to the background mode.
see:
Will iOS wake up the terminated app if it's registered with location for UIBackgroundModes?
pay attention to:
App won't relaunch when monitoring CLLocationManager significant location changes - iPhone
compare with:
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
You simply can't do what you want with iOS 6 or lower (app can't launch itself on those iOS versions), workaround would be to alarm user to launch your app with local notifications. But iOS 7 comes with some new features, and allows certain apps to wake at the background to complete tasks.
You can not make startUpdatingLocation(didUpdateLocations) automatically run after reboot. You have to
1. use startMonitoringForRegion ;
2. or use a remote notification to invoke startUpdatingLocation.
From the Core Location documentation:
The regions you register with the location manager persist between launches of
your application. If a region crossing occurs while your application is not
running, the system automatically wakes up your application (or relaunches it)
in the background so that it can process the event. When relaunched, all of
the regions you configured previously are made available in the
monitoredRegions property of any location manager objects you create.
Unfortunately, this is unclear as to whether or not the same app will also be relaunched after device reboot in response to a region change.
Will an iOS app that monitors significant location changes in the background still be relaunched, even after a device reboot?
Yes, your app will be launched to respond to the region events even if the phone is restarted, and even if the user did not explicitly run your app after the reboot.
I haven't seen any documentation that spells that out clearly. But this is how it works in a couple of my own apps.
Just to make an update. I know that this is an old question, but I want to confirm that it works on iOS7, even after a reboot.
Check my question here:
Are background mode location and fetch called even after the device restarted in iOS7?
I am doing a tracking kind of application for internal use of an organization and do not wish to submit it to app store.
What I am doing in the application is I am tracking the phone calls, messages etc.
My app runs in background once I start the app manually and keeps on running in the background until I close the app or the phone is switched off.
The thing that I want to add to my app is, I want to load the app automatically when the phone is switched on again.
Any idea or guidance will help. Suggestion for use of private apis is also welcome.
In private api, in file SBApplication.h there are all methods that you need.
In particular:
[...]
-(BOOL) _shouldAutoLaunchOnBoot:(BOOL)boot;
-(void) autoLaunchIfNecessaryOnBoot:(BOOL)boot;
-(void) _cancelAutoRelaunch;
-(void) _relaunchAfterExit;
[...]
etc, etc...
hope this helps.
As far as I can understand you can do it by registering your app for significant location changes. If an app registers for significant location changes, as soon as your cellular phone moves to a new tower, app receives an update. If the application is suspended when an update occurs, the system wakes it up in the background to handle the update.
So if you close the app and turn of your phone, as soon as your phone will restart it should get an update and it will force your app to run in background mode.
For more info read iOS programming guide: http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/BackgroundExecution/BackgroundExecution.html
Hope it helps
Greetings all.
I am attempting to implement significant location change and region support into my app. While the app is active, there is obviously no problem receiving location updates. My question is how to handle updates when the app is not active.
This is my understanding of what happens if a significant location change or region entry/exit is detected:
If the app is in the background or suspended, iOS calls locationManager:didUpdateToLocation:fromLocation: (or locationManager:didEnterRegion:) on my existing location delegate.
If the app is terminated, iOS calls application:didFinishLaunchingWithOptions: with the key UIApplicationLaunchOptionsLocationKey on my application delegate. At this point I need to create a new location manager instance to obtain the new location.
Is this correct? Am I missing anything?
Thanks for help.
Regards,
--John
You are partly right.
If the app is in background, and you are using significant location change:
The app will call locationManager:locationDidUpdateToLocation:fromLocation
If app crashed while it was in background, it will call application:didFinishLaunchingWithOption: with UIApplicationLaunchOptionLocationKey. You then have to init location manager again to get significant location change. This will then come in to locationManager:locationDidUpdateToLocation:fromLocation. This step is important
If the app is in background, and you are using region monitoring
locationManager:locationDidUpdateToLocation:fromLocation will not be called
the app calls locationManager:didEnterRegion:
To get location update when the app is in the background versus when the app is suspended are 2 very different scenario. You will have to handle them differently.
You can only use the key UIApplicationLaunchOptionsLocationKey if your locationManager is using the method startMonitoringSignificantLocationChanges, you can not use startUpdatingLocation.
To get the location update when
A) The app is In the background, please see: Background Location Services not working in iOS 7
B) The app is suspended/terminated, please see: How to Get Location Updates for iOS 7 and 8 Even when the App is Suspended
I have written 2 very long article explaining the different between the 2 scenario. The source codes for the above 2 scenario are also available on the GitHub.
I believe it always calls application: didFinishLaunchingWithOptions if your app is not in the foreground.