Swift - detection when sending an application to the background, but not when locking the device

I’m developing an iOS application where I need to monitor whether the user leaves the application (pressing the "home" button to use other applications) while they are "in the game", however, the user must be able to block and disconnect their device without calling this function.

func applicationDidEnterBackground(application: UIApplication) {

    if defaults.boolForKey("TimerActive"){
        defaults.setBool(true, forKey: "Failed")
    }
}

This, unfortunately, is triggered when the user blocks their devices, as well as when they exit the application.

Small application context: the application encourages people to focus on their work and not be distracted by their phones for a given period of time. Other suggestions on how I can encourage users to reopen the application on exit while the timer is still active, but not when they lock their devices, would be very welcome!

+4
source share
1 answer

Well, there is no clean way to do this. But there is a hack that you can use. It is not guaranteed to continue to work (I tested before iOS 9.3, and I'm sure it works on iOS 10 beta).

, . / , , .

, . , . , , ( checkState). , , , . , , , . objc, (- , , )

@interface LockStateDetector : NSObject {
    int _notify_token;
}

@property BOOL deviceIsLocked;
@property BOOL appIsInBackground;
@property NSTimer * checkStateTimer;

@end

@implementation LockStateDetector

- (instancetype)init
{
    self = [super init];
    if (self) {
       [self registerForNotifications];
    }
    return self;
}

- (void)dealloc
{
   [[NSNotificationCenter defaultCenter] removeObserver:self];
   notify_cancel(_notify_token);
}

- (void)registerForNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMoveToBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    __weak__ LockStateDector * wSelf = self;
    notify_register_dispatch("com.apple.springboard.lockstate", &_notify_token, dispatch_get_main_queue(), ^(int token) {
        __strong__ LockStateDetector sSelf = wSelf;
        if (!sSelf) { 
            return;
        }
        uint64_t state = UINT64_MAX;
        notify_get_state(token, &state);
        sSelf.deviceIsLocked = state != 0;
        NSLog(@"device lock state changed: %@", @(state));
        [sSelf checkState];
    });
}

- (void)didBecomeActive
{
    self.appIsInBackground = NO;
    [self checkState];
}

- (void)didMoveToBackground
{
    self.appIsInBackground = YES;
    [self checkState];
}

- (void)checkState
{
    [self.checkStateTimer invalidate];
    self.checkStateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(_checkState) userInfo:nil repeats:NO];
}

- (void)_checkState
{
    [self.checkStateTimer invalidate];
    self.checkStateTimer = nil;

    if (!self.appIsInBackground) {
        return;
    }

    if (!self.deviceIsLocked) {
        // app is in background because device was locked
    } else {
       // app is in background because user pressed home and switched to something else
    }

}
0

Source: https://habr.com/ru/post/1652325/


All Articles