iOS Customize Local Authentication with Touch ID - ios

I am using the following code to implement the touchID/passcode authentication in my app
let context : LAContext = LAContext()
var error: NSError?
// Check if the device can evaluate the policy.
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthentication, error: &error) {
context.evaluatePolicy(LAPolicy.deviceOwnerAuthentication,
localizedReason: messageString,
reply: { (success: Bool, evalPolicyError: Error?) -> Void in
if success {
// ...
}
else {
switch evalPolicyError!._code {
case LAError.systemCancel.rawValue:
print("Authentication was cancelled by the system")
case LAError.userCancel.rawValue:
print("Authentication was cancelled by the user")
case LAError.userFallback.rawValue:
print("User selected to enter custom password")
OperationQueue.main.addOperation({ () -> Void in
// ...
})
default:
print("Authentication failed")
OperationQueue.main.addOperation({ () -> Void in
// ...
})
}
}
})
}
Is is possible to customize it? For example:
Choose the number of TouchID attempts before switching to passcode?
In the first AlertView let user choose to switch to passcode with a button (in the current implementation you can access the passcode only if you fail the TouchID auth)

Related

What are the delegate methods for ReplayKit's initial alert choices?

When the the user first decides to use ReplayKit there is an alert that appears. It gives 3 choices:
-Record Screen and Microphone
-Record Screen Only
-Don’t Allow
What are the delegate methods so that I can find out which option a user choose?
There aren't any delegate methods to determine which option a user chooses. You have to use the completionHandler and .isMicrophoneEnabled to determine the chosen option.
Once an option is chosen the completionHandler is called:
If the user chooses Don't Allow then the error code will run
If the user chooses Record Screen & Microphone then .isMicrophoneEnabled will get set to true
If the user chooses Record Screen Only then .isMicrophoneEnabled will get set to false
Inside the completionHandler you can check to see their choice then do whatever you need to do from that point on. Read the 2 comments in the completionHandler part of the code below.
let recorder = RPScreenRecorder.shared()
recorder.startCapture(handler: { [weak self](buffer, bufferType, err) in
// ...
}, completionHandler: { (error) in
// 1. If the user chooses "Dont'Allow", the error message will print "The user declined application recording". Outside of that if an actual error occurs something else will print
if let error = error {
print(error.localizedDescription)
print("The user choose Don't Allow")
return
}
// 2. Check the other 2 options
if self.recorder.isMicrophoneEnabled {
print("The user choose Record Screen & Microphone")
} else {
print("The user choose Record Screen Only")
}
})
The safe way to do this so that you know how to respond to each error code is to use a switch statement on the error codes:
}, completionHandler: { (error) in
if let error = error as NSError? {
let rpRecordingErrorCode = RPRecordingErrorCode(rawValue: error.code)
self.errorCodeResponse(rpRecordingErrorCode)
}
})
func errorCodeResponse(_ error: RPRecordingErrorCode?) {
guard let error = error else { return }
switch error {
case .unknown:
print("Error cause unknown")
case .userDeclined:
print("User declined recording request.")
case .disabled:
print("Recording disabled via parental controls.")
case .failedToStart:
print("Recording failed to start.")
case .failed:
print("Recording error occurred.")
case .insufficientStorage:
print("Not enough storage available on the device.")
case .interrupted:
print("Recording interrupted by another app.")
case .contentResize:
print("Recording interrupted by multitasking and content resizing.")
case .broadcastInvalidSession:
print("Attempted to start a broadcast without a prior session.")
case .systemDormancy:
print("Recording forced to end by the user pressing the power button.")
case .entitlements:
print("Recording failed due to missing entitlements.")
case .activePhoneCall:
print("Recording unable to record due to active phone call.")
default: break
}
}
If you only want to detect when Don't Allow is tapped, here is a simple solution:
recorder.startCapture(handler: { [self] (sampleBuffer, sampleType, passedError) in
if let passedError = passedError {
print(passedError.localizedDescription)
return
}
}) { err in
if let error = err {
if error._code == RPRecordingErrorCode.userDeclined.rawValue {
print("User didn't allow recording")
}
}
}

touchID implementation error cancelled by user

How to resolve the TouchId error: Domain=com.apple.LocalAuthentication Code=-2 "Canceled by user."
I tried to add local context again:
let myContext = LAContext()
let myLocalizedReasonString = "Please use your last login for Inspyrus Supplier Central."
var authError: NSError?
if #available(iOS 8.0, macOS 10.12.1, *) {
if myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: myLocalizedReasonString) { success, evaluateError in
DispatchQueue.main.async {
if success {
self.btnLoginClicked(UIButton())
} else {
print(evaluateError?.localizedDescription ?? "Failed to authenticate")
// Fall back to a asking for username and password.
// ...
}
}
}
}
}
You can check if the evaluateError returned from the evaluatePolicy call is a LAError.userCancel.
Something like this:
if success {
//...
}
else if let authError = evaluateError as? LAError {
switch authError.code {
case .userCancel:
// Authentication was canceled by user (e.g. tapped Cancel button).
break
default:
// Other error
break
}
// Or
switch authError {
case LAError.userCancel:
// Authentication was canceled by user (e.g. tapped Cancel button).
break
default:
// Other error
break
}
}

