12

I need to do something in applicationDidEnterBackground. But I need to differentiate which user action causes the "enter background": screen lock or home button press.

I was using this code, which is from this post - How to differentiate between screen lock and home button press on iOS5?:

UIApplicationState state = [application applicationState];
if (state == UIApplicationStateInactive) {
    NSLog(@"Sent to background by locking screen");
} else if (state == UIApplicationStateBackground) {
    NSLog(@"Sent to background by home button/switching to other app");
}

It works fine on iOS6. but on iOS7 (both device and simulator), I always get UIApplicationStateBackground, whether the user clicks the home or the lock button.

Does someone have an idea about what could cause this? iOS 7 updates to multi-task background handling? Or some setting of my app (my app's background mode is off)?

And is there an alternative solution?

Community
  • 1
  • 1
Perisheroy
  • 239
  • 4
  • 8
  • possible duplicate of [How to differentiate between screen lock and home button press on iOS5?](http://stackoverflow.com/questions/8303703/how-to-differentiate-between-screen-lock-and-home-button-press-on-ios5) – jamesmortensen Nov 05 '13 at 02:07
  • I think I didn't state it clearly enough. I read the post on your link but that doesn't work any more in iOS7. I don't think it's a duplicate . But anyway, I edit my question to make it clear. – Perisheroy Nov 05 '13 at 20:16
  • Good idea to clarify, plus the edit bumps your post back to the top so others see it again. :D – jamesmortensen Nov 06 '13 at 07:57
  • @Perisheroy I also have the same problem. Did you find any solution for that problem? If found please help me. – Archive Feb 04 '14 at 10:25

3 Answers3

19

This can help you both on iOS6 & iOS7 :).

When user press lock button you will get a com.apple.springboard.lockcomplete notification.

//new way
//put this in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                    NULL,
                                    displayStatusChanged,
                                    CFSTR("com.apple.springboard.lockcomplete"),
                                    NULL,
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

//put this function in AppDelegate
static void displayStatusChanged(CFNotificationCenterRef center,
                                 void *observer,
                                 CFStringRef name,
                                 const void *object,
                                 CFDictionaryRef userInfo) {
    if (name == CFSTR("com.apple.springboard.lockcomplete")) {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kDisplayStatusLocked"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

//put this in onAppEnterBackground
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
    if (state == UIApplicationStateInactive) {
        NSLog(@"Sent to background by locking screen");
    } else if (state == UIApplicationStateBackground) {
        if (![[NSUserDefaults standardUserDefaults] boolForKey:@"kDisplayStatusLocked"]) {
            NSLog(@"Sent to background by home button/switching to other app");
        } else {
            NSLog(@"Sent to background by locking screen");
        }
    }

//put this in - (void)applicationWillEnterForeground:(UIApplication *)application
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"kDisplayStatusLocked"];
[[NSUserDefaults standardUserDefaults] synchronize];

CGFloat screenBrightness = [[UIScreen mainScreen] brightness];

NSLog(@"Screen brightness: %f", screenBrightness);

UIApplicationState state = [[UIApplication sharedApplication] applicationState];

if (state == UIApplicationStateInactive) {

    NSLog(@"Sent to background by locking screen");

} else if (state == UIApplicationStateBackground) {
    if (screenBrightness > 0.0) {
        NSLog(@"Sent to background by home button/switching to other app");
    } else {
        NSLog(@"Sent to background by locking screen");
    }
}

wqq
  • 239
  • 1
  • 6
  • 2
    If you find a duplicate question, the correct action, once you have 15 rep, is to flag the post as a duplicate. Simply posting the same copy/paste answer around the site is not what we're about, and this creates noise. – jamesmortensen Nov 05 '13 at 02:07
  • @jmort253 Sorry, I don't know I should do like this. I am new user, but my answer is right I think. – wqq Nov 05 '13 at 02:37
  • not working for me. test it on iOS 7 (simulator and device). I don't think this is the right way of using [[UIScreen mainScreen] brightness]. According to apple library documents, it's just a setting for screen brightness in this app, not necessary current screen brightness level. – Perisheroy Nov 05 '13 at 20:09
  • @Perisheroy I am sure that will work on iOS7 device, I have test it on my and my friend's iOS7 iPhone5. You can put code snippet in `- (void)applicationDidEnterBackground:(UIApplication *)application` at your appDelegate.m. It is not work on iOS simulator, sorry I have not mention that before. – wqq Nov 11 '13 at 18:03
  • This is currently not working in the latest iOS 7 simulator. I can provide a video showing this if you'd like. – Jose Rafael Santiago Jr. Feb 20 '14 at 15:58
  • @JoseRafaelSantiagoJr. I have update my code. Please try this way again :). – wqq Feb 22 '14 at 18:20
  • @wqq Thanks for the update. It works beautifully! I put everything into a sample project on github for others to check out with credit given to you in the README: https://github.com/binarydev/ios-home-vs-lock-button – Jose Rafael Santiago Jr. Feb 24 '14 at 17:28
  • Will it be rejected by Apple? But you save my life. Thanks – SeanChense Aug 19 '15 at 02:47
  • @SeanChense It would not be rejected, I have submit my app many times. – wqq Aug 20 '15 at 04:37
  • Just tried it on iOS 9 and it worked WONDERFULLY. Thank you for such a great solution! – Kenny Wyland Dec 02 '15 at 19:20
  • @KennyWyland did your app make it through review without problems? – random Mar 08 '16 at 15:51
  • It depends on apple I guess. If the tester is not having a great day, your app will be rejected. – nr5 May 01 '18 at 08:30
  • mine got rejected – FH- Feb 26 '20 at 12:07
2

This solution was taken from this answer and worked for me. It is a bit hacky but it makes it easier to be accepted on the appstore because it doesn't use com.apple.springboard.lockcomplete or com.apple.springboard.lockstate.

The following code goes into your AppDelegate:

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

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

The idea is to try changing the brightness of the screen after the application went to background and to check if this change was successful.

Disclaimer: it doesn't work on the simulator and you will have to test it on a real device.

MCSim
  • 41
  • 1
  • 7
  • 1
    the thing is when the app is already in the background then the user locks the screen it cant detect the action. – FH- Feb 26 '20 at 12:08
0

It doesn't work in Swift, you need to do some modification to make it work in Swift as follow

1.create a objectiveC file named LockNotifierCallback.m as follow:

static void displayStatusChanged(CFNotificationCenterRef center,
                                 void *observer,
                                 CFStringRef name,
                                 const void *object,
                                 CFDictionaryRef userInfo) {
    if ([(__bridge NSString *)name  isEqual: @"com.apple.springboard.lockcomplete"]) {
        NSLog(@"Screen Locked");
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kDisplayStatusLocked"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

@implementation LockNotifierCallback

+ (void(*)(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo))notifierProc {
return displayStatusChanged;
}

@end

create a head as well: #import

@interface LockNotifierCallback : NSObject


+ (void(*)(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo))notifierProc;


@end

2.bridge this file to swift

3.add function to APPdelegate.swift:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), nil, LockNotifierCallback.notifierProc(), "com.apple.springboard.lockcomplete", nil, CFNotificationSuspensionBehavior.DeliverImmediately)

PS:UIApplicationState doesn't work perfectly in here