I've a strange bug which occur only on iPad physical device, on iPhone physical device and all iPad simulators all works great, but on iPad physical device I get Error Domain=kAFAssistantErrorDomain Code=1700. How this can happen?
My code for SFSpeechRecognizer:
func requestTranscribePermissions() {
SFSpeechRecognizer.requestAuthorization { [unowned self] authStatus in
DispatchQueue.main.async {
if authStatus == .authorized {
print("Good to go!")
} else {
print("Transcription permission was declined.")
}
}
}
}
func convertAudioToText() {
if let file = audio {
print(file)
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
let request = SFSpeechURLRecognitionRequest(url: file)
request.shouldReportPartialResults = false
if (recognizer?.isAvailable)! {
recognizer?.recognitionTask(with: request) { result, error in
guard error == nil else { print("Error: \(error!)"); return }
guard let result = result else { print("No result!"); return }
self.text = result.bestTranscription.formattedString
self.performSegue(withIdentifier: "Convert", sender: nil)
print(result.bestTranscription.formattedString)
}
} else {
print("Device doesn't support speech recognition")
}
} else {
let alert = UIAlertController(title: "There's no audio", message: "No audio recorded", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .default, handler: { _ in
NSLog("The \"OK\" alert occured.")
}))
self.present(alert, animated: true, completion: nil)
}
}
Only on iPad phycal device I get:
[Utility] +[AFAggregator logDictationFailedWithError:] Error Domain=kAFAssistantErrorDomain Code=1700 "(null)"
Error: Error Domain=kAFAssistantErrorDomain Code=1700 "(null)"
I had the same error in my app.
The error was fixed updating my iphone from iOS 13.4.2 to 13.5.1 and XCode to 11.5.
Hope this help.
I had this problem on macOS and it was simply due to not requesting authorisation first.
[SFSpeechRecognizer requestAuthorization: ...]
Related
I have followed this tutorial to set up authentication on my app.
It works fine, but when try to terminate the app, I get the following:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the
layout engine must not be performed from a background thread after it
has been accessed from the main thread.'
* First throw call stack:
(0x18bf22a48 0x18bc49fa4 0x18c3f8f08 0x18c1fa03c 0x19035664c 0x190357a00 0x18f604c5c 0x18f6004c8 0x18f600734 0x18f600a54
0x18f6054dc 0x18f605328 0x18f5e7004 0x18f97b134 0x18f97b838
0x18f990f70 0x18f989d7c 0x18f98b790 0x18f98dc6c 0x18f98e168
0x18f98dbbc 0x18f98de24 0x100c0f4ec 0x100c01780 0x1017917fc
0x101792bd8 0x1017952d4 0x1017a4160 0x1017a4a88 0x18bc3eb48
0x18bc41760)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
I do not understand the error.
Here's my code:
func authenticateUser() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { [weak self] success, authError in
DispatchQueue.main.async {
if success {
self?.loginSuccessfull()
} else {
DispatchQueue.main.async {
let ac = UIAlertController(title: "Errore", message: "Riprova", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
self?.authenticateUser()
return
}))
self?.present(ac, animated: true, completion: nil)
}
}
}
}
} else {
let ac = UIAlertController(title: "Errore", message: "Il tuo device non è configurato per l'autenticazione", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Ok", style: .default))
self.present(ac, animated: true, completion: nil)
}
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] success, authenticationError in
DispatchQueue.global().async {
if success {
DispatchQueue.main.async {
self.loginSuccessfull()
}
} else {
let ac = UIAlertController(title: "Authentication failed", message: "Sorry!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
}
}
} else {
let ac = UIAlertController(title: "Touch ID not available", message: "Your device is not configured for Touch ID.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
As you can see, I just evaluate the biometrics. Again: this works perfectly during the whole "life" of the application, but the problem comes out when I terminate the app. It just crashes and gets me to the home screen.
There are no crash logs into Settings > Privacy...
please use for authentication function its a global function
//enum for response handler
enum AuthenticatinsError: String {
case userEnrolled = "User is not enrolled"
case passCodeNotSet = "user not set passcode"
case biometricNotAvelabel = "Biometric authentication not available"
case faild = "faild to authenticat"
case noIssue = ""
}
func authenticationUser(compleation: #escaping (_ status: Bool, _ msgg: AuthenticatinsError) -> Void) {
context = LAContext()
//check inside app if biometric on then in UserDefault set true other wise false
//let isBiometricOn = WUserDefault.getBiometric()
//if isBiometricOn == false {
//context.invalidate()
//}
// 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 {
compleation(true, .noIssue)
} else {
print(error?.localizedDescription ?? "Failed to authenticate")
compleation(false, .faild )
}
}
} else {
if let err = error {
if #available(iOS 11.0, *) {
switch err.code {
case LAError.Code.biometryNotEnrolled.rawValue:
notifyUser("User is not enrolled",
err: err.localizedDescription)
compleation(false, .userEnrolled)
case LAError.Code.passcodeNotSet.rawValue:
compleation(false, .passCodeNotSet)
case LAError.Code.biometryNotAvailable.rawValue:
notifyUser("Biometric authentication not available",
err: err.localizedDescription)
compleation(false, .biometricNotAvelabel)
default:
compleation (false, .passCodeNotSet)
}
} else {
// Fallback on earlier versions
}
}
}
}
user code where you call
self.authenticationUser { (statu, msg) in
if statu == true {
DispatchQueue.main.async {
self?.loginSuccessfull()
}
} else {
DispatchQueue.main.async {
let ac = UIAlertController(title: "Errore", message: "Riprova", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
self?.authenticateUser()
return
}))
self?.present(ac, animated: true, completion: nil)
}
}
}
I a implementing face ID in my iOS app. When authentication fails a alert shows containing cancel and try again buttons, cancel button works but try again button not working. How can I edit this button or to be worked try again button. When i Click on try again button nothing happens if i click on cancel button that is working and even title of cancel button also be changing but no action is applying on try again.I have tried the following code and had a lot of search on internet but nothing found.
enter image description here
func startFaceIDTest(){
attempted = true
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason, reply: {
successfaceID, authenticationError in
DispatchQueue.main.async {
if successfaceID {
self.success = true
} else {
self.success = false
guard let errorr = authenticationError else {return}
switch(errorr) {
case LAError.authenticationFailed:
print("Failed")
break
case LAError.userCancel:
print("User cancel")
break
case LAError.userFallback:
print("Fallback")
break
case LAError.systemCancel:
print("System cancel")
break
default:
break
}
}
}
})
} else {
if let err = error {
if #available(iOS 11.0, *) {
self.success = false
switch err.code {
case LAError.Code.biometryNotEnrolled.rawValue:
notifyUser("Your device not enrolled for biometric",
err: err.localizedDescription)
case LAError.Code.passcodeNotSet.rawValue:
notifyUser("A passcode has not been set",
err: err.localizedDescription)
case LAError.Code.biometryNotAvailable.rawValue:
notifyUser("Biometric authentication not available",
err: err.localizedDescription)
default:
notifyUser("Unknown error",
err: err.localizedDescription)
}
} else {
// Fallback on earlier versions
}
}
}
}
func notifyUser(_ msg: String, err: String?) {
let alert = UIAlertController(title: msg, message: err, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
func bioandpasscodeAuthentication() {
let context = LAContext()
var error:NSError?
// edit line - deviceOwnerAuthentication
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
//showAlertViewIfNoBiometricSensorHasBeenDetected()
return
}
let reason = "Identify yourself!"
// edit line - deviceOwnerAuthentication
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
// edit line - deviceOwnerAuthentication
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason, reply: { (success, error) in
if success {
DispatchQueue.main.async {
print("Authentication was successful")
}
}else {
DispatchQueue.main.async {
//self.displayErrorMessage(error: error as! LAError )
print("Authentication was error")
}
}
})
}else {
// self.showAlertWith(title: "Error", message: (errorPointer?.localizedDescription)!)
}
}
try this code
I am using Face id in my iOS app. Be default when user fails to authenticate try again not working. I want to add callback when user click on try again.Please see my below code.I have searched a lot but nothing found about face id.
func startFaceIDTest(){
attempted = true
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] (successfaceID, authenticationError) in
DispatchQueue.main.async {
if successfaceID {
self.success = true
//self.unlockSecretMessage()
} else {
self.success = false
// let ac = UIAlertController(title: "Authentication failed", message: "You could not be verified; please try again.", preferredStyle: .alert)
// ac.addAction(UIAlertAction(title: "OK", style: .default))
// self.present(ac, animated: true)
}
}
}
} else {
if let err = error {
if #available(iOS 11.0, *) {
self.success = false
switch err.code {
case LAError.Code.biometryNotEnrolled.rawValue:
notifyUser("Your device not enrolled for biometric",
err: err.localizedDescription)
case LAError.Code.passcodeNotSet.rawValue:
notifyUser("A passcode has not been set",
err: err.localizedDescription)
case LAError.Code.biometryNotAvailable.rawValue:
notifyUser("Biometric authentication not available",
err: err.localizedDescription)
default:
notifyUser("Unknown error",
err: err.localizedDescription)
}
} else {
// Fallback on earlier versions
}
}
}
}
I cannot get even the demonstration code to work after converting it to swift 3.0. I have tried everything I can think of to no avail.
The exception is very unhelpful and the stack trace as well. (see the screenshot)
This is the swift 2.3 code, which works perfectly well:
#IBAction func getCurrentPlace(sender: UIButton) {
placesClient?.currentPlaceWithCallback({
(placeLikelihoodList: GMSPlaceLikelihoodList?, error: NSError?) -> Void in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
return
}
self.nameLabel.text = "No current place"
self.addressLabel.text = ""
if let placeLikelihoodList = placeLikelihoodList {
let place = placeLikelihoodList.likelihoods.first?.place
if let place = place {
self.nameLabel.text = place.name
self.addressLabel.text = place.formattedAddress!.componentsSeparatedByString(", ")
.joinWithSeparator("\n")
}
}
})
}
And this is the equivalent in swift 3.0:
#IBAction func go(_ sender: AnyObject) {
var placesClient: GMSPlacesClient?
placesClient = GMSPlacesClient.shared()
placesClient?.currentPlace(callback: {
(placeLikelihoodList: GMSPlaceLikelihoodList?, error: NSError?) in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
let alert = UIAlertController(title: "Error", message: "Couldn't find a location", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
if let placeLikelihoodList = placeLikelihoodList {
let place = placeLikelihoodList.likelihoods.first?.place
if let place = place {
self.testlabel.text = place.name
}
}
} as! GMSPlaceLikelihoodListCallback)
}
The exception stops me here: as! GMSPlaceLikelihoodListCallback
Anyone have a clue as to what's going on?
var placesClient: GMSPlacesClient?
placesClient = GMSPlacesClient.shared()
placesClient?.currentPlace(callback: { (place, error) in
if let error = error {
print("Pick Place error: \(error.localizedDescription)")
let alert = UIAlertController(title: "Error", message: "Couldn't find a location", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
if let placeLikelihoodList = place {
let place = placeLikelihoodList.likelihoods.first?.place
if let place = place {
self.lblOrigem.text = place.formattedAddress
}
}
})
The documentation that Apple has provided for TouchID implementation for iOS 8 is in Objective-C.
Is there a Swift version of it?
Objective-C:
- (IBAction)touchIDAvailable:(UIButton *)touchIDAvailableButton {
LAContext *context = [[LAContext alloc] init];
__block NSString *msg;
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(#"Place your finger on the sensor", nil) reply: ^(BOOL success, NSError *authenticationError) {
if (success) {
}
}
}
Swift:
#IBAction func touchidbutton(sender: AnyObject) {
authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Place your finger on the sensor"?, reply: ((success : Bool, NSError!) -> Void)?){
if (success) {
}
}
}
Here is my view controller that does these checks in Swift. While working on this I found the completion block/closure syntax in Swift to be very confusing.
Notice that some of the options changed in Beta 2 in order to give you more control over the Touch ID dialog such as disabling the fallback option or the cancel button.
// Imports
import UIKit
import LocalAuthentication
// Class Implementation
class FirstViewController: UIViewController {
// Class Properties
#IBOutlet var statusLabel : UILabel
#IBOutlet var headerString: UILabel
var authError : NSError?
var authContext = LAContext()
var statusText = ""
var alert = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.Alert)
// Class Methods
#IBAction func swiftButtonPress(sender : AnyObject) {
statusLabel.text = "Authenticating"
//Can we use local auth?
if authContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &authError) {
authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics,
localizedReason: "I need to see if it's really you",
reply: {(success: Bool, error: NSError!) -> Void in
if success {
self.statusText = "Touch ID success!"
self.alert.title = "Success"
self.alert.message = "I knew it was you!"
} else {
self.statusText = "Touch ID failed!"
self.alert.title = "Failure"
switch error!.code {
case LAError.AuthenticationFailed.toRaw():
self.alert.message = "Authentication Failed"
case LAError.UserCancel.toRaw():
self.alert.message = "User canceled!"
case LAError.SystemCancel.toRaw():
self.alert.message = "The system canceled!"
case LAError.UserFallback.toRaw():
self.alert.message = "User request to enter passcode"
default:
self.alert.message = "Something else went wrong"
}
}
self.presentViewController(self.alert, animated: true, completion:{self.statusLabel.text = self.statusText})
})
} else {
self.statusText = "No local authentication"
alert.title = "Uh oh!"
switch authError!.code {
case LAError.TouchIDNotAvailable.toRaw():
alert.message = "No Touch ID on device"
case LAError.TouchIDNotEnrolled.toRaw():
alert.message = "No fingers enrolled"
case LAError.PasscodeNotSet.toRaw():
alert.message = "No passcode set"
default:
alert.message = "Something went wrong getting local auth"
}
self.presentViewController(self.alert, animated: true, completion: {self.statusLabel.text = self.statusText})
}
resetTouchID()
}
// Reset the system so we can go again
func resetTouchID() {
authContext = LAContext()
alert = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
let passcodeDetector = SwiftPasscodeDetector()
if passcodeDetector.checkForPasscode() {
headerString.text = "Passcode Set on Device"
} else {
headerString.text = "No Passcode Set"
}
}
// Inherited Methods
override func viewDidLoad() {
super.viewDidLoad()
resetTouchID()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The API name is LAContext, and it's in the docs right here. It's pretty sparse, but it does its job. The method you probably want is
evaluatePolicy(_ policy: LAPolicy,
localizedReason localizedReason: String!,
reply reply: ((Bool, NSError!) -> Void)!)
The string argument is a subheader to display to the user, the reply is simply a callback block, and the policy currently has to be LAPolicy.DeviceOwnerAuthenticationWithBiometrics, but it appears the framework is there for other types of authentication in the future. Interesting...
Hope that helps! I tried on my phone because I was curious and it works wonderfully. Just make sure to query for ability to evaluate policy before you try to use it, in case it's on an older device.
The LAContext reference has method signatures in both Obj-C and Swift. Furthermore, if you ⌘-click on the LAContext class in your Swift code, you should be able to view the generated "header" for it in Swift.
Updated to Swift 3
static func authorizeWithTouchIDIfPossible(){
let authContext = LAContext()
var authError : NSError?
if authContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
authContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "I need to see this", reply: { (success, error) in
if success {
print("Touch ID success!")
DispatchQueue.main.async {
//Do stuff here
}
} else {
print("Touch ID failed!")
}}
);
} else {
print("No local authentication")
}
}
Found it!
The link below is from a user named Shmoopi from Github. Shmoopi made the app to test the TouchID programmed in Swift.
https://github.com/Shmoopi/Swift-Touch-ID
Swift 3.0 in:
import UIKit
import LocalAuthentication
class ViewController: UIViewController
{
#IBAction func TouchBtn(_ sender: AnyObject)
{
let context:LAContext = LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error:nil)
{
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason:"We Need Your Id", reply:{
(wasSuccessful,Error) in
if wasSuccessful
{
print("Was a Sucess")
}
else
{
print("Not Logged In")
}
})
}
}
}
Swift 5 :
import LocalAuthentication
func authenticateUser() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Identify yourself!"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
[unowned self] success, authenticationError in
DispatchQueue.main.async {
if success {
print("Success!")
} else {
let ac = UIAlertController(title: "Authentication failed", message: "Sorry!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
self.present(ac, animated: true)
}
}
}
} else {
let ac = UIAlertController(title: "Touch ID not available", message: "Your device is not configured for Touch ID.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}