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

如何检测 iPhone 上的屏幕锁定/解锁事件?当用户解锁它时,我想从我的 iPhone 应用程序中显示通知警报。 (就像 Android 中用于屏幕解锁的广播接收器一样。)

【问题讨论】:

    标签: ios objective-c events unlock


    【解决方案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);见链接:stackoverflow.com/questions/14352228/…
    • 请看一下我写的 notify_get_state 方法的陷阱,Nate 在这里回答了 (stackoverflow.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】:
      1. 在向 App Store 提交应用时,您不能使用com.apple.springboard.lockcompletecom.apple.springboard.lockstate,您的应用将被拒绝,因为它是私有 API。

      2. 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 的锁定/解锁的问题,并且您的解决方案仅在应用程序进入后台时触发,应用程序可以进入后台的原因有多种,用户点击主页按钮,用户点击将他们带到另一个应用程序的通知,用户接听电话等。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-07
        • 2021-06-29
        • 2010-10-16
        • 1970-01-01
        • 2016-05-28
        • 2012-01-02
        相关资源
        最近更新 更多