ios 锁定 解锁事件 iphone
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/706344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lock Unlock events iphone
提问by
How can I detect lock/unlock events on the iPhone? Assuming it's only possible for jailbroken devices, can you point me to the correct API?
如何检测 iPhone 上的锁定/解锁事件?假设它只适用于越狱设备,你能指出我正确的 API 吗?
By lock events, I mean showing or hiding the Lock Screen (which might need a password to unlock, or not).
通过锁定事件,我的意思是显示或隐藏锁定屏幕(可能需要密码才能解锁)。
回答by Nate
You can use Darwin notifications, to listen for the events. From my testing on a jailbroken iOS 5.0.1 iPhone 4, I think that one of these events might be what you need:
您可以使用Darwin 通知来监听事件。从我对越狱的 iOS 5.0.1 iPhone 4 的测试来看,我认为这些事件之一可能是您需要的:
com.apple.springboard.lockstate
com.apple.springboard.lockcomplete
Note:according to the poster's comments to a similar question I answered here, this should work on a non-jailbroken phone, too.
注意:根据发帖人对我在此处回答的类似问题的评论,这也应该适用于未越狱的手机。
To use this, register for the event like this (this registers for just the first event above, but you can add an observer for lockcomplete
, too):
要使用它,请像这样注册事件(这仅注册上面的第一个事件,但您也可以为 添加观察者lockcomplete
):
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
(void*)self, // observer (can be NULL)
lockStateChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
where lockStateChanged
is your event callback:
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);
}
}
The lockstate
event occurs when the device is locked andunlocked, but the lockcomplete
event is only triggered when the device locks. Another way to determine whether the event is for a lock or unlock event is to use notify_get_state()
. You'll get a different value for lock vs. unlock, as described here.
该lockstate
事件在设备锁定和解锁时发生,但该lockcomplete
事件仅在设备锁定时触发。确定事件是针对锁定事件还是解锁事件的另一种方法是使用notify_get_state()
. 您将获得不同的 lock 与 unlock 值,如此处所述。
回答by BadPirate
Round about answer:
轮回答案:
Application will resign active gets called in all sorts of scenarios... and from all my testing, even if your application stays awake while backgrounded, there are no ways to determine that the screen is locked (CPU speed doesn't report, BUS speed remains the same, mach_time denom / numer doesn't change)...
应用程序将在各种情况下被调用激活...从我所有的测试来看,即使您的应用程序在后台保持唤醒状态,也无法确定屏幕已锁定(CPU 速度不报告,总线速度保持不变,mach_time denom / numer 不变)...
However, it seems Apple does turn off the accelerometer when the device is locked... Enable iPhone accelerometer while screen is locked(tested iOS4.2 on iPhone 4 has this behavior)
然而,当设备被锁定时,Apple 似乎确实关闭了加速度计......在屏幕锁定时启用 iPhone 加速度计(在 iPhone 4 上测试的 iOS4.2 有这种行为)
Thus...
因此...
In your application delegate:
在您的应用程序委托中:
- (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;
}
I know... It's kind of a hack, but it has worked like a charm for me so far. Please update if you see any issues that prevent this from working.
我知道......这有点像黑客,但到目前为止它对我来说就像一种魅力。如果您发现任何阻止此功能正常工作的问题,请更新。
回答by Lvsti
There is a prettier way of telling apart task switching and screen locking-originated applicationWillResignActive:
callbacks which doesn't even involve undocumented features such as the accelerometer state.
有一种更漂亮的方式来区分任务切换和屏幕锁定引发的applicationWillResignActive:
回调,它甚至不涉及未记录的功能,例如加速度计状态。
When the app is moving to the background, the app delegate is first sent an applicationWillResignActive:
, then an applicationDidEnterBackground:
. When the app is interrupted by pressing the Lock button or by an incoming phone call, the latter method is not called. We can use this information to distinguish between the two scenarios.
当应用程序移至后台时,应用程序委托首先发送一个applicationWillResignActive:
,然后发送一个applicationDidEnterBackground:
. 当应用程序因按下锁定按钮或来电而中断时,不会调用后一种方法。我们可以使用这些信息来区分这两种情况。
Say you want to be called back in the screenLockActivated
method if the screen gets locked. Here's the magic:
假设您希望screenLockActivated
在屏幕被锁定时在方法中被回调。这是魔法:
- (void)applicationWillResignActive:(UIApplication*)aApplication
{
[self performSelector:@selector(screenLockActivated)
withObject:nil
afterDelay:0];
}
- (void)applicationDidEnterBackground:(UIApplication*)aApplication
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
- (void)screenLockActivated
{
NSLog(@"yaay");
}
Explanation:
解释:
By default, we assume that every call to applicationWillResignActive:
is because of an active->inactive state transition (as when locking the screen) but we generously let the system prove the contrary within a timeout (in this case, a single runloop cycle) by delaying the call to screenLockActivated
. In case the screen gets locked, the system finishes the current runloop cycle without touching any other delegate methods. If, however, this is an active->background state transition, it also invokes applicationDidEnterBackground:
before the end of the cycle, which allows us to simply cancel the previously scheduled request from there, thus preventing it from being called when it's not supposed to.
默认情况下,我们假设每次调用applicationWillResignActive:
都是因为 active->inactive 状态转换(如锁定屏幕时),但我们慷慨地让系统在超时(在这种情况下,单个 runloop 循环)内通过延迟证明相反对 的调用screenLockActivated
。如果屏幕被锁定,系统会在不接触任何其他委托方法的情况下完成当前的 runloop 循环。然而,如果这是一个 active->background 状态转换,它也会applicationDidEnterBackground:
在循环结束之前调用,这允许我们从那里简单地取消先前安排的请求,从而防止它在不应该被调用时被调用。
Enjoy!
享受!
回答by Warpling
As of the time of writing there are two fairly reliable ways to detect device locking:
在撰写本文时,有两种相当可靠的方法来检测设备锁定:
Data Protection
数据保护
By enabling the Data Protection entitlementyour app can subscribe to the applicationProtectedDataWillBecomeUnavailable:
and applicationProtectedDataDidBecomeAvailable:
notifications to determine with high probability when a device that uses passcode/TouchID Authentication is locked/unlocked. To determine if a device uses a passcode/TouchID LAContext
can be queried.
通过启用数据保护权利,您的应用程序可以订阅applicationProtectedDataWillBecomeUnavailable:
和applicationProtectedDataDidBecomeAvailable:
通知,以确定使用密码/TouchID 身份验证的设备何时被锁定/解锁的可能性很高。要确定设备是否使用密码/LAContext
可以查询TouchID 。
Caveats: This method relies on the "protected data becoming unavailable" coinciding with the phone being locked. When the phone is using TouchID and the sleep/lock button is pressed then the phone is locked, protected data becomes unavailable, and a passcode will immediately be required to unlock it again. This means that protected data becoming unavailable essentially indicates that the phone has been locked. This is not necessarily true when someone is using just a passcodesince they can set the "requires passcode" time to anywhere from immediatelyto something like 4 hours. In this case the phone will report being able to handle protected data but locking the phone will not result in protected data becoming unavailable for quite some time.
注意事项:此方法依赖于“受保护的数据变得不可用”与手机被锁定同时发生。当手机使用 TouchID 并按下睡眠/锁定按钮时,手机被锁定,受保护的数据将不可用,并且将立即需要密码才能再次解锁。这意味着受保护的数据变得不可用本质上表明手机已被锁定。当某人仅使用密码时,这不一定是正确的,因为他们可以将“需要密码”时间设置为从立即到4 小时之类的任何时间。在这种情况下,手机将报告能够处理受保护的数据,但锁定手机不会导致受保护的数据在相当长一段时间内不可用。
Lifecycle Timing
生命周期计时
If your app is in the foreground there will be a noticeable change in time difference between the two lifecycle events UIApplicationWillResignActiveNotification
and UIApplicationDidEnterBackgroundNotification
depending on what triggers them.
如果您的应用程序在前台,则两个生命周期事件之间的时间差将发生明显变化UIApplicationWillResignActiveNotification
,UIApplicationDidEnterBackgroundNotification
具体取决于触发它们的原因。
(This was tested in iOS 10 and may change in future releases)
(这是在 iOS 10 中测试的,可能会在未来版本中更改)
Pressing the home button results in a significant delay between the two (even when the Reduced Motion setting is enabled):
按下主页按钮会导致两者之间出现明显延迟(即使启用了“减少运动”设置):
15:23:42.517 willResignActive
15:23:43.182 didEnterBackground
15:23:43.184 difference: 0.666346
Locking the device while the app is open creates a more trivial (<~0.2s) delay between the two events:
在应用程序打开时锁定设备会在两个事件之间产生更微不足道的(<~0.2 秒)延迟:
15:22:59.236 willResignActive
15:22:59.267 didEnterBackground
15:22:59.267 difference: 0.031404
回答by david
in iOS 8, you lock the screen or push the home button, all of those make app push in background, but you don't know which operator result in this. My solution same with Nits007ak,use notify_register_dispatch to get state.
在 iOS 8 中,你锁定屏幕或按下主页按钮,所有这些都会使应用程序在后台推送,但你不知道是哪个操作符导致了这个。我的解决方案与 Nits007ak 相同,使用 notify_register_dispatch 获取状态。
#import <notify.h>
int 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");
}
}
);
As long as the app is running, in foreground or background. not suspend, you can get this event.
只要应用程序在前台或后台运行。不暂停,你可以得到这个事件。
And you can use notify_token as parameter of notify_get_state to get current state anywhere, this is useful when you want know the state and the screen state don't change.
并且您可以使用 notify_token 作为 notify_get_state 的参数在任何地方获取当前状态,这在您想知道状态并且屏幕状态不改变时很有用。
回答by Nits007ak
Just import #import notify.h before using this code. enjoy!!
只需在使用此代码之前导入 #import notify.h 即可。请享用!!
-(void)registerAppforDetectLockState {
int 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");
}
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];
});
}
回答by Eyal
If passcode is set, you can use these event in AppDelegate
如果设置了密码,您可以在 AppDelegate 中使用这些事件
-(void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application
{
}
- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
{
}
回答by CFreymarc
From a lot of trial and error, discovered monitoring the blank screen, lock complete and lock state events gives a consistent lock screen indicator. You'll need to monitor a state transition.
从大量的试验和错误中,发现监控黑屏、锁定完成和锁定状态事件给出了一致的锁屏指示器。您需要监视状态转换。
// 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);
}
To have the screen lock indicators run in the background, you need to implement background processing calling the following upon app launching.
要在后台运行屏幕锁定指示器,您需要在应用程序启动时实现调用以下的后台处理。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.backgroundTaskIdentifier =
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
}];
[self registerforDeviceLockNotif];
}
回答by user738960
If your app is running and the user locks the device your app delegate will receive a call to 'application Will Resign Active:'. If your app was running when locked, it will receive a call to 'application Did Become Active:' when the device is unlocked. But you get the same calls to your app if the user gets a phone call and then chooses to ignore it. You can't tell the difference as far as I know.
如果您的应用程序正在运行并且用户锁定设备,您的应用程序委托将收到“应用程序将退出活动:”的调用。如果您的应用程序在锁定时正在运行,它将在设备解锁时收到“应用程序已激活:”的调用。但是,如果用户接到电话然后选择忽略它,您的应用程序也会收到相同的电话。据我所知,你无法分辨出区别。
And if your app wasn't running at any of these times there is no way to be notified since your app isn't running.
如果您的应用程序在任何这些时间都没有运行,那么您将无法收到通知,因为您的应用程序没有运行。
回答by Jossy Paul
The simplest way to get screen lock and unlock events are by adding event observers using NSNotificationCenter in your viewcontroller. I added the following observer in the viewdidload method. This is what i did:
获取屏幕锁定和解锁事件的最简单方法是在视图控制器中使用 NSNotificationCenter 添加事件观察者。我在 viewdidload 方法中添加了以下观察者。这就是我所做的:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationEnteredForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
Then I added the following selector to the viewcontroller. This selector will get called when the screen is unlocked.
然后我将以下选择器添加到视图控制器。当屏幕解锁时将调用此选择器。
- (void)applicationEnteredForeground:(NSNotification *)notification {
NSLog(@"Application Entered Foreground");
}
If you want to detect the event when screen gets locked, you can replace UIApplicationWillEnterForegroundNotificationwith UIApplicationDidEnterBackgroundNotification.
如果您想在屏幕被锁定检测的情况下,可以更换UIApplicationWillEnterForegroundNotification与UIApplicationDidEnterBackgroundNotification时。