Wondering how I can determine if the device the user has supports the Touch ID API? Hopefully have this as a boolean value.
Thanks!
try this:
- (BOOL)canAuthenticateByTouchId {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
return [[[LAContext alloc] init] canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil];
}
return NO;
}
or like #rckoenes suggest:
- (BOOL)canAuthenticateByTouchId {
if ([LAContext class]) {
return [[[LAContext alloc] init] canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil];
}
return NO;
}
UPDATE
I forgot, check this: How can we programmatically detect which iOS version is device running on? to define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO
You should consider LAContext framework that is required to Touch ID authentication.
And parameter LAErrorTouchIDNotAvailable will show is devise support this functionality.
Code snippet :
- (IBAction)authenticateButtonTapped:(id)sender {
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// Authenticate User
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
}
Nice tutorial to learn this feature is here.
You can check the error using CanEvaluatePolicy. If the Error Code is -6, it means no physical Touch Id on that device. You can tell from the Error Description, it says
Biometry is not available on this device.
Below is the code if you're using C# Xamarin:
var context = new LAContext();
NSError AuthError;
if (!context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError))
{
if ( AuthError != null && AuthError.Code == -6 )
{
var alert = new UIAlertView ("Error", "TouchID not available", null, "BOOO!", null);
alert.Show ();
}
}
This function will help with that -
-(BOOL)doesThisDeviceSupportTouchIdForLocalAuthentication{
//Checking for 64 bit (armv7s) architecture before including the LAContext as it would give error otherwise.
#if TARGET_CPU_ARM64
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]){
return YES;
}
return NO;
#endif
return NO;
}
Objective c
#import LocalAuthentication;
// Get the local authentication context:
LAContext *context = [[LAContext alloc] init];
// Test if fingerprint authentication is available on the device and a fingerprint has been enrolled.
if ([context canEvaluatePolicy: LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil])
{
NSLog(#"Fingerprint authentication available.");
}
Related
I'm using the following logic to check if touchID is available on iPhone and based on the returned value, I direct the user to enroll in touchID or navigate them to setup a PIN. It works fine in the happy path, but if I have even one fingerprint enrolled but have disabled touchID option from iPhone system settings, then it still returns true and navigates user to setup touchID. If I remove all fingerprints, then it works as expected by returning false and navigating to PIN screen.
- (BOOL) isTouchIDAvailable {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
NSLog(#"Touch ID checking error: %#", [authError localizedDescription]);
return NO;
}
return YES;
}
I've referred to some questions on stack and apple dev docs
Not sure what I'm missing? Appreciate any help. Thanks in advance :)
let context = LAContext()
var error: NSError?
if #available(iOS 9.0, *) {
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
//this is for success
}else{
//error.description for type error LAError.biometryLockout, .biometryNotEnrolled and other errors
}
}
it's not possible. if you have TouchID, you have touchID. But if you want, you can disabled with programaticly. Look at the below code snippet to check touchID is aviable or not.
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = [NSString stringWithFormat:#"Login With your fingerprint with : %#",username];
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
// [self performSegueWithIdentifier:#"Success" sender:nil];
[self loginWithFingerprint];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
I have enabled touch id inmy iOS app. But iPhone 5 and 5c the finger print sensor is not available. How can I detect devices programmatically which are not having finger print sensor. My app is written in objective-c.
Please help me.
Thanks
You should use LAContext framework that is required for Touch ID authentication.
LAErrorTouchIDNotAvailable shows which device has the functionality.
Code snippet :
- (IBAction)shouldAuthenticate:(id)sender {
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// Authentication here.
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
}
or try this to get BOOL return :
- (BOOL)canAuthenticateByTouchId {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
return [[[LAContext alloc] init] canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil];
}
return NO;
}
func checkIfTouchIDEnabled() {
var error:NSError?
// 2. Check if the device has a fingerprint sensor
// If not, show the user an alert view and bail out!
guard authenticationContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
if let error = error as NSError? {
if error.code == LAError.Code.touchIDNotAvailable.rawValue { /* Device does not support touch id*/
print("Finger print sensors are not present in this device")
} else if error.code == LAError.Code.touchIDNotEnrolled.rawValue {
print("Finger print sensors are present in this device but no TouchID has been enrolled yet")
} else {
// Add more checks ...
}
}
return
}
}
I use the following code to check and request authorization for the Camera. Problem is the following. The following scenario leads to a wrong authorization status:
User declines authorization for the first time
Terminates the app
Restarts the app
Leaves the application, grants authorization for the camera in settings app
Returns to the app
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] will return AVAuthorizationStatusDeclined (authorized as said).
After terminating and restarting results in AVAuthorizationStatusAuthorized as it should. In this case the user leaves to settings and denies camera access the result will remain AVAuthorizationStatusAuthorized until next restart.
Any ideas what I miss here?
- (void) popCamera {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
//picker.allowsEditing = YES;
#if !(TARGET_IPHONE_SIMULATOR)
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
#endif
self.view.translatesAutoresizingMaskIntoConstraints = YES;
[self presentViewController:picker animated:YES completion:NULL];
}
- (void)camDenied
{
NSLog(#"%#", #"Denied camera access");
NSString *alertText;
NSString *alertButton;
BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
if (canOpenSettings)
{
alertText = LSS(#"DeniedCamera1");
SDCAlertView *alert = [[SDCAlertView alloc]
initWithTitle:LSS(#"DeniedCameraTitle")
message:alertText
delegate:self
cancelButtonTitle:LSS(#"Cancel")
otherButtonTitles:LSS(#"Goto"), nil];
alert.tag = 3491832;
[alert show];
}
else
{
alertText = LSS(#"DeniedCamera2");
SDCAlertView *alert = [[SDCAlertView alloc]
initWithTitle:LSS(#"DeniedCameraTitle")
message:alertText
delegate:self
cancelButtonTitle:LSS(#"Cancel")
otherButtonTitles:nil];
alert.tag = 3491832;
[alert show];
}
}
- (IBAction) onTakePhoto:(id)sender {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(authStatus == AVAuthorizationStatusAuthorized)
{
[self popCamera];
}
else if(authStatus == AVAuthorizationStatusNotDetermined)
{
NSLog(#"%#", #"Camera access not determined. Ask for permission.");
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
{
if(granted)
{
[self popCamera];
}
else
{
[self camDenied];
}
}];
}
else if (authStatus == AVAuthorizationStatusRestricted)
{
SDCAlertView *alert = [[SDCAlertView alloc]
initWithTitle:LSS(#"RestrictCameraTitle")
message:LSS(#"RestrictCamera")
delegate:self
cancelButtonTitle:LSS(#"OK")
otherButtonTitles:nil];
}
else
{
[self camDenied];
}
}
Credits for the original code: Is there a way to ask user for Camera access after they have already denied it on iOS 8?
This seems to be the intended behaviour. If Apple would want you to react to authorization changes at runtime, there would be a notification that tells you that it changed.
But right now, there is no such notification (as far as I can see). You just call +authorizationStatusForMediaType: and it either returns a definitive status (like denied or authorized), or it returns AVAuthorizationStatusNotDetermined to tell you that you need to request authorization via requestAccessForMediaType:completionHandler:.
Unfortunately, this isn't an authoritative answer; I'm just drawing conclusions and guessing here. You might want to ask on Apple's developer forum and hope to get an answer from an Apple engineer.
I'm using Twitter SDK to loggin and tweet. Authenticate it's ok, but when use TWTRComposer with a simple text, the SDK callback return 'TWTRComposerResultDone', but the Simulator/Device show 'The tweet "text" cannot be sent because the connection to Twitter failed.
The debugger show 'plugin com.apple.share.Twitter.post invalidated' but everything aparently is correct.
Is there a bug or I forgot some thing.
My code:
TWTRComposer *composer = [[TWTRComposer alloc] init];
[composer setText:#"some text"];
[composer showWithCompletion:^(TWTRComposerResult result) {
if (result == TWTRComposerResultCancelled) {
NSLog(#"Tweet composition cancelled");
}
else {
NSLog(#"Sending Tweet!");
}
}];
Tweet Using SDK
1. Crearte App on twitter.developer
2. add twitter frameworks like TwitterCore.framework, TwitterKit.framework, Fabric.framework, TwitterKitResources.bundle
3. write below code in tweet button
[[Twitter sharedInstance] startWithConsumerKey:#"YourConsumerKey" consumerSecret:#"YourConsumerSecret"];
[Fabric with:#[[Twitter sharedInstance]]];
[[Twitter sharedInstance] logInWithCompletion:^(TWTRSession *session, NSError *error)
{
if (session)
{
NSLog(#"logged in user with id %#", session.userID);
TWTRComposer *composer = [[TWTRComposer alloc] init];
[composer setText:#"Enter Your Tweet Message"];
//[composer setImage:[UIImage imageNamed:#"fabric"]];
[composer showFromViewController:self completion:^(TWTRComposerResult result) {
if (result == TWTRComposerResultCancelled)
{
NSLog(#"Tweet composition cancelled");
}
else
{
NSLog(#"Sending Tweet!");
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"" message:#"Sent Tweet!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
}
}];
}
else
{
// log error
}
}];
I'm working on adding the LocalAuthentication framework to allow users to authenticate with a fingerprint on comparable devices. Everything works properly, but when a user is authenticated with their finger print it takes between 10-15 seconds for the proper segue to be performed, is this typical, or is there something wrong with the way I'm authenticating a user?
Code:
-(void)viewDidLoad { [super viewDidLoad]; [self.view setBackgroundColor:[NPSColor NPSBackgroundColor]];
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Register" style:UIBarButtonItemStylePlain target:self action:#selector(onRegisterTapped)]; self.navigationItem.rightBarButtonItem = anotherButton;
LAContext *context = [[LAContext alloc] init];
NSError *error = nil; if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:#"Login?" reply:BOOL success, NSError *error {
if (error) {
}
if (success) {
[self performSegueWithIdentifier:#"loginSeg" sender:self];
} else {
}
}];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
} }
So it may be that performing a segue has to do with a view action which should mainly be performed on the main thread. I'm not too sure but it could very well be the evaluatePolicy method is performed on a background thread. If this is the case, you would want to throw your performSegue on the main thread.
To do so, use this:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"loginSeg" sender:self];
});