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
Swift Unsafemutablepointer & Unsafemutablepointer<Unsafepointer<Sometype>>
Automatically Reload Tableviewcontroller on Rewind
Trouble Calling a Method in an Init
Core Data with Swiftui Mvvm Feedback
Swift: Get The Compile Time Name of Variable (Referencing to a Class)
Swift Preserve UIswitch State on UIlongpress
Prevent Retain Cycle in Swift Function Pointers
How to Make a Function Operate on a Sequence of Optional Values
Passing Values Between Viewcontrollers Based on List Selection in Swift
Firebase Swift 3 Get List of Child in a Array
Calling C++ from Swift - What Is The Equivalent of Std::Vector<T>
Swift 4, Coreplot, Send Chart via Mail App (With Messageui)
Xcode 9.3 Watchkit Crash on Wkinterfacebutton Tap
Error Validating Cms Signature
Can't Override UItableviewdatasource and UItableviewdelegate