I have an app that needs to do something when it’s sent to background using the Home button and something else when the device is locked using the top hardware button. The standard way of solving these requirements are the notifications and delegate methods sent out by UIApplication
. On iOS 4 they look like this:
// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.
// Pressing the lock button
Will resign active.
// Unlocking the device
Did become active.
In other words, it’s quite easy to tell between locking and backgrounding. On iOS 5 the behaviour changed:
// Pressing the home button
Will resign active.
Did enter background.
// Tapping app icon on Springboard
Will enter foreground.
Did become active.
// Pressing the lock button
Will resign active.
Did enter background.
// Unlocking the device
Will enter foreground.
Did become active.
Notice that the didEnterBackground
and willEnterForeground
notifications are now sent out even when (un)locking the device, making it impossible to tell between locking and backgrounding. Is this change documented somewhere? Is it a regression? Do you know another way to distinguish the two cases?
There’s a thread about this issue on Apple Developer Forums (registered developers only, sorry). The gist is that the new behaviour is by design. There are requests for a new API feature to distinguish between the two use cases, but nothing working yet.
Here is what Apple's iOS Programming Guide says:
http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
So, you should check the
UIApplication
'sapplicationState
property inapplicationDidEnterBackground:
. If it isUIApplicationStateBackground
the user pressed the home button. But if it isUIApplicationStateInactive
the user locked the device.iOS 6
In my preliminary testing via the simulator, checking the application state with
in either
allows you to differentiate between a call to lock the device and just switching back to the homescreen. A lock screen will return 1 (UIApplicationStateInactive), whereas a home button press will register as a 2 (UIApplicationStateBackground).
It seems consistent and should work on an iOS device just as reliably as it does in the simulator.
iOS 7
The iOS 6 method no longer works in iOS 7. In order to do this now, you have to utilize CFNotificationCenter and listen for a darwin notification (labeled: com.apple.springboard.lockcomplete). You can find the github repo with the sample project here: https://github.com/binarydev/ios-home-vs-lock-button
Credit for the iOS 7 fix goes out to wqq
I have looked into this quite a bit so I would love to be wrong here if someone knows something I don't, but technically, there is no documented way to tell the difference between locking the device, and sending to background.
One thing you can check however, is the
UIApplicationState
during the transition from foreground to background. Locking a device will giveUIApplicationStateInactive
and moving the App to the background will giveUIApplicationStateBackground
. But, since this behaviour is not officially documented it may change in the future.A basic example:
According to the UIApplicationDelegate Protocol Reference:
are the only methods that ever get called in both situations.
According to the iOS 4.3 to iOS 5.0 API Diff, these are the ONLY changes regarding
UIApplication
orUIApplicationDelegate
, so I couldn't find where they documented any of these notification changes:This is more of a workaround/hack, but according to my experience it's very reliable. When the device is screen-locked (not just home button-ed, if that's a word :)) - bound network (UDP) sockets are broken. I was using GCDAsyncUDPSocket (also AsyncUDPSocket before) and they both fire a network/broken pipe error reliably when the device is turned off. In my case I need the UDP socket anyway, for other apps it might be a bit smelly, however, just binding/listening on a UDP socket without any action is not too terrible if you really need to differentiate here.
This note will [self destruct]; is 5 minutes (so Apple won't find out).