How to use passcode lock scene in my app? - ios

Actually, I building an app which contains local authentication.
My code so far:
func authenticateUser() {
let authenticationContext = LAContext()
var error: NSError?
let reasonString = "Touch the Touch ID sensor to unlock."
// Check if the device can evaluate the policy.
if authenticationContext.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) {
authenticationContext.evaluatePolicy( .deviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success, evalPolicyError) in
if success {
print("success")
} else {
if let evaluateError = error as NSError? {
// enter password using system UI
}
}
})
} else {
print("toch id not available")
// enter password using system UI
}
}
My problem is I want to use the passcode lock scene when the app doesn't has touch ID or invalid finger print.
Like below Image:
How can I do it?

You should use .deviceOwnerAuthentication instead of .deviceOwnerAuthenticationWithBiometrics to evaluate policy. With this parameter the system uses biometric authentication if available else it presents passcode screen. And if the biometric authentication is available but fails, a fallback button redirect to the passcode screen. See documentation :
If Touch ID or Face ID is available, enrolled, and not disabled, the user is asked for that first. Otherwise, they are asked to enter the device passcode.
Tapping the fallback button switches the authentication method to ask the user for the device passcode.
So your code will be:
func authenticateUser() {
let authenticationContext = LAContext()
var error: NSError?
let reasonString = "Touch the Touch ID sensor to unlock."
// Check if the device can evaluate the policy.
if authenticationContext.canEvaluatePolicy(LAPolicy.deviceOwnerAuthentication, error: &error) {
authenticationContext.evaluatePolicy( .deviceOwnerAuthentication, localizedReason: reasonString, reply: { (success, evalPolicyError) in
if success {
print("success")
} else {
// Handle evaluation failure or cancel
}
})
} else {
print("passcode not set")
}
}

At this point, I am afraid that you cannot access this passcode lock screen into your app, it is related to the iOS itself. You might need to build your own custom view controller to look/behave as the passcode lock scene (with Touch ID). I would suggest to use a library for achieving this, personally, I've tried PasscodeLock and it works fine for me.

Related

Is it possible to ask for the user's PIN, Face ID or Touch ID before he sees a UIView?

I'd like to have the history section of an app locked for everyone besides the person who owns the phone. I don't like forcing the user to make an account or make a new PIN just for this app. Can I authorize using the PIN, Face ID or Touch ID he has already set up?
The Local Authentication framework will handle this.
Here is part of an Apple code sample:
/// Logs out or attempts to log in when the user taps the button.
#IBAction func tapButton(_ sender: UIButton) {
if state == .loggedin {
// Log out immediately.
state = .loggedout
} else {
// Get a fresh context for each login. If you use the same context on multiple attempts
// (by commenting out the next line), then a previously successful authentication
// causes the next policy evaluation to succeed without testing biometry again.
// That's usually not what you want.
context = LAContext()
context.localizedCancelTitle = "Enter Username/Password"
// First check if we have the needed hardware support.
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
let reason = "Log in to your account"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in
if success {
// Move to the main thread because a state update triggers UI changes.
DispatchQueue.main.async { [unowned self] in
self.state = .loggedin
}
} else {
print(error?.localizedDescription ?? "Failed to authenticate")
// Fall back to a asking for username and password.
// ...
}
}
} else {
print(error?.localizedDescription ?? "Can't evaluate policy")
// Fall back to a asking for username and password.
// ...
}
}
}

Would it be possible to use Apple’s Face ID technology for an app

Let’s say I want to create a door lock with face recognition. And in order to unlock the door the lock app on my phone has to recognize my face. Would it be possible to use Apple's Face ID for authentication?
You can use the LocalAuthentication framework to initiate FaceID (if the device supports the FaceID) and authenticate then use that result.
public func loginWithLocalAuthentication(isLoggedIn : #escaping ((Bool)->Void))
{
let reason = "Log in to your account"
let context = LAContext()
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason ) { success, error in
if success {
// Move to the main thread because a state update triggers UI changes.
isLoggedIn(true)
} else {
print(error?.localizedDescription ?? "Failed to authenticate")
isLoggedIn(false)
}
}
}

How to check Face ID is disabled for my app in settings page

How I can check is the Face ID is Enabled/ Disabled in settings page?
I checked in LAContext error type. It return
Code=-6 "User has denied the use of biometry for this app."
But the device do not support biometric authentication also getting same error code. (kLAErrorTouchIDNotAvailable -6)
Is any way to find user enabled/disabled Face ID in settings?
first add a method for your users to enable faceid/Touch ID using local authentication. adding this method will allow users to enable and disable biometric id in settings. you can use a whatever method you'd like, button, segment controller or view and using a prompt you'll ask the users permission to enable biometric id. This code may help:
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Enable FaceID!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] (success, authenticationError) in
DispatchQueue.main.async {
if success {
self.unlockSecretMessage()
} else {
// error
}
}
}
} else {
// no biometry
}

FaceID/TouchID success case keeps prompting for further authentication

I've implemented password/TouchID/FaceID on a view controller and when I hit the success case, I'd expect the prompt to stop firing but it just fires over and over again.
In my VC:
var context: LAContext!
func authenticateReturningUser() {
context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
let reason = "Verify that this is your device to continue."
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, error in
DispatchQueue.main.sync {
guard success else {
guard let error = error else {
// show error
return
}
switch error {
case LAError.userCancel:
// do stuff
return
default: return
}
}
print("success")
}
}
}
}
The prompt should fire once and not again if the user successfully authorizes
Edit:
authenticateReturningUser is called from the AppDelegate's applicationDidBecomeActive function:
self.coverVC?.completionHandler = { self.removeBackgroundVC() }
self.coverVC?.authenticateReturningUser()
As far as I remember, when showing the Touch ID prompt, your app becomes inactive. So when the prompt is dismissed, your app becomes active again, triggering the App Delegate's applicationDidBecomeActive again.
You might consider introducing a flag that stores whether the app became inactive because of Touch ID / Face ID etc. or because of another reason and use it in applicationDidBecomeActive to decide if authentication should be triggered or not.
Where are you calling authenticateReturningUser()? You may want to create a static boolean authenticated that if false, allows the call to authenticateReturningUser(), and if true, skips the call, and set authenticated = true after calling the function once.

Why evaluatePolicy fails only once if TouchID is turn off for iPhone Unlock

I want to use TouchID in my app and I've found some weird behaviour. So in general when TouchID alert is shown it and user try to authenticate with fingerprint canEvaluatePolicy will fail only after 3 attempts but if user go to Settings>Touch ID & Passcode and turn off "use touch id for: iPhone Unlock" canEvaluatePolicy will fail after first attempt with error message "Biometry is disabled for unlock.". Does anyone know is it a bug or it is by design.
Also looks like it happens only on iOS 11.
Here is code that i use for TouchID configuration
var error: NSError?
context.localizedFallbackTitle = "fallback title"
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
DispatchQueue.main.async {
if success {
// success case
}
else {
// error handling
}
}
}
}
else {
// error handling
}

Resources