锁定解锁事件iphone

时间:2009-04-01 16:29:24

标签: iphone ios api locking

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

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

9 个答案:

答案 0 :(得分:21)

您可以使用Darwin notifications来收听事件。根据我对越狱的iOS 5.0.1 iPhone 4的测试,我认为其中一个事件可能就是你所需要的:

com.apple.springboard.lockstate
com.apple.springboard.lockcomplete

注意:根据海报的comments to a similar question I answered here,这也适用于非越狱手机。

要使用它,请注册这样的事件(这只注册上面的第一个事件,但你也可以添加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()。您将获得锁定与解锁的不同值as described here

答案 1 :(得分:14)

回答答案:

应用程序将在各种情况下调用active resign ...并且从我的所有测试中,即使你的应用程序在后台运行时保持清醒状态,也无法确定屏幕是否被锁定(CPU速度没有报告,BUS速度保持不变,mach_time denom / numer不会改变)......

但是,当设备锁定时,Apple似乎确实关闭了加速度计...... Enable iPhone accelerometer while screen is locked (在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;
}

我知道......这是一种黑客行为,但到目前为止,它对我来说就像是一种魅力。如果您发现任何阻止其工作的问题,请更新。

答案 2 :(得分:7)

有一种更漂亮的方式可以分辨任务切换和屏幕锁定 - 来源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:都是因为活动 - >非活动状态转换(如锁定屏幕时),但我们慷慨地让系统在超时内证明相反(在此case,单个runloop循环)通过延迟调用screenLockActivated。如果屏幕被锁定,系统将完成当前的runloop循环,而不会触及任何其他委托方法。但是,如果这是一个active->后台状态转换,它还会在循环结束前调用applicationDidEnterBackground:,这样我们就可以简单地从那里取消先前调度的请求,从而防止它被调用它不应该。

享受!

答案 3 :(得分:4)

在使用此代码之前,只需导入#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];

    });
}

答案 4 :(得分:4)

在iOS 8中,您锁定屏幕或按下主页按钮,所有这些都会在后台进行应用程序推送,但您不知道哪个运营商会导致此问题。我的解决方案与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的参数来获取当前状态,当你想知道状态和屏幕状态不会改变时,这很有用。

答案 5 :(得分:3)

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

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

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

答案 6 :(得分:1)

如果您的应用程序正在运行且用户锁定了该设备,则您的应用代表将收到“应用程序将重新启动活动:”的调用。如果您的应用在锁定时正在运行,则当设备解锁时,它会收到“应用已变为活动:”的呼叫。但是,如果用户接到电话,然后选择忽略它,您就会收到与您的应用相同的电话。据我所知,你无法区分它们。

如果您的应用未在任何时间运行,则由于您的应用未运行,因此无法收到通知。

答案 7 :(得分:1)

从大量的反复试验中,发现监控空白屏幕,锁定完成和锁定状态事件给出了一致的锁定屏幕指示。您需要监控状态转换。

// 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);
}

要让屏幕锁定指示器在后台运行,您需要实现后台处理,在启动应用程序时调用以下内容。

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

        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
    }];

    [self registerforDeviceLockNotif];
}

答案 8 :(得分:-3)

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

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

然后我将以下选择器添加到viewcontroller。屏幕解锁后将调用此选择器。

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

如果要在屏幕锁定时检测事件,可以使用 UIApplicationDidEnterBackgroundNotification 替换 UIApplicationWillEnterForegroundNotification