如何检测 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.lockcomplete
或com.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 上的屏幕锁定/解锁事件?的主要内容,如果未能解决你的问题,请参考以下文章