Nat*_*ate 22
您可以使用Darwin通知来侦听事件.从我在越狱的iOS 5.0.1 iPhone 4上的测试中,我认为其中一个事件可能就是你所需要的:
com.apple.springboard.lockstate
com.apple.springboard.lockcomplete
Run Code Online (Sandbox Code Playgroud)
注意:根据海报对我在这里回答的类似问题的评论,这也适用于非越狱手机.
要使用它,请注册这样的事件(这只注册上面的第一个事件,但你也可以添加一个观察者lockcomplete):
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
(void*)self, // observer (can be NULL)
lockStateChanged, // callback
CFSTR("com.apple.springboard.lockstate"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
lockstate设备锁定和解锁时会发生此事件,但lockcomplete仅在设备锁定时触发事件.确定事件是用于锁定还是解锁事件的另一种方法是使用notify_get_state().你会得到锁定与解锁不同的值,如本文所述.
Bad*_*ate 13
回答:
应用程序将在各种情况下调用活动调用...并且从我的所有测试中,即使您的应用程序在后台运行时保持清醒状态,也无法确定屏幕是否已锁定(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;
}
Run Code Online (Sandbox Code Playgroud)
我知道......这是一种黑客行为,但到目前为止,它对我来说就像是一种魅力.如果您发现任何阻止其工作的问题,请更新.
有一种更漂亮的方法可以分辨任务切换和屏幕锁定发起的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");
}
Run Code Online (Sandbox Code Playgroud)
说明:
默认情况下,我们假设每次调用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
Run Code Online (Sandbox Code Playgroud)
在应用打开时锁定设备会在两个事件之间产生更微不足道的(<〜0.2s)延迟:
15:22:59.236 willResignActive
15:22:59.267 didEnterBackground
15:22:59.267 difference: 0.031404
Run Code Online (Sandbox Code Playgroud)
在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");
}
}
);
Run Code Online (Sandbox Code Playgroud)
只要应用程序在前台或后台运行。不暂停,您可以获取此事件。
而且您可以将notify_token用作notify_get_state的参数以在任何地方获取当前状态,这在您希望了解状态和屏幕状态不变的情况下非常有用。
小智 1
如果您的应用程序正在运行并且用户锁定设备,您的应用程序委托将收到“应用程序将退出活动:”的调用。如果您的应用程序在锁定时运行,则当设备解锁时,它将收到“应用程序已变为活动状态:”的调用。但是,如果用户接到电话然后选择忽略它,您的应用程序也会收到相同的电话。据我所知,你无法分辨出差异。
如果您的应用程序在任何这些时间都没有运行,则无法收到通知,因为您的应用程序没有运行。
| 归档时间: |
|
| 查看次数: |
36266 次 |
| 最近记录: |