如何在iPhone上检测屏幕锁定/解锁事件?当用户解锁时,我想从我的iPhone应用程序中显示通知警报。(就像Android中屏幕解锁的广播接收器一样。)
如何在iPhone上检测屏幕锁定/解锁事件?当用户解锁时,我想从我的iPhone应用程序中显示通知警报。(就像Android中屏幕解锁的广播接收器一样。)
看这个,我想检测锁定/解锁事件,我通过达尔文通知解决了这个问题。
可以通过"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
原始问题相当古老,所以对于任何偶然发现的人:
在具有Face ID和Touch ID的现代设备上,您可以使用AppDelegate方法applicationProtectedDataDidBecomeAvailable(_:)
(docs)和applicationProtectedDataWillBecomeUnavailable(_:)
(docs)。
这些方法在设备存储解密或加密时被调用。它们旨在让应用程序知道何时可以读取存储中的数据或何时变得不可用。然而,由于几乎所有iPhone都启用了设备加密,您也可以使用这些方法来检测屏幕锁定和解锁事件。
然而,这当然只在您的应用程序处于活动状态时有效。
从当前的视图控制器中,您应该为UIApplicationDidEnterBackgroundNotification添加一个观察者,并在取消视图控制器时移除观察者。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
lockcomplete
可能会在lockstate
之前出现。我现在在 iOS 9.3 上观察到了这一点。最好不要依赖顺序。 - Nate