有没有办法检查 iOS 设备是否已锁定/解锁?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14229955/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:47:14  来源:igfitidea点击:

Is there a way to check if the iOS device is locked/unlocked?

iosgpssleepcore-location

提问by Rohit Kashyap

I have used GPS location updates in my application. I want to detect if the iOS device is in sleep mode so that I can turn off the GPS location updates and optimize the battery use. I have already tried pausesLocationupdates in iOS 6, but it does not work as desired. I want to turn off the GPS location updates as soon as the device goes to sleep mode. I want to detect the lock/unlock event in the device.

我在我的应用程序中使用了 GPS 位置更新。我想检测 iOS 设备是否处于睡眠模式,以便我可以关闭 GPS 位置更新并优化电池使用。我已经在 iOS 6 中尝试过 pausesLocationupdates,但它不能按预期工作。我想在设备进入睡眠模式后立即关闭 GPS 位置更新。我想检测设备中的锁定/解锁事件。

Is there any way to achieve this functionality ?

有什么办法可以实现这个功能吗?

so far I got the darwin notifications as given below

到目前为止,我收到了如下所示的达尔文通知

-(void)registerForall
{
    //Screen lock notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.iokit.hid.displayStatus"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);


    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockstate"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockcomplete"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

}
//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    NSLog(@"IN Display status changed");
    NSLog(@"Darwin notification NAME = %@",name);


}

I am able to get the darwin notifications when device is locked/unlocked, but the real problem is how identify between if the notification has come from locking or the unlocking of the device. Console logs are:

当设备被锁定/解锁时,我能够收到达尔文通知,但真正的问题是如何识别通知是来自设备锁定还是解锁。控制台日志是:

 LockDetectDemo[2086] <Warning>: IN Display status changed
 LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockcomplete
 LockDetectDemo[2086] <Warning>: IN Display status changed
 LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.lockstate
 LockDetectDemo[2086] <Warning>: IN Display status changed
 LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.springboard.hasBlankedScreen
 LockDetectDemo[2086] <Warning>: IN Display status changed
 LockDetectDemo[2086] <Warning>: Darwin notification NAME = com.apple.iokit.hid.displayStatus

Any private API would also suffice. Thanks in advance.

任何私有 API 也足够了。提前致谢。

回答by Rohit Kashyap

I solved it like this:

我是这样解决的:

//call back
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    // the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
    CFStringRef nameCFString = (CFStringRef)name;
    NSString *lockState = (NSString*)nameCFString;
    NSLog(@"Darwin notification NAME = %@",name);

    if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
    {
        NSLog(@"DEVICE LOCKED");
        //Logic to disable the GPS
    }
    else
    {
        NSLog(@"LOCK STATUS CHANGED");
        //Logic to enable the GPS
    }
}

-(void)registerforDeviceLockNotif
{
    //Screen lock notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockcomplete"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                    NULL, // observer
                                    displayStatusChanged, // callback
                                    CFSTR("com.apple.springboard.lockstate"), // event name
                                    NULL, // object
                                    CFNotificationSuspensionBehaviorDeliverImmediately);
}

Note: the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification

注意:“ com.apple.springboard.lockcomplete”通知总是在“com.apple.springboard.lockstate”通知之后

Update

更新

The orderof the two notifications can no longer be relied upon, as of recent versions of iOS

从最近的 iOS 版本开始,不能再依赖这两个通知的顺序

回答by Jules

Apps are not allowed to listen to device lock notifications now!.

现在不允许应用程序收听设备锁定通知!。

I had receive this:

我收到了这个:

Dear developer,

We have discovered one or more issues with your recent submission for "xxxx". To process your submission, the following issues must be corrected:

Unsupported operation - Apps are not allowed to listen to device lock notifications.

Once these issues have been corrected, use Xcode or Application Loader to upload a new binary to iTunes Connect. Choose the new binary on the app's Details page in My Apps on iTunes Connect, and click Submit for Review.

Regards,

The App Store team
April 26 2017 at 10:56

亲爱的开发者,

我们发现您最近提交的“xxxx”有一个或多个问题。要处理您的提交,必须更正以下问题:

不支持的操作 - 不允许应用侦听设备锁定通知。

纠正这些问题后,使用 Xcode 或 Application Loader 将新的二进制文件上传到 iTunes Connect。在 iTunes Connect 上我的应用程序的应用程序详细信息页面上选择新的二进制文件,然后单击提交以供审核。

问候,

App Store 团队
2017 年 4 月 26 日 10:56

回答by Nits007ak

/* Register app for detecting lock state */

/* 注册检测锁状态的应用 */

 -(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];

  });

 }

回答by arturgrigor

Here's a better solution

这是一个更好的解决方案

#import <notify.h>

#define kNotificationNameDidChangeDisplayStatus                 @"com.apple.iokit.hid.displayStatus"

