- (void)touchIdIntegration{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:#"Authenticate via Touch ID to unlock the app"
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[[AppManager instance].helpManager setDontShowInterstialAd:TRUE];
[[AppManager instance].cycleManager setUserAuthenticated:TRUE];
[self.delegate showAlertViewsOnServerData];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
switch (error.code) {
case kLAErrorAuthenticationFailed:
NSLog(#"kLAErrorAuthenticationFailed");
break;
case kLAErrorTouchIDNotEnrolled:
NSLog(#"kLAErrorTouchIDNotEnrolled");
break;
case LAErrorPasscodeNotSet:
NSLog(#"LAError code ");
break;
default:
break;
}
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
self.m_imgFingerPrint.hidden = YES;
NSLog(#"LAError code %ld",authError.code);
NSString *alertMessage =nil;
switch (authError.code) {
case kLAErrorAuthenticationFailed:
{
alertMessage = #"kLAErrorAuthenticationFailed" ;
}
break;
case kLAErrorTouchIDNotEnrolled:
alertMessage = #"kLAErrorTouchIDNotEnrolled" ;
break;
case LAErrorPasscodeNotSet:
alertMessage = #"LAErrorPasscodeNotSet" ;
break;
default:
break;
}
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:alertMessage
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
});
}
}
I don't want this pop up each every time when user moves to this screen.Is it possible or not ?Please let me know.
please find the screen shot below:
Anyways thanks in advance.
Don't write this code viewDidLoad or viewDidAppear. Write it only when it is absolutely required to ask for touchID.
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 made one demo for login application with touch id authentication.
It is going fine with touch id authentication but,
My Problem is
When I do authentication with my touch id it gives me immediate response according the finger scans , But after messaging it took so much time for further process like move forward or display result which I have placed on success.
I have also used Switch Case Statements in my code.
Code is
- (IBAction)touchidRegistration:(id)sender {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Authenticate using your finger";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
self.myHud.hidden = NO;
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL succes, NSError *error) {
if (succes) {
self.btnRegister.enabled = YES;
// self.myHud.hidden = YES;
self.registrationFlag = #"YES";
self.flag = #"";
self.verifiedImage.hidden = NO;
NSLog(#"flag Value is %#",self.flag);
NSLog(#"Done!!!");
[self showMessage:#"Authentication is successful" withTitle:#"Success"];
NSLog(#"User authenticated");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
self.myHud.hidden = YES;
[self showMessage:#"Authentication is failed" withTitle:#"Error"];
NSLog(#"Authentication Failed");
break;
case LAErrorUserCancel:
self.myHud.hidden = YES;
[self showMessage:#"You clicked on Cancel" withTitle:#"Error"];
NSLog(#"User pressed Cancel button");
break;
case LAErrorUserFallback:
self.myHud.hidden = YES;
[self showMessage:#"You clicked on \"Enter Password\"" withTitle:#"Error"];
NSLog(#"User pressed \"Enter Password\"");
break;
default:
self.myHud.hidden = YES;
[self showMessage:#"Touch ID is not configured" withTitle:#"Error"];
NSLog(#"Touch ID is not configured");
break;
}
NSLog(#"Authentication Fails");
}
}];
} else {
self.myHud.hidden = YES;
NSLog(#"Can not evaluate Touch ID");
[self showMessage:#"Can not evaluate TouchID" withTitle:#"Error"];
}
}
Please help me guys or suggest me any link I do not able to search this type of problem on here.I have seen one but its for Swift,I need for OBJECTIVE - C
link:- swift - touchID takes long time to load
Note:-I am using I-Phone 6 device for testing.
Thanks in advance.
Finally I got the answer ,
Its Working Fine For me thank you
if (succes) {
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{
// Background work
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Main thread work (UI usually)
NSMutableDictionary *userInfo = [StaticClass getTouchIdData:#"userInfo"];
if(!([userInfo count] == 0))
{
self.myHud.hidden = YES;
self.flag = #"";
TestViewController *testView = [[TestViewController alloc]initWithNibName:#"TestViewController" bundle:nil];
[testView setUserInfo:userInfo];
[self.navigationController pushViewController:testView animated:YES];
}
else
{
self.myHud.hidden = YES;
self.flag = #"YES";
self.registrationFlag = #"";
[self showMessage:#"For The First time user ,You have to login manually" withTitle:#"Error"];
self.touchIdLoginView.hidden = YES;
}
NSLog(#"User Id is %#",userInfo);
NSLog(#"Done!!!");
NSLog(#"User authenticated");
}];
}];
Is it possible in Objective-C in xCode to open up the native iPhone "Add Event" calendar prompt with a couple of fields already filled in? For instance name, address and start/end date? If so, how?
This would allow the user to still change a couple of parameters: when does he want to be alerted, etc.
I have looked around but all I have found are methods to automatically add the event without the confirmation of the user.
Step 1
First take Calendar Permission
dispatch_async(dispatch_get_main_queue(), ^{
[self.eventManager.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if(granted==NO)
{
BOOL permission=[[NSUserDefaults standardUserDefaults] boolForKey:#"CalendarPermissionAlert"];
if(permission==NO) {
kAppDelegateObject.eventManager.eventsAccessGranted=NO;
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:#"CalendarPermissionAlert"];
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Calendar Access is OFF"
message:kCalenderResetMessage
delegate:self
cancelButtonTitle:#"CANCEL"
otherButtonTitles:#"SETTING",nil];
[alert show];
alert.tag=101;
return ;
}
}
Step 2
//Add Event
-(void)addEventWithMessage:(NSString*)eventMessage withEventDate:(NSDate *)eventDate
EKEventStore *eventStore;
eventStore = [[EKEventStore alloc] init];
// Create a new event object.
EKEvent *event = [EKEvent eventWithEventStore: eventStore];
// Set the event title.
event.title = eventMessage;
// Set its calendar.
NSString *identifier=[[NSUserDefaults standardUserDefaults]objectForKey:#"calenderId"]; //your application id
// NSLog(#"cal identifier: %#",identifier);
event.calendar = [eventStore calendarWithIdentifier:identifier];
//set Alarm
NSTimeInterval secondsInOneHours = 1 * 60 * 60;
NSDate *dateOneHoursAhead = [eventDate dateByAddingTimeInterval:secondsInOneHours];
// Set the start and end dates to the event.
event.startDate = eventDate;
event.endDate = dateOneHoursAhead; //
NSError *error;
if ([eventStore saveEvent:event span:EKSpanFutureEvents commit:YES error:&error]) {
// NSLog(#"Event Added");
}
else{
// An error occurred, so log the error description.
// NSLog(#"%#", [error localizedDescription]);
}
Here is how I handled it...with EKEventEditViewController!
First:
#import EventKitUI;
At the very top of your .m file.
Then set the EKEventEditViewDelegate
Then, when you want to add the event, use the following method:
- (IBAction)addToCalendar:(id)sender {
EKEventStore *eventStore = [[EKEventStore alloc] init];
if ([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
// the selector is available, so we must be on iOS 6 or newer
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error)
{
NSLog(#"%#", error);
// display error message here
}
else if (!granted)
{
NSLog(#"%# acce sdenied", error);
// display access denied error message here
}
else
{
EKEvent *event = [EKEvent eventWithEventStore: eventStore];
event.title = nom;
event.location = adresse;
// Set the start and end dates to the event.
event.startDate = startDate;
event.endDate = endDate; //
EKEventEditViewController *eventViewController = [[EKEventEditViewController alloc] init];
eventViewController.event = event;
eventViewController.eventStore=eventStore;
eventViewController.editViewDelegate = self;
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
[eventViewController setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:eventViewController animated:YES completion:NULL];
}
});
}];
}
}
Finally, add this delegate method to handle the completion action:
-(void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action {
NSError *error;
switch (action) {
case EKEventEditViewActionCancelled:
// User tapped "cancel"
NSLog(#"Canceled");
break;
case EKEventEditViewActionSaved:
NSLog(#"Saved");
[controller.eventStore saveEvent:controller.event span: EKSpanFutureEvents error:&error];
[calendarBouton setTitle:#"Ajouté!" forState:UIControlStateDisabled];
calendarBouton.enabled = NO;
break;
case EKEventEditViewActionDeleted:
// User tapped "delete"
NSLog(#"Deleted");
break;
default:
NSLog(#"Default");
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Currently I am trying to send sms from a users phone through an app.
The idea is that the user selects the recipients of the message and then one by one the message is sent to each recipient.
Currently this is how I am doing it after a button is clicked this happens
if (self.abNumbersSelected.count > 0){
for(NSString *phoneNumber in self.abNumbersSelected)
{
if(self.currentController)
[self.currentController dismissViewControllerAnimated:YES completion:^{[self sendInviteMessage:phoneNumber];}
];
else
[self sendInviteMessage:phoneNumber];// message that invites selected message
}
}
abNumbersSelected is an array of numbers that the user has picked the sendInviteMessage is here:
- (void)sendInviteMessage:(NSString*)invitingNumber
{
//Invites the numbers using sms
//First checks if it duplicates it
if ([self checkDuplicate:invitingNumber]) {
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"Invalid Phone Number" message:#"The phone number you entered is not valid." delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[alertView show];
self.phoneField.text = #"";
}
//if not a duplicate then it sends the message
else {
if (SharedSessionManager.authToken) {
NSString* currentUserName = #"";
if (SharedSessionManager.currentUser.firstName && SharedSessionManager.currentUser.lastName) {
currentUserName = [NSString stringWithFormat:#"%# %#", SharedSessionManager.currentUser.firstName, SharedSessionManager.currentUser.lastName];
}
else if (SharedSessionManager.currentUser.firstName) {
currentUserName = SharedSessionManager.currentUser.firstName;
}
if (!customLoadingView.isLoading)
[customLoadingView beginLoading];
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
NSString *message = [NSString stringWithFormat:#"%# invited you to join Friendli - a mobile, location based social network. Join now at friendli.co",currentUserName];
controller.body = message;
controller.recipients = [NSArray arrayWithObjects:invitingNumber, nil];
controller.messageComposeDelegate = self;
controller.disableUserAttachments;
controller.title = #"Invite Friend";
self.currentController = controller;
[self presentModalViewController:self.currentController animated:YES];
}
}
}
}
Currently no message shows up to be sent.
Also here is the messageComposeViewController: method
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult) result
{
switch (result) {
case MessageComposeResultCancelled:
break;
case MessageComposeResultFailed:
{
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to send SMS!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
break;
}
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
In the log this is what is said when 2 recipients are picked and the button to trigger the MFMessageComposeViewController to be created is clicked by the user
2015-06-05 13:29:10:521 Friendli[241:807] [self.abNumbersSelected count]: 2
2015-06-05 13:29:11:638 Friendli[241:807] Reading auth token from keychain. (friendli.116.authtoken)
2015-06-05 13:29:11:643 Friendli[241:807] Reading auth token from keychain. (friendli.116.authtoken)
2015-06-05 13:29:12.869 Friendli[241:10525] Remote compose controller timed out (NO)!
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult) result
{
switch (result) {
case MessageComposeResultCancelled:
break;
case MessageComposeResultFailed:
{
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Failed to send SMS!" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[warningAlert show];
break;
}
case MessageComposeResultSent:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:^{
if (self.abNumbersSelected.count > 0 && self.multipleRecipients) {
[self sendInviteMessage:[self.abNumbersSelected objectAtIndex:0]];
}
}];
}
In the didFinish method for the MFMessageComposeController in the dismiss statement using the if statement in the block of code the code will continue to create more MFMessageComposeViewControllers till it is done.
I have implemented EKEventStore, EKCalendar in my app to make the EKEvent within the app. It is working fine until or unless I didn't change permissions from the settings. But when I changed the requested access (on/off or off/on) from the settings, the app get crashed. I am unable to find the error. If someone has idea then please help me out. Here is the code I have implemented :
self.eventStore = [[EKEventStore alloc] init];
[self checkEventStoreAccessForCalendar];
-(void)checkEventStoreAccessForCalendar
{
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
switch (status)
{
case EKAuthorizationStatusAuthorized: [self accessGrantedForCalendar];
break;
case EKAuthorizationStatusNotDetermined: [self requestCalendarAccess];
break;
case EKAuthorizationStatusDenied:
case EKAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Privacy Warning" message:#"Permission was not granted for Calendar"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
} }
-(void)requestCalendarAccess
{
[self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted,
NSError *error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
}];
}
-(void)accessGrantedForCalendar
{
self.defaultCalendar = self.eventStore.defaultCalendarForNewEvents;
EKEvent *addEvent = [EKEvent eventWithEventStore:self.eventStore];
addEvent.title = [NSString stringWithFormat:#"%#", textcontainer.text];
}
#pragma mark EKEventEditViewDelegate
-(void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action{
[self dismissViewControllerAnimated:YES completion:^
{
if (action != EKEventEditViewActionCanceled)
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
}];
}
- (EKCalendar *)eventEditViewControllerDefaultCalendarForNewEvents:(EKEventEditViewController *)controller
{
return self.defaultCalendar;
}
When your app goes to the background it should save all its states and should be prepared to get killed. When someone switches off access to calendar, the easiest way for the system to deals with that is to kill your app, and that is why its happening. If you switch back to your app by clicking 'Back to Your-App' on top, you can notice that your app will be launching from the beginning, not from where you left. Try not using the breakpoint and you will notice the change.
So its not a crash actually.