Detecting When App Is Becoming Active from Lockscreen VS Other on iOS7

Detecting when app is becoming active from lockscreen vs other on iOS7

I was able to figure out a hack on this and so far seems to be reliable. It only works on the device, not the simulator, and has been tested on an iPhone 5s, 5 and 4S running iOS 7.

It seems that there is no possible way to detect where the app is being launched from on iOS 7, but there is a way to detect if you are going to the lock-screen vs springboard. The trick is to read the screen brightness in applicationDidEnterBackground. When the app hits the background due to the lock button being pressed or an auto-lock timeout, the brightness will be 0.0 on iOS 7. Otherwise, it will be > 0 when the home button is pressed or another app launched from the multitask selector or notification center.

- (void)applicationDidEnterBackground:(UIApplication *)application {
CGFloat screenBrightness = [[UIScreen mainScreen] brightness];
NSLog(@"Screen brightness: %f", screenBrightness);
self.backgroundedToLockScreen = screenBrightness <= 0.0;
}

Now that I have an ivar holding this info, I can use it in applicationWillEnterForeground to determine my app flow.

- (void)applicationWillEnterForeground:(UIApplication *)application {
if (self.backgroundedToLockScreen) {
... // app was backgrounded to lock screen
} else {
... // app was backgrounded on purpose by tapping the home button or switching apps.
}
self.backgroundedToLockScreen = NO;
}

It is not the exact same as the iOS 6 behavior though. On iOS 6, you could inspect the UIApplicationState to detect where you were coming from, and this solution answers the similar, but not exactly the same, question of where you were going when the app was backgrounded. For example, perhaps the app was backgrounded due to a screen lock timeout, but then a notification for another app woke the device, and the user went there directly from the lockscreen, then back to my app. My app would have determined on backgrounding that the user went to the lockscreen, but when they come back they are actually coming from an active screen. For my app, this difference is negligible, but your milage may vary.

So what about older OS support? My app also supports iOS 6 so I needed to get the old behavior too. Simple. Just the application state monitoring to the foreground method:

- (void)applicationWillEnterForeground:(UIApplication *)application {
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (UIApplicationStateInactive == state || // detect if coming from locked screen (iOS 6)
self.backgroundedToLockScreen) // detect if backgrounded to the locked screen (iOS 7)
{
... // app is coming from or was backgrounded to lock screen
} else {
... // app was backgrounded on purpose by tapping the home button or switching apps
}
self.backgroundedToLockScreen = NO;
}

I am not sure how reliable the brightness reading is, or whether or not it will change in future OS builds, but in the meantime, this hack seems to be the best we can get. Hope this helps.

Is it possible to distinguish between locking the device and sending an app to background?

iOS 6

In my preliminary testing via the simulator, checking the application state with

[[UIApplication sharedApplication] applicationState]

in either

- (void)applicationWillEnterForeground:(UIApplication *)application

- (void)applicationDidEnterBackground:(UIApplication *)application

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

How to detect if user actively relaunched the app by clicking the app icon?

Step 1:
When application is started and wasn't in the background before (suspended), application:didFinishLaunchingWithOptions: will execute first. This method carries launchOptions parameter - when it's nil, then your app was launched via icon tap in Springboard. Otherwise launchOptions will indicate the reason app was started (URL-scheme, Push Notification etc... more in documentation).

Step 2:
So far, so good. Now let's take care of resuming. When an app is resumed (or started), at some point it will call applicationDidBecomeActive in app's delegate. The trick is that this method is called after all possible reasons due to application can be resumed (started) were serviced. So all you need to do is introduce a BOOL flag that you'll set in methods servicing the reason your app was resumed and check it later in applicationDidBecomeActive against expected value.

A list (incomplete, I guess) of methods where your flag needs to be set:

  • application:handleOpenURL:
  • application:openURL:sourceApplication:annotation:
  • application:didReceiveLocalNotification:
  • application:didReceiveRemoteNotification:

The rest of methods you'll find in documentation mentioned above. And remember that applicationDidBecomeActive for Step 1 will also be called.

Good luck!

How Do I Tell What State My Application Is Being Launched From In Swift

That is the difference between application:didFinishLaunchingWithOptions: and applicationDidBecomeActive:.

application:didFinishLaunchingWithOptions: is only called when the application is starting new.

applicationDidBecomeActive: will be called when the app is becoming active again from the background. Note: applicationDidBecomeActive: is called on first launch as well. If you need to differentiate between the two cases, you have to do so using application:didFinishLaunchingWithOptions:. You could set a local variable to track if it was launched for the first time.

Can we detect whether a user left through the home button or lock button without listening to darwin notifications?

After searching through the documentation from apple and digging through a ton of threads I think I might have stumbled upon the solution.

As far as I know this is currently the only way of detecting whether a user left through the home button or lock button (I don't believe this works on the simulator you have to try it on an actual phone).

Inside of this delegate (And it will only work when called in this delegate)

func applicationDidEnterBackground(_ application: UIApplication) {

}

You can call this little snippet here:

func DidUserPressLockButton() -> Bool {
let oldBrightness = UIScreen.main.brightness
UIScreen.main.brightness = oldBrightness + (oldBrightness <= 0.01 ? (0.01) : (-0.01))
return oldBrightness != UIScreen.main.brightness
}

Usage:

func applicationDidEnterBackground(_ application: UIApplication) {
if (DidUserPressLockButton()) {
//User pressed lock button
} else {
//user pressed home button
}
}

EXPLANATION:

It seems that apple only lets you change the screen brightness from applicationDidEnterBackground when the user left through the lock button and not the home button. So the idea is to change the screen brightness with a miniscule amount and check to see if it was able to be changed. This seems kinda hacky but I've heard that this is actually working as intended. As far as testing it goes it seems to be working 100% of the time. I could not find any issues with this except for users that really do want to change the brightness of the screen. I hope someone else can find something less hacky and more concrete.

Detect if the app was launched/opened from a push notification

See This code :

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground )
{
//opened from a push notification when the app was on background
}
}

same as

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification


Related Topics



Leave a reply



Submit