我该如何在iPhone上检测屏幕锁定/解锁事件?

21

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

7个回答

24

看这个,我想检测锁定/解锁事件,我通过达尔文通知解决了这个问题。 可以通过"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);  
}   

1
实际上,在这种情况下,这段代码可能会出现问题。 "com.apple.springboard.lockstate" 无论是在锁定还是解锁时都会出现。因此,如果您尝试仅在解锁时执行某些操作,则此代码将需要一些额外的逻辑。例如,跟踪您当前的状态(设备是否已锁定)。如果设备已锁定并且您收到了“ com.apple.springboard.lockstate”,则这是真正的解锁事件,否则它只是 com.apple.springboard.lockcomplete 的前奏。 - Victor Ronin
现在您可以完全跟踪状态:int result = notify_get_state(notifyToken, &state);请参阅链接:https://dev59.com/6mYq5IYBdhLWcg3wmRua - Rohit Kashyap
不错,但它的工作方式相反。设备被锁定时呼叫解锁屏幕,我希望这样可以让我得到+1。 - Prince Kumar Sharma
1
实际上,代码中的注释是不正确的。lockcomplete 可能会在 lockstate 之前出现。我现在在 iOS 9.3 上观察到了这一点。最好不要依赖顺序。 - Nate
3
这个解决方案似乎已不再适用。https://forums.developer.apple.com/message/224401#224401 - Dae KIM
显示剩余3条评论

4

在 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")
}

2
  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
}

1

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

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

- (void)applicationDidEnterBackground:(UIApplication *)application

告诉委托对象应用程序已经变为活动状态。
- (void)applicationDidBecomeActive:(UIApplication *)application

告诉代理应用程序即将变为非活动状态。
- (void)applicationWillResignActive:(UIApplication *)application

@ Nekto,实际上我想要的是,如果我退出应用程序并锁定iPhone,一段时间后我解锁iPhone,然后退出应用程序会显示通知或警报启动应用程序。例如,就像Windows中的启动选项,skype,gtalk等。 - Vikas S Singh
我不明白你想要什么。也许这是不可能的。 - Nekto
1
@Nekto 我想简单地说一下:我该如何让我的应用程序在 iPhone 启动时启动? - Vikas S Singh
UIApplication.shared.isIdleTimerDisabled = true。 - Gauri Shankar

1
实际上,我希望如果我退出应用程序并锁定 iPhone, 然后过一段时间我解锁 iPhone,退出应用程序时显示通知或启动应用程序的警报。 在 iPhone 上你做不到这一点。

6
我知道你想回复下面的一条评论,但是“答案”应该回答上面提出的“问题”,因此这个回答并不正确。如果你想回复一条评论,应该在原来的地方回复另一条评论。请注意修改并保留原意。 - Nate
@Nate:你说得对,这似乎是我刚开始时还没有完全掌握SO工作方式的帖子。 - Oliver
没问题。如果您愿意,可以删除旧答案,并将内容(“您无法在iPhone上执行此操作”)移动到最合适的评论部分。当然,看起来Nekto也发表了同样的评论,所以可能只需点赞他的评论就足够了 :) - Nate
我不认为这个答案是正确的。我的手机上有几个应用程序似乎在我解锁手机后立即显示通知。(Foursquare,我在看着你。) - Carl G

0

原始问题相当古老,所以对于任何偶然发现的人:

在具有Face ID和Touch ID的现代设备上,您可以使用AppDelegate方法applicationProtectedDataDidBecomeAvailable(_:)docs)和applicationProtectedDataWillBecomeUnavailable(_:)docs)。

这些方法在设备存储解密或加密时被调用。它们旨在让应用程序知道何时可以读取存储中的数据或何时变得不可用。然而,由于几乎所有iPhone都启用了设备加密,您也可以使用这些方法来检测屏幕锁定和解锁事件。

然而,这当然只在您的应用程序处于活动状态时有效。


-2

从当前的视图控制器中,您应该为UIApplicationDidEnterBackgroundNotification添加一个观察者,并在取消视图控制器时移除观察者。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

2
这不是OP所问的。他们询问如何检测iPhone的锁定/解锁情况,而你的解决方案仅在应用程序进入后台时触发,应用程序进入后台的原因有多种,例如用户按下主页按钮、用户点击通知以跳转到另一个应用程序、用户接听电话等等。 - esttorhe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接