I'm running into a bit of an issue.
My software needs to know when the application is in background so it will disconnect from the server, and start receiving push notifications.
For that I use UIApplicationDelegate's method :
- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void)applicationWillEnterForeground:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
- (void)applicationWillTerminate:(UIApplication *)application
The problem is, when a jailbroken device is using the "tweak" called backgrounder, that will force your application to stay active and not going into background, none of the UIApplicationDelegate's method get called when we click on the HOME button.
The thing is, each client connected in SSL cost me a lot of memory on the server. I do not really care that the device is jailbroken, or as a matter a fact, the application will run indefinitely on the device. But I would like them to disconnect from the server when the application is no longer on the screen, but I can't seems to find any method that will inform me of such operation when backgrounder is installed.
Solution find : check my own answer on the post
The best thing to do would to eat up A LOT of memory so that way the jail breakers would have to quit your application! Just kidding of course. The best option is to wait for inactivity on the user's side. For example: 1. Check if the device is jailbroken. 2. Check if backgrounder is installed (I am not sure if you can do this but I am pretty sure you can). 3. If the user is all those things wait for them to be inactive for, lets say, 30 seconds and then disconnect from the server.
Do none of those methods get called at all in your app when Backgrounder is installed, or only when your app transitions to the background? If they never get called at all, then the solution is extremely simple: Set a timer for, say, 10 seconds, when your app's application:didFinishLaunchingWithOptions method is called, and when that timer expires, if applicationDidBecomeActive: has not been called, then you know that the user is using Backgrounder.
If they do get called on app launch, though, then things get trickier. I'm not aware of any direct methods to detect if a tweak like Backgrounder is installed from within the sandbox. You could simply check if the device is jailbroken (there are a number of ways to do this, they should be easy to find), and add a timeout period for your server connection if so.
Milk Tea got me on the right track... So the bounty goes to him.
But actually I got a better solution...
I have checked every single notifications thrown when resigning the App...
and I got this, even with backgrounder configured to keep the App open, those notifications are thrown :
UIApplicationSuspendedEventsOnlyNotification -- When going into background
UIApplicationResumedEventsOnlyNotification -- When going into foreground
This makes sense, since even with backgrounder, it would have been a bad idea to let the App keep receiving events notifications, for example, when a change of rotation (or a shake) is done outside the App. Do you imagine every App doing a rotation on background everytime you move your iphone ?
Related
While the device is powered on, is it possible for iOS to automatically terminate my app (calling applicationWillTerminate:) while it's in the background?
I'm also curious what happens in two other cases, three in total:
Device is powered on
Device is powered off
Device loses battery
I'm asking because I want to know how often applicationWillTerminate: is likely to get called. I want to know this because that's where I'm registering for remote notifications. And if there's a failure sending the device token to the server, I want to know how likely it is that that method will get called again (i.e., retry sending the device token to the server).
If your application supports multitasking (the default for anything linked against iOS 4.0+), this method will almost never be called. The documentation says it may be called in cases where the application is running in the background and the system wants to terminate. However, in my experience, I've only ever seen this actually called when running a music app that's actively playing music in the background and the system is jettisoning everything. In cases where I have background tasks running (not music, but short-term background tasks), I've seen the app terminated without this method being called.
I wouldn't ever rely on this being called and try and do all the clean-up you need to do in your delegate methods for transitioning into the background and your background task completion blocks (which do get executed for at least a few seconds before the app gets jettisoned).
Not only can iOS terminate your app automatically, but the user can kill it manually. In fact, the only time the user can kill your app is when it's in the background. Furthermore, when your app is "in the background" it's more likely to be suspended than actually running, so don't count on doing a lot of processing when you're not the foreground app.
As for how likely it is that you'll get -applicationWillTerminate:, that'll depend on the user and how they're using their device. You should handle it appropriately when you get it, and go about your business otherwise.
When memory is running low, iOS can shut down your app, calling applicationWillTerminate.
The docs say this about the method:
... 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.
Check out iOS Developer Library : iOS App Programming Guide : App Termination.
So here is the issue I am facing. Certain portions of the application I am building open some c network sockets that allow connections to various servers/services. However, if the application goes to sleep, these socket connections are lost, and error out when trying to reload them. So what I want to do is basically notify the user when the app launches again, that the application needs to be restarted. The main question is, can I present them with a button that will kill the app by using exit(0) without my app getting rejected?
Apple says that the user should be in control of when the app is killed, and in this case I see that they are, but I am not sure of Apple's opinion on this. Has anyone else used this? Have you been rejected for this? Thanks in advance for any advice!
EDIT:
Thank you everyone for your advice. I am trying to take everything into consideration, but because the app needs to be submitted ASAP, I just need to know, if we can not get another solution, if the above proposed solution, will get rejected or not.
Your application delegate receives notifications when significant events affect the life of the application. Rather than ask your user to recreate a session, you should attempt to discontinue network operations and then resume them at the appropriate times in the application's lifecycle automatically.
You can gracefully kill network sockets (amongst other things) in any number of places as the application prepares to exit or enter the background via callbacks in your application delegate:
applicationWillResignActive:
applicationWillEnterBackground:
applicationWillTerminate:
Potentially reconstruct sockets in:
applicationDidBecomeActive
applicationWillEnterForeground
Have you tried not allowing the app to run in the background? Then it will be killed whenever the user exits to the home screen. This might be a bit aggressive, but would solve the problem. From Apple's opting out of background execution:
"If you do not want your application to remain in the background when
it is quit, you can explicitly opt out of the background execution
model by adding the UIApplicationExitsOnSuspend key to your
application’s Info.plist file and setting its value to YES.
When an application opts out, it cycles between the not running,
inactive, and active states and never enters the background or
suspended states.
When the user taps the Home button to quit the application, the
applicationWillTerminate: method of the application delegate is called
and the application has approximately five seconds to clean up and
exit before it is terminated and moved back to the not running state."
See also: How to prevent my app from running in the background on the iPhone
The documentation is pretty explicit about this, "There is no API provided for gracefully terminating an iOS application." See Technical Q&A QA1561
How do I programmatically quit my iOS application?.
To be blunt, terminating an app to cleanup a socket is just like dealing with memory management by forcing an app to exit instead of calling release.
What about bringing up a modal view controller telling the user to quit the application? You could make this view controller without any dismiss button, so the user is obligated to kill the app.
My app connects to a Bluetooth sensor then starts updating the UI based on the notifications sent from said device. I am having a problem with IOS automatically generating a large amount of notification pop-ups when the app is minimized, I think this is due to the frequency at which the sensor is sending data. So I am trying to figure out how to keep the user from being bombarded when they minimize the app. I am trying to tell the device to stop sending data, but I suspect that delegate method never gets called.
I have tried adding
[application cancelAllLocalNotifications]
to both
- (void)applicationDidEnterBackground:(UIApplication *)application
and
- (void)applicationWillResignActive:(UIApplication *)application
but still seem to have an issue, any ideas.
Thanks
You can use CBPerpheral::setNotifyValue:forCharacteristic: to start or stop getting notification from the said peripheral.
Another option is to use session backgrounding. For that you need to add the bluetooth-central backgrounding mode to the app's plist file. After that the app is going to receive the bluetooth communication events both in foreground and background and no notifications will be generated by iOS. If your app decides it needs a notfification, it can simply generate a local notification (tutorial).
I have determined experimentally using a couple devices that (as far as I can tell) iOS devices running iOS 4 call applicationWillResignActive when they go to sleep (either when the user presses the top right button, or when the screen shuts off due to inactivity, but the app is still running), but devices running iOS 5 call applicationDidEnterBackground when this happens, and only call applicationWillResignActive for something like an incoming text message/phone call, or the user pulling down the notification bar (in other words, very temporary events).
The iOS device going to sleep, however, is not a very short event (could be a very long one) and thus for that case I'd like to cancel the current server call, which I don't need to do (and don't want to do) for very short interruptions.
My question is: is there a way to tell when the app has gone to sleep as opposed to any other shorter interruption (ie text message), and/or, alternatively, does anyone know if my guess above about what iOS 4 vs 5 devices call when they go to sleep is indeed correct?
This is what I have right now, in applicationWillResignActive:
if ([[[UIDevice currentDevice]systemVersion] hasPrefix:#"4"] ) {
//cancel server call
}
This works fine as far as I can tell, but every thread I've read about how to determine iOS version on the device says that you shouldn't use that code if possible, and should instead call the correct selector for what you're trying to do. But I've no idea what that would be in this case.
In this post: Understanding iOS 4 Backgrounding and Delegate Messaging, you can find an excellent explanation of when the delegate messages are sent. In particular, it explains when applicationWillResignActive and applicationDidEnterBackground are sent, according to different iOS versions.
I hope it helps you.
Cheers
Hee
Does anybody know how to recognize a multitask-kill.
When the user puts the application in background state and then kills the app through the menu in iOS 4.2 my application shuts down.
Before there used to be an function called:
- (void)applicationWillTerminate:(UIApplication *)application
This method is not called anymore in iOS 4 and higher.
Is there a way to recognize it?
Thanks already.
Actually that's not entirely true. It is called on iOS4 devices that do not support multi-tasking and the documentation says that it can be called on other handsets (though I've never seen it myself).
But to answer your question, no, you can't recognise when a user kills your app. If you have state that you want to save you need to do this when your app goes into the background and not when the app is killed.
If you look at the crash reports you'll see that iOS sends SIGKIL which you can't catch.
You cannot catch this, your processed really is killed. Hard. Without notice. That us why you need to save state when you enter background now.
Maybe setting up a signal handler might work (don't know which signal to catch, though).