9

How can i detect screen unlock events on iPhone? When the user unlocks it, I want to perform an action in my app. I searched on googled but only found code related to objective C , change it to swift but its not working.
Follow this blog: http://kidtechblogs.blogspot.com/2014/07/how-to-detect-screen-lockunlock-events.html.
Any help how can i detect it in swift. Below is the code change into swift..

func displayStatusChanged(center: CFNotificationCenter, observer: Void, name: CFString, object: Void, userInfo: CFDictionaryRef) {
        // the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
        let lockState = (name as String)
        print("Darwin notification NAME = \(name)")
        if (lockState == "com.apple.springboard.lockcomplete") {
            print("DEVICE LOCKED")
        }
        else {
            print("LOCK STATUS CHANGED")
        }
    }

func registerforDeviceLockNotification() {
        //Screen lock notifications
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
                nil,     // observer
                displayStatusChanged,     // callback
                CFSTR("com.apple.springboard.lockcomplete"),     // event name
                nil,     // object
                .deliverImmediately)
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
                nil,     // observer
                displayStatusChanged,     // callback
                CFSTR("com.apple.springboard.lockstate"),     // event name
                nil,     // object
                .deliverImmediately)
    }
fmashkoor
  • 113
  • 1
  • 2
  • 6

3 Answers3

13

There a few errors in your code sample:

  • Using CFString in swift is done by a simple cast: myString as CFString, no more CFSTR()...
  • The easiest way to get the notification callback is to have add an observer using Unmanaged.passUnretained(self).toOpaque(). That will give you the possibility to catch the callback in your class

In the end, the swift version is quite different from the objective-c one, here the full code in Swift 3:

func registerforDeviceLockNotification() {
    //Screen lock notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
        Unmanaged.passUnretained(self).toOpaque(),     // observer
        displayStatusChangedCallback,     // callback
        "com.apple.springboard.lockcomplete" as CFString,     // event name
        nil,     // object
        .deliverImmediately)
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
        Unmanaged.passUnretained(self).toOpaque(),     // observer
        displayStatusChangedCallback,     // callback
        "com.apple.springboard.lockstate" as CFString,    // event name
        nil,     // object
        .deliverImmediately)
}

private let displayStatusChangedCallback: CFNotificationCallback = { _, cfObserver, cfName, _, _ in
    guard let lockState = cfName?.rawValue as? String else {
        return
    }

    let catcher = Unmanaged<MyClassObserving>.fromOpaque(UnsafeRawPointer(OpaquePointer(cfObserver)!)).takeUnretainedValue()
    catcher.displayStatusChanged(lockState)
}

private func displayStatusChanged(_ lockState: String) {
    // the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
    print("Darwin notification NAME = \(lockState)")
    if (lockState == "com.apple.springboard.lockcomplete") {
        print("DEVICE LOCKED")
    } else {
        print("LOCK STATUS CHANGED")
    }
}

and just in case, don't forget to remove your observer:

CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(),
                                   Unmanaged.passUnretained(self).toOpaque(),
                                   nil,
                                   nil)
tbaranes
  • 3,560
  • 1
  • 23
  • 31
2

As far as we know you can't detect screen lock-unlock status by using native code. By using private api there will be chance of detecting screen lock-unlock status. Your app might be rejected if you are using private api of apple. We recommend not to use apple private api.

You can find the answer from below links if you want screen lock-unlock event in jail broken device

Getting state for system wide notifications in iOS and OS X

Lock Unlock events iphone

Detect screen on/off from iOS service

Community
  • 1
  • 1
Patrick R
  • 6,621
  • 1
  • 24
  • 27
2

I just updated the Code

just call the registerforDeviceLockNotification() function into app delegate didfinishLunch function (AppDelegate.swift)

if you are using session then call the registerforDeviceLockNotification() function into willConnectTo (SceneDelegate.swift)

example code (AppDelegate.swift)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        registerforDeviceLockNotification()
        return true
    }
    
    func registerforDeviceLockNotification() {
        //Screen lock notifications
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
            Unmanaged.passUnretained(self).toOpaque(),     // observer
            displayStatusChangedCallback,     // callback
            "com.apple.springboard.lockcomplete" as CFString,     // event name
            nil,     // object
            .deliverImmediately)

    }
    
    private let displayStatusChangedCallback: CFNotificationCallback = { _, cfObserver, cfName, _, _ in
        guard let lockState = cfName?.rawValue as String? else {return}

        if (lockState == "com.apple.springboard.lockcomplete") {
               print("DEVICE LOCKED")
           } else {
               print("LOCK STATUS CHANGED")
           }

       
    }

Example Code (SceneDelegate.swift)

func registerforDeviceLockNotification() {
    //Screen lock notifications
    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),     //center
        Unmanaged.passUnretained(self).toOpaque(),     // observer
        displayStatusChangedCallback,     // callback
        "com.apple.springboard.lockcomplete" as CFString,     // event name
        nil,     // object
        .deliverImmediately)

}

private let displayStatusChangedCallback: CFNotificationCallback = { _, cfObserver, cfName, _, _ in
    guard let lockState = cfName?.rawValue as String? else {return}

    if (lockState == "com.apple.springboard.lockcomplete") {
           print("DEVICE LOCKED")
       } else {
           print("LOCK STATUS CHANGED")
       }

   
}




 
Muhammad Ahmad
  • 388
  • 4
  • 9
  • I used your code, this is working... but my app is rejected, apple never accept to access "com.apple.springboard.lockcomplete". Any idea? – DarkHorse Dec 16 '20 at 19:38