I have a question about CLLocationManagerDelegate. The documentation says if the user changes the settings for your location services (in the iPhone's Settings.app) then your app is supposed to receive an didChangeAuthorizationStatus: message to the delegate. My question is, when would this happen?
If the user changed the setting, it means they are in the settings app, and your app is either backgrounded or not running at all, so in the former case, when would your app's CLLocationManager delegate get the didChangeAuthorizationStatus: call?
I just ran across this method an hour ago, so good timing on the question!
It looks like in my case this method gets called:
When the app becomes active.
On allowing Location Services for the app on the initial startup of the app.
I wrote a quick test app you can find here:
https://github.com/mharper/LocationServices
It simply logs the authorization status whenever the method gets called.
This delegate method will be called when:
The first time you init a CLLocationManager instance
1.1. If that's the first time your App launch on device, you'll receive state kCLAuthorizationStatusNotDetermined before user see the [Allow/Don't Allow] UIAlertView. (At this time, you can find that the UISwitch of your App in Settings - Privacy - Location Service is turn off or not shown.
1.2. When user re-launch your App. Because decision has been made in previous launch, so you can retrieve the state.
The first time after user made decision. This is obvious. After you call the startUpdatingLocation/startUpdatingHeading, then iOS show the UIAlertView.
In your answer's situation, user made changes in Settings, if your App is running in background, you'll receive the new state when your App become active. Otherwise, reference 1.2.
If your app is running in the background or not at all it will be called the moment the user returns to your application.
I encounter the same issue as well.
my solution is put the request gps authorization code in main loop.
I guess it can also works if you put in another run loop.
I ran into this problem of handling location permission changes correctly recently and did a lot of research and debugging.
If the app is not running at all and the user changes location permissions in Settings, then when you start your app, locationManager:didChangeAuthorizationStatus is called when the location manager is initialized as stated in mharper's answer. This behavior is not in Apple's docs.
If the app is in the background/suspended, I tested it in the simulator and it looks like the delegate function is also called.
Related
How can I check if user has exited the app, so I can make sure the app will shutdown?
I am currently using Swift - Xcode 6.3.1
In the AppDelegate class (AppDelegate.m) there is a function called applicationWillTerminate:(NSNotification*)notif. This function will be called when the application has been quit. This is where you put any code that you have to call before quitting the app (e.g. closing files, deleting timers, etc). This is automatically called when the app closes, you don't have to check yourself.
In iOS you don't (in general) terminate an app. You should design your app such that if the user moves away from it (e.g. presses the Home button) that it is ready for when they decide to come back. You also need to design it such that if iOS terminates it (e.g. due to memory limitations) that no user data is lost and that all is right next time the app launches (the general guidance here is that the user cannot tell that the app terminated - but a lot of apps don't succeed in that). But otherwise you do not need to do anything when the user 'goes away' from your app.
See this Apple document for the official line on not terminating. See this Apple document for more details on the App lifecycle in iOS.
The sole exception is that you may want to terminate if a fatal error occurs - in Swift you can use fatalError to do this, but it will look like a crash to your user.
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
My app has to run for a long time (also) in the background, due to Location Services.
When a certain condition is met the app has to move to the foreground.
I was able to run my app in the background and bring it to the front manually.
Reading up on this issue I got confused on how to move my app to the foreground by code.
It has to be in an if statement but what to do from here?
No do not think this is possible. You will be able to spawn a UILocalNotification to show application state to the user, but it is my understanding that iOS prevents you from making your app take focus.
you can't do that without user interaction. You can present a UILocalNotification
-- you can't even be sure iOS leaves it running though!
on a jailbroken phone I guess it is possible
This is clearly not possible, as it would be a mess if any app could just take over control at any point in time. As mentioned, you have to post a notification, and then it is up to the user if he or she wants to launch the app. If you notification states a good reason why they should launch your app, they might very well do it :-) And remember, don't mix up the user's needs with your/your app's needs.
Does anyone know how to detect if the user has force killed my app while the app is in the background? In the Apple documentation for the applicationWillTerminate: method it says this:
"For applications that support background execution, this method is generally not called when the user quits the application because the application simply moves to the background in that case. However, this method may be called in situations where the application is running in the background (not suspended) and the system needs to terminate it for some reason."
From my testing, when I force kill the app, my app still looks like it is tracking my location (the arrow is still at the top). But the cllocationmanager delegate method is not getting called until the app is relaunched, and the manager is stopped then started again. What is the best way, if any, to handle this situation?
Thanks!
UPDATE:
After looking into this post: Behaviour for significant change location API when terminated/suspended?
I'm still left with a problem. Because I'm using the method startUpdatingLocation, rather than the startMonitoringSignificantLocationChanges method. It looks like the application is only relaunched if you are logging significant changes. It seems to me that's it's kinda a hack to log significant changes just so I don't lose the app. Any ideas?
I am fairly new to iphone app development. I am creating an app that has multiple views. Initially it starts with a view for authentication and then load views according to user interaction. When I build and run the app - the first time it shows the "Default.png" screen and then shows the first view where I do my authentication process (typing in userid,password and do a web service) and then after the credentials are verified it takes me to the next view. When I close the app at this state in the simulator and reopen it again, I am seeing the same state in which I closed my app. But here is what I want. When I relaunch the app I should be able to show the "DEfault.png" and screen and then show my initial authentication view. Can you please help me out on this ? Thanks
It sounds like the problem you are trying to solve is that your authenticated session may time out while the app is suspended and you need to log in again.
Although the proposed solution (setting UIApplicationExistsOnSuspend to true) would work I think you should consider a different approach.
Apple recommends that you do everything you can to make it look like the phone supports multitasking. That is why, by default, your app will suspend and resume instead of exit and relaunch. In your case, though, you may need to re-login to resume the session. I offer you a couple of alternate solutions:
Cache the credentials (ie username and password) and silently use them to resume the session when needed. If the back-end supports this.
Detect when the session has become stale and bring in a view to inform the user that the session has expired and ask them to log in again. This would also address the issue if the user keeps the app active past the timeout of the session.
Both of these approaches should improve perceived app performance and integrate better into the Apple usability guidelines.
That's because iOS 4 apps are supposed to support multitasking. You can change the app so it doesn't: In Info.plist, set UIApplicationExitsOnSuspend to true (i.e. <key> UIApplicationExitsOnSuspend</key><true/>) — make sure it's a boolean and not a string. Note that this will probably make startup slower, since the app has to be launched again.
The other way is to handle applicationDidEnterBackground: in your app delegate and do two things:
Reset your view hierarchy (you can do this on next launch, but doing it earlier might help to free more memory)
Show "Default.png" in a full-screen view — iOS takes a screenshot of your app after it's hidden which it uses to animate the app back in.