如何检测 iPhone 上的屏幕锁定/解锁事件?

Posted

技术标签:

【中文标题】如何检测 iPhone 上的屏幕锁定/解锁事件?【英文标题】:How can I detect screen lock/unlock events on the iPhone? 【发布时间】:2011-10-25 11:20:55 【问题描述】:

当用户解锁它时,我想从我的 iPhone 应用程序中显示通知警报。 (就像 android 中用于屏幕解锁的广播接收器一样。)

【问题讨论】:

【参考方案1】:

检查一下,我想检测锁定/解锁事件,我通过 Darwin 通知解决了它。 当设备被"com.apple.springboard.lockcomplete"锁定时,您可以检测到该事件。

//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

    NSString *lockState = (NSString*)name;
    NSLog(@"Darwin notification NAME = %@",name);

    if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
    
        NSLog(@"DEVICE LOCKED");
    
    else
    
        NSLog(@"LOCK STATUS CHANGED");
       



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

【讨论】:

实际上这段代码在这种情况下可能会出现问题。 com.apple.springboard.lockstate”在锁定和解锁时都会出现。因此,如果您尝试仅在解锁时执行某些操作,则此代码将需要一些额外的逻辑。例如跟踪您当前的状态(设备是否被锁定或不是)。如果设备被锁定并且你得到“com.apple.springboard.lockstate”那么它是真正的解锁事件,否则它只是com.apple.springboard.lockcomplete的前奏 现在您可以完全跟踪状态: int result = notify_get_state(notifyToken, &state);见链接:***.com/questions/14352228/… 请看一下我写的 notify_get_state 方法的陷阱,Nate 在这里回答了 (***.com/questions/14820249/…)。 好一个,但它可以反向工作。解锁屏幕上的设备锁定呼叫,我想要这样,所以我得到 +1。 此解决方案似乎不再可用。 forums.developer.apple.com/message/224401#224401【参考方案2】:

要在 swift 5 中检测应用程序内部的锁定/解锁,只有这对我有用:

override func viewDidLoad() 
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplication.willEnterForegroundNotification, object: nil)
     NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)


@objc func applicationDidBecomeActive(notification: NSNotification) 
    print("ACTIVE")

@objc func applicationDidEnterBackground(notification: NSNotification) 
    print("BACKGROUND")

【讨论】:

【参考方案3】:

    在向 App Store 提交应用时,您不能使用com.apple.springboard.lockcompletecom.apple.springboard.lockstate,您的应用将被拒绝,因为它是私有 API。

    com.apple.springboard.lockcomplete 通知并不总是出现在com.apple.springboard.lockstate 通知之后,它可能会提前或推迟。您需要设置一个计时器来等待该事件。

以下是在 Swift 5 中检测屏幕锁定和解锁状态的方法:

struct NotificationName 
    // Listen to CFNotification, and convert to Notification
    public static let lockComplete = Notification.Name("NotificationName.lockComplete")
    public static let lockState = Notification.Name("NotificationName.lockState")

    // Handle lockComplete and lockState Notification to post locked or unlocked notification.
    public static let locked = Notification.Name("NotificationName.locked")
    public static let unlocked = Notification.Name("NotificationName.unlocked")


func addNotificationObservers() 
    let lockCompleteString = "com.apple.springboard.lockcomplete"
    let lockString = "com.apple.springboard.lockstate"

    // Listen to CFNotification, post Notification accordingly.
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                    nil,
                                     (_, _, _, _, _) in
                                        NotificationCenter.default.post(name: NotificationName.lockComplete, object: nil)
                                    ,
                                    lockCompleteString as CFString,
                                    nil,
                                    CFNotificationSuspensionBehavior.deliverImmediately)

    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                    nil,
                                     (_, _, _, _, _) in
                                        NotificationCenter.default.post(name: NotificationName.lockState, object: nil)
                                    ,
                                    lockString as CFString,
                                    nil,
                                    CFNotificationSuspensionBehavior.deliverImmediately)

    // Listen to Notification and handle.
    NotificationCenter.default.addObserver(self,
                                            selector: #selector(onLockComplete),
                                            name: NotificationName.lockComplete,
                                            object: nil)

    NotificationCenter.default.addObserver(self,
                                            selector: #selector(onLockState),
                                            name: NotificationName.lockState,
                                            object: nil)


