我正在开发一个iOS应用程序,我需要跟踪用户是否离开应用程序(按下主页按钮以使用其他应用程序),而他们在“游戏中”但是用户应该能够锁定和取消在没有调用此函数的情况下锁定其设备.
func applicationDidEnterBackground(application: UIApplication) { if defaults.boolForKey("TimerActive"){ defaults.setBool(true,forKey: "Failed") } }
不幸的是,当用户锁定他们的设备以及他们退出应用程序时,会触发此操作.
关于应用程序的一些背景:该应用程序鼓励人们专注于他们的工作,而不是在预设的时间段内被手机分心.
关于如何鼓励用户在退出时重新打开应用程序的其他建议,当计时器仍处于活动状态但不是在他们锁定设备时,将非常受欢迎!
解决方法
好吧,没有干净的方法来做到这一点.但是有一个你可以使用的黑客.它不能保证继续工作(我已经测试了iOS 9.3,我很确定它适用于iOS 10测试版).
这个想法是有一个系统范围的电话被锁定通知.你可以听到它,再加上听你的应用程序上的背景/前景事件,你可以确定发生了什么.
这是一个用于观察这些东西的对象的代码片段.从应用代表或任何地方创建它,并在您需要时保留强大的参考.给它一个委托,它可以调用你想要观察的任何事件并做出反应(或者将代码放在checkState中).我没有编译这个,所以我可能会输入一些错误.它源自我在应用程序中使用的代码,但原始文件中有更多我不会在此处发布的内容.这是objc,但转换为swift应该不会太难(有人可以随意发布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 } }