locking解锁事件iphone

如何检测iPhone上的locking/解锁事件? 假设它只能用于越狱的设备,你能指出我正确的API吗?

通过locking事件 ,我的意思是显示或隐藏locking屏幕(可能需要密码来解锁,或不)。

您可以使用达尔文通知来监听事件。 从我在越狱的iOS 5.0.1 iPhone 4上的testing中,我认为这些事件之一可能是你需要的:

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是您的事件callback:

 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事件发生在设备被locking解锁时,但lockcomplete事件只在设备locking时触发。 确定事件是否用于locking或解锁事件的另一种方法是使用notify_get_state() 。 如此处所述,您将获得locking与解锁的不同值。

回答一下:

应用程序将会在所有情况下都会被主动调用…即使您的应用程序在后台保持清醒时仍然保持清醒状态,也无法确定屏幕是否被locking(CPU速度不报告,总线速度保持不变,mach_time denom / numer不会改变)…

但是,似乎苹果确实closures加速度计,当设备被locking… 启用iPhone加速度计,同时屏幕locking (在iPhone 4上testing的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; } 

我知道…这是一种黑客,但迄今为止,它对我来说就像一个魅力。 如果您发现任何阻止此操作的问题,请更新。

有一种更好的方法来区分任务切换和屏幕locking源applicationWillResignActive: .WinResignActive applicationWillResignActive:callback,甚至不涉及诸如加速度计状态之类的未公开的function。

当应用程序移动到后台时,应用程序委托首先发送一个applicationWillResignActive: ,然后是一个applicationDidEnterBackground: 当按下“locking”button或来电时应用程序被中断,后一种方法不会被调用。 我们可以使用这些信息来区分这两种情况。

假如你想在screenLockActivated方法中被调用,如果屏幕被locking。 这是魔法:

 - (void)applicationWillResignActive:(UIApplication*)aApplication { [self performSelector:@selector(screenLockActivated) withObject:nil afterDelay:0]; } - (void)applicationDidEnterBackground:(UIApplication*)aApplication { [NSObject cancelPreviousPerformRequestsWithTarget:self]; } - (void)screenLockActivated { NSLog(@"yaay"); } 

说明:

默认情况下,我们假定每次调用applicationWillResignActive:都是因为一个活动 – >非活动状态转换(如locking屏幕时),但是我们慷慨地让系统在超时(在这种情况下,一个runloop周期)通过延迟调用screenLockActivated 。 在屏幕被locking的情况下,系统完成当前的循环周期而不触及任何其他委托方法。 但是,如果这是一个活动 – >后台状态转换,它还会在循环结束之前调用applicationDidEnterBackground:它允许我们简单地从那里取消先前调度的请求,从而防止它在不应该被调用的时候被调用。

请享用!

