How can I detect screen lock/unlock events on the iPhone? When the user unlocks it, I want to show a notification alert from my iPhone app. (For Just like Broadcast Receiver for screen unlock in Android.)
Check this out, I wanted to detect the lock/unlock events, I solved it by Darwin notifications.
You can detect the event when the device is locked by "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);
}
lockcomplete
may actually come before lockstate
. I'm observing that right now on iOS 9.3. Best not to rely on order here. –
Subtropics To detect lock/unlock inside app in swift 5 only this worked for me:
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")
}
You can't use
com.apple.springboard.lockcomplete
orcom.apple.springboard.lockstate
when submitting your app to App Store, your app will be rejected because it's private API.The
com.apple.springboard.lockcomplete
notification NOT always comes after thecom.apple.springboard.lockstate
notification, it may happen early or later. You need to set a timer to wait for that event.
So here is how you can detect screen lock and unlock status, in 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
}
May be you need to implement following methods in AppDelegate
:
Tells the delegate that the application is now in the background.
- (void)applicationDidEnterBackground:(UIApplication *)application
Tells the delegate that the application has become active.
- (void)applicationDidBecomeActive:(UIApplication *)application
Tells the delegate that the application is about to become inactive.
- (void)applicationWillResignActive:(UIApplication *)application
Actually I want the if I exit the application and lock the iPhone , and after some time I have unlock the iPhone , then exit Applications show the notifications or Alert the Start-up the Applications.
You can't do that on the iPhone.
The original question is quite old, so for anybody who stumbles on this:
On modern devices with Face ID and Touch ID, you can use the AppDelegate methods applicationProtectedDataDidBecomeAvailable(_:)
(docs) and applicationProtectedDataWillBecomeUnavailable(_:)
(docs).
These are called when the device storage is decrypted or encrypted. They are intended to let the app know when data from the storage can be read or becomes unavailable. However, because device encryption is active on almost any iPhone today, you can also use these to detect screen lock and unlock events.
However, this of course only works as long as your app is actively running.
From the current view controller your should add an observer for UIApplicationDidEnterBackgroundNotification and remove the observer during dismissing the view controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
© 2022 - 2024 — McMap. All rights reserved.