如何在iPhone上检测锁定/解锁事件?假设它只能用于越狱设备,你能指出我正确的API吗?
通过锁定事件,我的意思是显示或隐藏锁定屏幕(可能需要密码才能解锁).
您可以使用Darwin通知来侦听事件.从我在越狱的iOS 5.0.1 iPhone 4上的测试中,我认为其中一个事件可能就是你所需要的:
com.apple.springboard.lockstate com.apple.springboard.lockcomplete
注意:根据海报对我在这里回答的类似问题的评论,这也适用于非越狱手机.
要使用它,请注册这样的事件(这只注册上面的第一个事件,但你也可以添加一个观察者lockcomplete
):
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center (void*)self, // observer (can be NULL) lockStateChanged, // callback CFSTR("com.apple.springboard.lockstate"), // event name NULL, // object CFNotificationSuspensionBehaviorDeliverImmediately);
lockStateChanged
你的事件回调在哪里:
static void lockStateChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { NSLog(@"event received!"); if (observer != NULL) { MyClass *this = (MyClass*)observer; } // you might try inspecting the `userInfo` dictionary, to see // if it contains any useful info if (userInfo != nil) { CFShow(userInfo); } }
lockstate
设备锁定和解锁时会发生此事件,但lockcomplete
仅在设备锁定时触发事件.确定事件是用于锁定还是解锁事件的另一种方法是使用notify_get_state()
.你会得到锁定与解锁不同的值,如本文所述.
回答:
应用程序将在各种情况下调用活动调用...并且从我的所有测试中,即使您的应用程序在后台运行时保持清醒状态,也无法确定屏幕是否已锁定(CPU速度未报告,总线速度保持不变,mach_time denom/numer不会改变)......
但是,当设备锁定时,Apple似乎关闭了加速计... 在屏幕锁定时启用iPhone加速计 (在iPhone 4上测试iOS4.2有此行为)
从而...
在您的应用程序委托中:
- (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"STATUS - Application will Resign Active"); // Start checking the accelerometer (while we are in the background) [[UIAccelerometer sharedAccelerometer] setDelegate:self]; [[UIAccelerometer sharedAccelerometer] setUpdateInterval:1]; // Ping every second _notActiveTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(deviceDidLock) userInfo:nil repeats:NO]; // 2 seconds for wiggle } //Deprecated in iOS5 - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { NSLog(@"STATUS - Update from accelerometer"); [_notActiveTimer invalidate]; _notActiveTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(deviceDidLock) userInfo:nil repeats:NO]; } - (void)deviceDidLock { NSLog(@"STATUS - Device locked!"); [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; _notActiveTimer = nil; } - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"STATUS - Application did become active"); [[UIAccelerometer sharedAccelerometer] setDelegate:nil]; [_notActiveTimer invalidate]; _notActiveTimer = nil; }
我知道......这是一种黑客行为,但到目前为止,它对我来说就像是一种魅力.如果您发现任何阻止其工作的问题,请更新.
有一种更漂亮的方法可以分辨任务切换和屏幕锁定发起的applicationWillResignActive:
回调,甚至不涉及无记录功能,如加速度计状态.
当应用程序移动到后台时,应用程序委托首先发送一个applicationWillResignActive:
,然后发送一个applicationDidEnterBackground:
.当通过按下"锁定"按钮或来电来中断应用程序时,不会调用后一种方法.我们可以使用此信息来区分这两种情况.
假设您希望screenLockActivated
在屏幕被锁定时在方法中回调.这是魔术:
- (void)applicationWillResignActive:(UIApplication*)aApplication { [self performSelector:@selector(screenLockActivated) withObject:nil afterDelay:0]; } - (void)applicationDidEnterBackground:(UIApplication*)aApplication { [NSObject cancelPreviousPerformRequestsWithTarget:self]; } - (void)screenLockActivated { NSLog(@"yaay"); }
说明:
默认情况下,我们假设每次调用applicationWillResignActive:
都是因为活动 - >非活动状态转换(如锁定屏幕时),但我们慷慨地让系统通过延迟在超时(在这种情况下,单个runloop循环)中证明相反打电话给screenLockActivated
.如果屏幕被锁定,系统将完成当前的runloop循环,而不会触及任何其他委托方法.但是,如果这是一个active-> background状态转换,它也会applicationDidEnterBackground:
在循环结束之前调用,这允许我们从那里简单地取消先前调度的请求,从而防止它在不应该被调用时被调用.
请享用!
截至撰写本文时,有两种相当可靠的方法来检测设备锁定:
通过启用数据保护权利,您的应用可以订阅applicationProtectedDataWillBecomeUnavailable:
和applicationProtectedDataDidBecomeAvailable:
通知,以很可能确定锁定/解锁使用密码/ TouchID身份验证的设备的时间。LAContext
可以查询以确定设备是否使用密码/ TouchID 。
注意事项:此方法依赖于与手机被锁定相一致的“受保护的数据变得不可用”。当手机使用TouchID并按下睡眠/锁定按钮时,手机将被锁定,受保护的数据将不可用,并且将需要立即输入密码来再次解锁。这意味着受保护的数据将变得不可用,本质上表示电话已被锁定。当某人仅使用密码时,这不一定是正确的,因为他们可以将“需要密码”的时间设置为从立即到4小时之类的任何时间。在这种情况下,手机将报告能够处理受保护的数据,但是锁定手机不会导致受保护的数据在相当长的时间内不可用。
如果您的应用位于前台,则这两个生命周期事件之间的时差将发生明显变化UIApplicationWillResignActiveNotification
,UIApplicationDidEnterBackgroundNotification
具体取决于触发它们的原因。
(这已在iOS 10中进行了测试,并可能在将来的版本中更改)
按下主屏幕按钮会导致两者之间有很大的延迟(即使启用了“降低动作”设置):
15:23:42.517 willResignActive 15:23:43.182 didEnterBackground 15:23:43.184 difference: 0.666346
在应用打开时锁定设备会在两个事件之间产生更微不足道的(<〜0.2s)延迟:
15:22:59.236 willResignActive 15:22:59.267 didEnterBackground 15:22:59.267 difference: 0.031404
在iOS 8中,您可以锁定屏幕或按下主屏幕按钮,所有这些操作都会使应用程序在后台推送,但是您不知道是哪个操作员导致了这种情况。我的解决方案与Nits007ak相同,请使用notify_register_dispatch获取状态。
#importint notify_token notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_token, dispatch_get_main_queue(), ^(int token) { uint64_t state = UINT64_MAX; notify_get_state(token, &state); if(state == 0) { NSLog(@"unlock device"); } else { NSLog(@"lock device"); } } );
只要应用程序在前台或后台运行。不暂停,您可以获取此事件。
而且您可以将notify_token用作notify_get_state的参数以在任何地方获取当前状态,这在您希望了解状态和屏幕状态不变的情况下非常有用。