只需在使用此代码之前导入#import notify.h即可。 请享用!!

 -(void)registerAppforDetectLockState { int notify_token; notify_register_dispatch("com.apple.springboard.lockstate", &notify_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"); } NSLog(@"com.apple.springboard.lockstate = %llu", state); UILocalNotification *notification = [[UILocalNotification alloc]init]; notification.repeatInterval = NSDayCalendarUnit; [notification setAlertBody:@"Hello world!! I come becoz you lock/unlock your device :)"]; notification.alertAction = @"View"; notification.alertAction = @"Yes"; [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:1]]; notification.soundName = UILocalNotificationDefaultSoundName; [notification setTimeZone:[NSTimeZone defaultTimeZone]]; [[UIApplication sharedApplication] presentLocalNotificationNow:notification]; }); } 

在iOS 8中,您locking屏幕或按下主页button,所有这些使得应用程序在后台推送,但是不知道哪个操作符会导致这种情况。 我的解决scheme与Nits007ak一样,使用notify_register_dispatch获取状态。

 #import <notify.h> int notify_token notify_register_dispatch("com.apple.springboard.lockstate", &notify_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的参数来获取当前状态,当您想知道状态和屏幕状态不会改变时,这是非常有用的。

从大量的反复试验中,发现监控黑屏,locking完成和locking状态事件给出了一致的锁屏指示。 你需要监视一个状态转换。

 // call back void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { // notification comes in order of // "com.apple.springboard.hasBlankedScreen" notification // "com.apple.springboard.lockcomplete" notification only if locked // "com.apple.springboard.lockstate" notification AppDelegate *appDelegate = CFBridgingRelease(observer); NSString *eventName = (__bridge NSString*)name; NSLog(@"Darwin notification NAME = %@",name); if([eventName isEqualToString:@"com.apple.springboard.hasBlankedScreen"]) { NSLog(@"SCREEN BLANK"); appDelegate.bDeviceLocked = false; // clear } else if([eventName isEqualToString:@"com.apple.springboard.lockcomplete"]) { NSLog(@"DEVICE LOCK"); appDelegate.bDeviceLocked = true; // set } else if([eventName isEqualToString:@"com.apple.springboard.lockstate"]) { NSLog(@"LOCK STATUS CHANGE"); if(appDelegate.bDeviceLocked) // if a lock, is set { NSLog(@"DEVICE IS LOCKED"); } else { NSLog(@"DEVICE IS UNLOCKED"); } } } -(void)registerforDeviceLockNotif { // screen and lock notifications CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center CFBridgingRetain(self), // observer displayStatusChanged, // callback CFSTR("com.apple.springboard.hasBlankedScreen"), // event name NULL, // object CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center CFBridgingRetain(self), // observer displayStatusChanged, // callback CFSTR("com.apple.springboard.lockcomplete"), // event name NULL, // object CFNotificationSuspensionBehaviorDeliverImmediately); CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center CFBridgingRetain(self), // observer displayStatusChanged, // callback CFSTR("com.apple.springboard.lockstate"), // event name NULL, // object CFNotificationSuspensionBehaviorDeliverImmediately); } 

为了使屏幕locking指示符在后台运行,您需要在应用程序启动时实施后台处理以调用以下内容。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; }]; [self registerforDeviceLockNotif]; } 

截至本文撰写时,有两种相当可靠的方法来检测设备locking:


数据保护

通过启用数据保护权利,您的应用程序可以订阅applicationProtectedDataWillBecomeUnavailable:applicationProtectedDataDidBecomeAvailable:通知,以便以高概率确定何时使用密码/ TouchID身份validation的设备被locking/解锁。 要确定设备是否使用密码,可以查询TouchID LAContext


生命周期时间

如果您的应用程序处于前台,则根据触发它们的原因,两个生命周期事件UIApplicationWillResignActiveNotificationUIApplicationDidEnterBackgroundNotification之间的时间差异将会有明显变化。

(这是在iOS 10中testing,并可能在未来的版本中改变)

按下主页button会在两者之间产生明显的延迟(即使启用了简化运动设置):

 15:23:42.517 willResignActive 15:23:43.182 didEnterBackground 15:23:43.184 difference: 0.666346 

在应用程序打开的情况下locking设备会在两个事件之间产生一个更微不足道(<〜0.2s)的延迟:

 15:22:59.236 willResignActive 15:22:59.267 didEnterBackground 15:22:59.267 difference: 0.031404 

如果您的应用程序正在运行,并且用户locking了设备,则您的应用程序委托将收到对“应用程序将重新启用:”的调用。 如果您的应用程序在locking状态下运行,则会在设备解锁时收到对“应用程序无法成为活动:”的调用。 但是,如果用户接到电话,然后select忽略它,则可以获得与您的应用相同的呼叫。 据我所知,你无法分辨这个区别。

如果您的应用程序没有在这些时间运行,则没有办法通知您的应用程序没有运行。

如果设置了密码,您可以在AppDelegate中使用这些事件

 -(void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application { } - (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application { } 

获取屏幕locking和解锁事件的最简单方法是在视图控制器中使用NSNotificationCenter添加事件观察器。 我在viewdidload方法中添加了下面的观察者。 这就是我所做的:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; 

然后我将下面的select器添加到视图控制器。 屏幕解锁时,此select器将被调用。

  - (void)applicationEnteredForeground:(NSNotification *)notification { NSLog(@"Application Entered Foreground"); } 

如果要在屏幕locking时检测事件,则可以使用UIApplicationDidEnterBackgroundNotificationreplaceUIApplicationWillEnterForegroundNotification