How to Lock your iOS app with Device Lock?

Lee young-jun
3 min readDec 13, 2023

--

Long ago, I developed a presentation app for iPad that required a secure feature. To fulfill this requirement, I implemented a custom alert controller to prompt users for a password.

How can a user open the presentation if they forget the password?

There is no server for the app, it uses only cloud drive like Google, Dropbox, OneDrive.

Since there is no server for the app and it relies on cloud drives like Google, Dropbox, and OneDrive, I decided to utilize the device lock.

If the user can unlock the device, it signifies ownership of the device, and I don’t have to worry about potential security breaches.

How can I programmatically lock the user’s device?

LAContext

To use the lock API, I created a Local Authentication Context.

import LocalAuthentication

let context = LAContext()

Evaluate

It is very easy to lock the device; just call evaluatePolicy.

context.evaluatePolicy(.deviceOwnerAuthentication, 
localizedReason: "Please unlock") { result, error in
debugPrint("Unlocked? \(result). Error[\(error)]")
}

Policy

deviceOwnerAuthentication is specifically designed for password authentication. However, there are 4 special policies that can be used as an alternative to the password.

Since I don’t have a watch, I attempted to use ...WithBiometrics.

2023–12–12 18:06:15.269447+0900 iOSDeviceLockExample[17914:57394382] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSFaceIDUsageDescription key with a string value explaining to the user how the app uses this data.

But the app crashed because the description is required when using Biometrics.

When I ran it again, the app prompted me for permission.

And displayed the face detection view.

Few seconds later, the system presented the failed alert.

Since I agreed to use Face ID, I couldn’t see the password screen anymore even with .deviceOwnerAuthentication.

Cancel

Cancel When I pressed the cancel button on the alert, the callback was invoked with an error..

Unlocked? false. Error[Optional(Error Domain=com.apple.LocalAuthentication Code=-2 \”Canceled by user.\” UserInfo={NSDebugDescription=Canceled by user., NSLocalizedDescription=Authentication canceled.})]”

2023–12–12 18:14:01.054536+0900 iOSDeviceLockExample[17989:57395550] [EventDispatcher] Found no UIEvent for backing event of type: 11; contextId: 0x209A520A

Retry

In specific cases, I need to lock again after the lock is canceled or unlocking fails. So, I called evaluatePolicy again when the result is false.

func lock() {
let context: LAContext = .init()

context
.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Please unlock") { [weak self]result, error in
guard result else{
self?.lock()
return
}

//
}
}

lazy var onLock: UIAction = .init { [weak self]_ in
self?.lock()
}

The full source is in this example repository.

If you found this post helpful, please give it a round of applause 👏. Explore more iOS-related content in my other posts.

For additional insights and updates, check out my LinkedIn profile. Thank you for your support!

References

--

--

No responses yet