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

My app has different behavior when becoming active from the lockscreen (locked while active), or becoming active from anything else.

On iOS 6 and lower I could detect this

  • Objective-C Difference between setting nil and releasing
  • How do you load custom UITableViewCells from Xib files?
  • What is the entry point of swift code execution?
  • Play Alert Sound (Vibrate) While AudioQueue is Recording
  • How to have a UIBarButtonItem with both image and text
  • NSAttributedString and Links on iOS
  • UIApplicationState state = [[UIApplication sharedApplication] applicationState];
    if (UIApplicationStateInactive == state)
        // Coming from locked screen (iOS 6)
    else
        // Coming from Springboard, another app, etc...
    

    But on iOS 7, the state value is UIApplicationStateBackground in both scenarios. Is this the intended behavior? How can I properly detect whether the app is launching from the lockscreen now?

    Registered devs, I already posted this on the devforums before the NDA was lifted, see here

    2 Solutions Collect From Internet About “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.

    Actually the only proper way to set your app behavior when becoming active is via the app delegate methods.

    - (void)applicationWillEnterForeground:(UIApplication *)application
    {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }
    
    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
    

    These two are called when the app is running in the background and becomes active either via multitasking UI or after a call or other interruption.

    When the app is opened from the Springboard and is not running in the background this method is called:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        // Override point for customization after application launch.
        return YES;
    }