Checking if device is locked (or sleeping) in iOS
This is easier in the main app, but there is a way to do this in the extension as well.
Published: May 25, 2021 Sponsored See booksSo recently for one fairly specific use case in client project, I had to check if screen is off. This in itself is basically impossible, but there is a workaround if we change the question to: "how to check if device is locked?".
It is not precise but pretty good proxy to know if the device is sleeping. Because sleeping device is also locked in most cases. I assume that since Touch ID and Face ID are really seamless, the vast majority of devices have lock enabled.
How to check if device is locked in the app
With these caveats out of the way, let's see how to check in the main app.
UIApplication.shared.isProtectedDataAvailable
And that is it. This will be true if the device is unlocked or in rare cases when file protection isn't active.
There are also AppDelegate
methods to tell you that protected data are now available, but not the other way around.
How to check in Extension if device is locked?
The above code is nice, but it isn't available in any of the extensions. Be it widgets, network extensions or anything else. However there is a way to detect if protected data is available and therefore if device is locked or not.
We can credit Keychain for that.
What you need to do, is basically save anything into KeyChain from your main app (or possibly even the extension) and set its accessibility to be available only if protected data are available.
In the extension you can then try to read the value and if that is successful, you can assume that device is unlocked. If you cannot read the data, then the device is locked.
This however requires us to configure Keychain sharing with the extension which is bit harder than the standard AppGroup stuff.
How to share Keychain with Extension
The first step is to add Xcode capability "Keychain Sharing" and create entry in Keychain Groups. This can be the same as your Bundle Identifier.
You need to add this both for you main app and for extension where you want to access the keychain.
Next we can move to code.
Whenever I am using Keychain, I use it via the excellent library KeychainWrapper. I would recommend you do the same.
It is also a good idea to create a extension for KeychainWrapper to have handy access to shared Keychain:
extension KeychainWrapper {
static var shared: KeychainWrapper {
return KeychainWrapper(serviceName: "anything", accessGroup: "[Team_ID].[Keychain_Group")
}
}
The access group is a bit different, because just the string we set in the capabilities isn't enough. This Keychain sharing can be used across your apps, so you need your Team ID here as well. You can find it on the Developer portal. It is under the Membership section.
Checking if device is locked in Extension
Now we can save something to the shared Keychain:
KeychainWrapper.shared.set(123, forKey: "isLockedCheckKey", withAccessibility: .whenUnlocked)
And in the extension we could check if device is locked like this:
KeychainWrapper.shared.integer(forKey: "isLockedCheckKey") == 123
If this returns true
then the device is unlocked.
Uses: Xcode 12 & Swift 5.3