Detect when user tapped Don't Allow when making changes to photo library

When you want to make a change to a PHAsset, you wrap it up in a performChanges block. You get a success Bool and an error NSError in the completion block. Now I would like to show an alert to the user in the case the request failed. This does the trick:
PHPhotoLibrary.sharedPhotoLibrary().performChanges({ () -> Void in
let request = PHAssetChangeRequest(forAsset: asset)
request.creationDate = date
}, completionHandler: { (success: Bool, error: NSError?) -> Void in
dispatch_async(dispatch_get_main_queue()) {
if let error = error {
//present alert
}
}
})
The problem is when the user taps Don't Allow it also presents the alert. I don't want to do that, the user intentionally canceled it so there's no need to inform them it failed. But how can I detect that's what has occurred? The error userInfo is nil, it doesn't seem it provides any useful info to detect that case. Am I missing something?
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
NSLog(#"%ld",(long)status);
switch (status) {
case PHAuthorizationStatusAuthorized:
// code for display photos
NSLog(#"ffefwfwfwef");
case PHAuthorizationStatusRestricted:
break;
case PHAuthorizationStatusDenied:
//code for Dont Allow code
break;
default:
break;
}
}];
This is now possible by checking if the error is a PHPhotosError and if so checking its code to see if it's .userCancelled.
PHPhotoLibrary.shared().performChanges({
let request = PHAssetChangeRequest(forAsset: asset)
request.creationDate = date
}) { success, error in
guard let error = error else { return }
guard (error as? PHPhotosError)?.code != .userCancelled else { return }
DispatchQueue.main.async {
//present alert
}
}

Can't prevent user from cancelling Touch ID

When the Touch ID alert is displayed, there is also a "Cancel" button. I would prefer to NOT allow the user to cancel because they are prohibited from continuing any further. 1. Is there a way to remove the "Cancel" button. 2. If the "Cancel" button is required, how can I force the user to re-authenticate with a fingerprint? If authenticate() is called a second time, the Touch ID API just lets them in. There is no alternative passcode and I'd hate to have to code up yet another view controller for it.
func authenticate() {
let myContext:LAContext = LAContext()
let authError:NSErrorPointer = nil
if (myContext.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: authError)) {
myContext.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Press fingerprint", reply: { (success:Bool, error:NSError?) -> Void in
if success == true {
log.debug("SUCCESSFUL AUTHENTICATION")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.performSegueWithIdentifier("showUI", sender: self)
})
}
else {
log.debug("FAILED AUTHENTICATION")
self.authenticate()
}
})
}
}
You need to dispatch your failure call to self.authenticate on the main queue;
func authenticate() {
let myContext:LAContext = LAContext()
let authError:NSErrorPointer = nil
if (myContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: authError)) {
myContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Press fingerprint", reply: { (success:Bool, error:NSError?) -> Void in
if success {
log.debug("SUCCESSFUL AUTHENTICATION")
DispatchQueue.main.async {
self.performSegueWithIdentifier("showUI", sender: self)
}
}
else {
log.debug("FAILED AUTHENTICATION")
DispatchQueue.main.async {
self.authenticate()
}
}
})
}
}

How to get fingerprint dat in ios 8?

For this i use La Authentication framework but with the help of that i don't got fingerprint data and it just returns me boolean value i.e true and false , so it cant help i want fingerprint data in variable so further i will process it.
Help me.
following is the sample code,
func authenticateUser() {
...
// Check if the device can evaluate the policy.
if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
[context .evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success: Bool, evalPolicyError: NSError?) -> Void in
if success {
}
else {
// If authentication failed then show a message to the console with a short description.
// In case that the error is a user fallback, then show the password alert view.
println(evalPolicyError?.localizedDescription)
switch evalPolicyError!.code {
case LAError.SystemCancel.toRaw():
println("Authentication was cancelled by the system")
case LAError.UserCancel.toRaw():
println("Authentication was cancelled by the user")
case LAError.UserFallback.toRaw():
println("User selected to enter custom password")
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.showPasswordAlert()
})
default:
println("Authentication failed")
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.showPasswordAlert()
})
}
}
})]
}
}
You can't, Apple does not allow access to the fingerprint data. This has to do with security.
The iOS SDK only allows you let a user validate them selfs with the Touch ID.

Resources