Swift - 检测应用程序何时发送到后台但不是设备被锁定时

时间:2016-08-24 11:23:25

标签: ios swift appdelegate

我正在开发一个iOS应用程序,我需要跟踪用户是否离开应用程序(按下主页按钮以使用其他应用程序),而他们在“游戏中”但是用户应该能够锁定并且在没有调用此函数的情况下取消锁定他们的设备。

tXt ask(tXt prmp) {
  printf("%s ?",prmp) ;
  return(txtFromFile(stdin)) ; }



void main(void) {
  tXt user = ask("user") ;
  if ( strcmp(txtConcat(user,"/",ask("password"),NULL),"waw/wow") == 0)
    printf("You have logged in\n"); 
  else
    printf("Failed, please try again\n");
}

不幸的是,当用户锁定他们的设备以及退出应用程序时,会触发此操作。

关于应用程序的一些背景:该应用程序鼓励人们专注于他们的工作,而不是在预设的时间段内被手机分心。 关于我如何鼓励用户在计时器仍处于活动状态时退出时重新打开应用程序的其他建议,而不是当他们锁定设备时,将非常欢迎!

1 个答案:

答案 0 :(得分:0)

嗯,没有干净的方法可以做到这一点。但是有一个你可以使用的黑客。它不能保证继续工作(我已经测试过iOS 9.3并且我非常确定它适用于iOS 10测试版)。

这个想法是,手机被锁定的系统范围通知。您可以聆听这一点,并结合在应用上收听背景/前景事件,您可以确定发生了什么。

这是一个用于监视此内容的对象的代码。从应用代表或任何地方创建它,并在您需要时保留强大的参考。给它一个委托,它可以调用你想要观察的任何事件并做出反应(或者将代码放在checkState中)。我没有编译这个,所以我可能会输入一些错误。它来自我在应用程序中使用的代码,但是原始文件中有更多我在这里发布的内容。它在objc中,但它不应该太难转换为swift(有人可以随意发布第二个答案或编辑我的,但我没有时间做正确的事情现在)

@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
    }

}