// nil means don't know; ture or false means we did or did not received such notification.
var receiveLockStateNotification: Bool? = nil
// when we received lockState notification, use timer to wait 0.3s for the lockComplete notification.
var waitForLockCompleteNotificationTimer: Timer? = nil
var receiveLockCompleteNotification: Bool? = nil

// When we received lockComplete notification, invalidate timer and refresh lock status.
@objc
func onLockComplete() 
    if let timer = waitForLockCompleteNotificationTimer 
        timer.invalidate()
        waitForLockCompleteNotificationTimer = nil
    

    receiveLockCompleteNotification = true
    changeIsLockedIfNeeded()


// When we received lockState notification, refresh lock status.
@objc
func onLockState() 
    receiveLockStateNotification = true
    changeIsLockedIfNeeded()


func changeIsLockedIfNeeded() 
    guard let state = receiveLockStateNotification, state else 
        // If we don't receive lockState notification, return.
        return
    

    guard let complete = receiveLockCompleteNotification else 
        // If we don't receive lockComplete notification, wait 0.3s.
        // If nothing happens in 0.3s, then make sure we don't receive lockComplete, and refresh lock status.
        waitForLockCompleteNotificationTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block:  _ in
            self.receiveLockCompleteNotification = false
            self.changeIsLockedIfNeeded()
        )
        return
    

    // When we determined lockState and lockComplete notification is received or not.
    // We can update the device lock status by 'complete' value.
    NotificationCenter.default.post(
        name: complete ? NotificationName.locked : NotificationName.unlocked,
        object: nil
    )

    // Reset status.
    receiveLockStateNotification = nil
    receiveLockCompleteNotification = nil

【讨论】:

【参考方案4】:

您可能需要在AppDelegate 中实现以下方法:

告诉代理应用程序现在在后台。

- (void)applicationDidEnterBackground:(UIApplication *)application

告诉代理应用程序已激活。

- (void)applicationDidBecomeActive:(UIApplication *)application

告诉代理应用程序即将变为非活动状态。

- (void)applicationWillResignActive:(UIApplication *)application

【讨论】:

@ Nekto 实际上我想要如果我退出应用程序并锁定 iPhone,一段时间后我解锁了 iPhone,然后退出应用程序显示通知或提醒启动应用程序。例如,就像启动选项中的窗口、skype、gtalk 等。 我不明白你想要什么。也许是不可能的。 @Nekto 我只想简单地说:我怎样才能让我的应用程序在 iPhone 上启动? UIApplication.shared.isIdleTimerDisabled = true【参考方案5】:

实际上,如果我退出应用程序并锁定 iPhone,我想要 一段时间后,我解锁了 iPhone,然后退出 Applications 显示通知或提醒启动应用程序。

你不能在 iPhone 上这样做。

【讨论】:

我知道您正试图回复下面发布的 comment,但 answers 应该是对 question 在上面提出,因此,这个答案并不正确。如果您对评论有回应,则应将其作为原始评论的另一评论。 @Nate :你说得对,这似乎是我开始时的一篇文章,当时我还没有完全掌握 SO 的工作方式。 没问题。如果愿意,您可以删除旧答案,只需将内容(“您不能在 iPhone 上执行此操作”)移动到最佳位置的评论部分。当然,看起来 Nekto 也发表了相同的评论,所以也许只是支持他的评论就足够了 :) 我认为这个答案不正确。我的手机上有几个应用程序似乎在我解锁手机后会显示一条通知。 (Foursquare,我在看着你。)【参考方案6】:

从当前视图控制器中,您应该为 UIApplicationDidEnterBackgroundNotification 添加一个观察者,并在关闭视图控制器期间移除该观察者 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

【讨论】:

这不是 OP 所要求的。他们询问有关检测 iPhone 的锁定/解锁的问题,并且您的解决方案仅在应用程序进入后台时触发,应用程序可以进入后台的原因有多种,用户点击主页按钮,用户点击将他们带到另一个应用程序的通知,用户接听电话等。

以上是关于如何检测 iPhone 上的屏幕锁定/解锁事件?的主要内容,如果未能解决你的问题,请参考以下文章

Android检测Chromebook上的锁定解锁事件

从主屏幕检测密码锁定状态

如何在 iPhone 解锁上打开应用程序

sh 解锁屏幕。此命令发送解锁设备上锁定屏幕的事件。它可以与上面的电源按钮命令结合使用

如何播放可以通过 iPhone 上的屏幕锁定按钮关闭的音频

iPhone双滑解锁?