@interface YourClass ()
{    
    int _notifyTokenForDidChangeDisplayStatus;
}

@property (nonatomic, assign, getter = isDisplayOn) BOOL displayOn;
@property (nonatomic, assign, getter = isRegisteredForDarwinNotifications) BOOL registeredForDarwinNotifications;

@end

- (void)registerForSomeNotifications
{
    //
    // Display notifications
    //

    __weak YourClass *weakSelf = self;

    uint32_t result = notify_register_dispatch(kNotificationNameDidChangeDisplayStatus.UTF8String,
                                               &_notifyTokenForDidChangeDisplayStatus,
                                               dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0l),
                                               ^(int info) {
                                                   __strong YourClass *strongSelf = weakSelf;

                                                   if (strongSelf)
                                                   {
                                                       uint64_t state;
                                                       notify_get_state(_notifyTokenForDidChangeDisplayStatus, &state);

                                                       strongSelf.displayOn = (BOOL)state;
                                                   }
                                               });
    if (result != NOTIFY_STATUS_OK)
    {
        self.registeredForDarwinNotifications = NO;
        return;
    }

    self.registeredForDarwinNotifications = YES;
}

- (void)unregisterFromSomeNotifications
{
    //
    // Display notifications
    //

    uint32_t result = notify_cancel(_notifyTokenForDidChangeDisplayStatus);
    if (result == NOTIFY_STATUS_OK)
    {
        self.registeredForDarwinNotifications = NO;
    }
}

回答by rockdaswift

For your particular use case checking the screen brightness can be useful.

对于您的特定用例,检查屏幕亮度会很有用。

var isScreenLocked: Bool {
    return UIScreen.main.brightness == 0.0
}

回答by Vijay Patidar

I got a solution for check lock button was press or put app in background mode.

我得到了一个检查锁定按钮的解决方案是按下或将应用程序置于后台模式。

App cycle for lock press and put app in background mode-

锁定按下的应用程序循环并将应用程序置于后台模式-

WHEN LOCK PRESS

当锁定按下

applicationWillResignActive

applicationWillResignActive

applicationDidEnterBackground

applicationDidEnterBackground

WHEN UNLOCK PRESS

解锁时按下

applicationWillEnterForeground

applicationWillEnterForeground

applicationDidBecomeActive

applicationDidBecomeActive

///////////////////// WHEN PUT IN BACKGROUND

///////////////////// 当置于背景中时

applicationWillResignActive

applicationWillResignActive

applicationDidEnterBackground

applicationDidEnterBackground

WHEN FORGROUND

当前景

applicationWillEnterForeground

applicationWillEnterForeground

applicationDidBecomeActive

applicationDidBecomeActive

you can observe in both scenario same method are calling. In this case this is difficult task to get pressed lock button or put app in background. A small hack is there when we press lock button

您可以在两种情况下观察到相同的方法正在调用。在这种情况下,按下锁定按钮或将应用程序置于后台是一项艰巨的任务。当我们按下锁定按钮时有一个小技巧

applicationWillResignActive

applicationWillResignActive

applicationDidEnterBackground

applicationDidEnterBackground

these methods will called immediately but when we put app in background there is a time interval of millisecond between both methods. we can get the time difference and put condition on it. like....

这些方法将立即调用,但是当我们将应用程序置于后台时,两种方法之间的时间间隔为毫秒。我们可以得到时差并对其设置条件。喜欢....

var dateResignActive : Date?
var dateAppDidBack : Date?
func applicationWillResignActive(_ application: UIApplication) {

    dateResignActive = Date()

}
func applicationDidEnterBackground(_ application: UIApplication) {

    dateAppDidBack = Date()

}
func applicationDidBecomeActive(_ application: UIApplication) {

    let el1 = getCurrentMillis(date: dateResignActive!)
    let el2 = getCurrentMillis(date: dateAppDidBack!)
    let diff = el2 - el1

    if diff < 10 { //// device was locked // 10 is aprox
        // device was locked

    }
    else {
        let elapsed = Int(Date().timeIntervalSince(date!))
        if elapsed > 15 { // put app in background
        }
    }

}
func getCurrentMillis(date : Date)->Int64 {
    return Int64(date.timeIntervalSince1970 * 1000)
}

**This code is tested in iPhone X(Notch) and iPhone 6(Home button device). Because notch device and home button device have small difference in above two method calling.**  

回答by Karim Mourra

Jimmy provided a great solution but it's safer to pass in (__bridge const void *)(self)as an observer.

Jimmy 提供了一个很好的解决方案,但(__bridge const void *)(self)作为观察者传递更安全。

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                (__bridge const void *)(self),
                                displayStatusChanged,
                                CFSTR("com.apple.springboard.lockcomplete"),
                                NULL,
                                CFNotificationSuspensionBehaviorDeliverImmediately);

This allows you to properly remove the observer.

这允许您正确删除观察者。