Biometric Authentication Evaluation with Swiftui

Biometric Authentication evaluation with swiftUI

Explanation:

'unowned' may only be applied to class and class-bound protocol types, not 'AuthenticateView'

First of all, you have AuthenticateView which is a struct. You can't do it class because whole Apple's SwiftUI idea is about structures. And because Struct is value type and not a Reference type, so no pointer as such. So you may not include code parts containing unowned self and weak self modifiers into struct AuthenticateView: View {}

Value of type 'AuthenticateView' has no member 'present'

present is a UIViewController's method. Here in SwiftUI you have no access to it. The alerts are being presented using the next style:

struct ContentView: View {
@State private var show = false
var body: some View {
Button(action: { self.show = true }) { Text("Click") }
.alert(isPresented: $showingAlert) {
Alert(title: Text("Title"),
message: Text("Message"),
dismissButton: .default(Text("Close")))
}
}
}

Solution:
For your case, I would create a class Handler subclass of ObservableObject for your logic and use the power of @ObservedObject, @Published and @State.

Rough example for understanding the concept:

import SwiftUI

struct ContentView: View {
@ObservedObject var handler = Handler()
var body: some View {
Button(action: { self.handler.toggleShowAlert() }) { Text("Click") }
.alert(isPresented: $handler.shouldShowAlert) {
Alert(title: Text(handler.someTitle),
message: Text(handler.someMessage),
dismissButton: .default(Text("Close")))
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

class Handler: ObservableObject {
@Published var shouldShowAlert: Bool = false
@Published var someTitle = ""
@Published var someMessage = ""

func toggleShowAlert() {
shouldShowAlert.toggle()
someTitle = "ErrorTitle"
someMessage = "ErrorMessage"
}
}

Face ID evaluation process not working properly

Working code of Touch ID & Face ID LocalAuthentication

(swift 4.0 & 5.0+ Code)

Note : Privacy - Face ID Usage Description key add in Info.plist

Use

self.Authenticate { (success) in
print(success)
}

Local Authentication Function

import LocalAuthentication

func Authenticate(completion: @escaping ((Bool) -> ())){

//Create a context
let authenticationContext = LAContext()
var error:NSError?

//Check if device have Biometric sensor
let isValidSensor : Bool = authenticationContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)

if isValidSensor {
//Device have BiometricSensor
//It Supports TouchID

authenticationContext.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Touch / Face ID authentication",
reply: { [unowned self] (success, error) -> Void in

if(success) {
// Touch / Face ID recognized success here
completion(true)
} else {
//If not recognized then
if let error = error {
let strMessage = self.errorMessage(errorCode: error._code)
if strMessage != ""{
self.showAlertWithTitle(title: "Error", message: strMessage)
}
}
completion(false)
}
})
} else {

let strMessage = self.errorMessage(errorCode: (error?._code)!)
if strMessage != ""{
self.showAlertWithTitle(title: "Error", message: strMessage)
}
}

}

Handle Error Codes with Messages

//MARK: TouchID error
func errorMessage(errorCode:Int) -> String{

var strMessage = ""

switch errorCode {

case LAError.Code.authenticationFailed.rawValue:
strMessage = "Authentication Failed"

case LAError.Code.userCancel.rawValue:
strMessage = "User Cancel"

case LAError.Code.systemCancel.rawValue:
strMessage = "System Cancel"

case LAError.Code.passcodeNotSet.rawValue:
strMessage = "Please goto the Settings & Turn On Passcode"

case LAError.Code.biometryNotAvailable.rawValue:
strMessage = "TouchI or FaceID DNot Available"

case LAError.Code.biometryNotEnrolled.rawValue:
strMessage = "TouchID or FaceID Not Enrolled"

case LAError.Code.biometryLockout.rawValue:
strMessage = "TouchID or FaceID Lockout Please goto the Settings & Turn On Passcode"

case LAError.Code.appCancel.rawValue:
strMessage = "App Cancel"

case LAError.Code.invalidContext.rawValue:
strMessage = "Invalid Context"

default:
strMessage = ""

}
return strMessage
}

Show alert message

//MARK: Show Alert
func showAlertWithTitle( title:String, message:String ) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)

let actionOk = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(actionOk)
self.present(alert, animated: true, completion: nil)
}

iOS cancel TouchID authentication dialog programmatically

Not every API Apple publishes makes it into the documentation on developer.apple.com (or in Xcode's docs viewer). The API diffs list public APIs, so anything you see there is in the header files (see LocalAuthentication/LAContext.h) and the Swift interfaces generated from those headers. And anything that's in the headers is a public API, so you're free to call it.

Sometimes (but not always) the undocumented APIs have decent header comments explaining how to use them... thankfully LAContext.invalidate() is one of these:

/// Invalidates the context.
///
/// @discussion The context is invalidated automatically when it is (auto)released. This method
/// allows invalidating it manually while it is still in scope.
///
/// Invalidation terminates any existing policy evaluation and the respective call will
/// fail with LAErrorAppCancel. After the context has been invalidated, it can not be
/// used for policy evaluation and an attempt to do so will fail with LAErrorInvalidContext.
///
/// Invalidating a context that has been already invalidated has no effect.
@available(iOS 9.0, *)
public func invalidate()

Indeed, it looks like calling invalidate() while the Touch ID alert is visible should dismiss it. (I haven't tried myself.)


iOS 11 update: Note that on devices with Face ID instead of Touch ID, the alert/HUD-like UI that appears when you call LAContext.evaluatePolicy doesn’t require or allow interaction, and dismisses itself upon successful authentication. Theoretically, the invalidate call still dismisses it (or the followup, actually-interactive alert that appears if Face ID doesn’t identify the user).

But it might not be wise to assume that on all possible devices and authentication methods you’ll always have enough time to cancel LAContext authentication after asking for it.



Related Topics



Leave a reply



Submit