【发布时间】:2011-10-25 11:20:55
【问题描述】:
如何检测 iPhone 上的屏幕锁定/解锁事件?当用户解锁它时,我想从我的 iPhone 应用程序中显示通知警报。 (就像 Android 中用于屏幕解锁的广播接收器一样。)
【问题讨论】:
标签: ios objective-c events unlock
如何检测 iPhone 上的屏幕锁定/解锁事件?当用户解锁它时,我想从我的 iPhone 应用程序中显示通知警报。 (就像 Android 中用于屏幕解锁的广播接收器一样。)
【问题讨论】:
标签: ios objective-c events unlock
检查一下,我想检测锁定/解锁事件,我通过 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);
}
【讨论】:
要在 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")
}
【讨论】:
在向 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
}
【讨论】:
您可能需要在AppDelegate 中实现以下方法:
告诉代理应用程序现在在后台。
- (void)applicationDidEnterBackground:(UIApplication *)application
告诉代理应用程序已激活。
- (void)applicationDidBecomeActive:(UIApplication *)application
告诉代理应用程序即将变为非活动状态。
- (void)applicationWillResignActive:(UIApplication *)application
【讨论】:
实际上,如果我退出应用程序并锁定 iPhone,我想要 一段时间后,我解锁了 iPhone,然后退出 Applications 显示通知或提醒启动应用程序。
你不能在 iPhone 上这样做。
【讨论】:
从当前视图控制器中,您应该为 UIApplicationDidEnterBackgroundNotification 添加一个观察者,并在关闭视图控制器期间移除该观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
【讨论】: