Category Archives: Uncategorized

Refactoring: Face ID/Touch ID for iOS 13 Update

Back in February 2015, my article on Touch ID was published on raywenderlich.com. I was written in Swift for Xcode 8. Every year or so i would update the article as an author on the iOS Team. Here’s a link to the latest — How To Secure iOS User Data: The Keychain and Biometrics – Face ID or Touch ID. A few months ago, I had to update one of my own apps for iOS 13 with Apple’s biometric identification framework, Local Authentication. My app was also still supporting Objective-C so here’s follow up on what I had to change. As a bonus you can also take your user to Settings in case they have disabled

First thing is to add Local Authentication at the top of the Login view controller.

#import <LocalAuthentication/LocalAuthentication.h>

Next create an action for the Touch ID method:

- (IBAction)touchIDAction:(id)sender {
  LAContext *myContext = [[LAContext alloc] init];
  NSError *authError = nil;
  NSString *myLocalizedReasonString = @"Used for quick and secure access to the test app";
  //...
}

After that we need to check if the device can support biometrics with canEvaluatePolicy and have an error ready.

Inside the touchIDAction add:

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics 
error:&authError]) {
  // 1. successful steps
} else {
  // 2. Oops. There's a error!
}

Inside the canEvaluatePolicy, we’ll use evaluatePolicy:localizedReason:reply. The reply will have a block that either succeeds or fails with our error.

// 1. successful steps.
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
   if (success) {
      dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
 //Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
// using a Keychain utility method to get the email and password
NSString *passwordFound = [KeychainUtils getPasswordForUsername:self->emailTextField.text andServiceName:@"My_app" error:nil];
self->passwordTextField.text = passwordFound;
self->usingSecureID = true; // a Bool I added to keep track
 [self loginAction:nil];
  [NSLog showWithStatus:@"Logging_In"];
  });
});
} else {
    // User did not authenticate successfully, look at error and take appropriate action 
   //I'm using a showAlert method to bring up a UIAlertViewController
   [self showAlert: @"There was a problem verifying your identity." withTitle:@"Error!"];
    return;
 }
}];

What do we do if there is an error enabling Face ID/Touch ID? It could be because the user has disabled the feature. What’s new is that we can now take the user to your application settings — without a hack.

Initially you can pop up an alert to inform the user. Added to UIKit in iOS 8, UIApplicationOpenSettingsURLString lets you add a button to the alert that will take the user to your app in Settings, where they can enable Face ID/Touch ID.

// Could not evaluate policy; look at authError and present an appropriate message to user
    NSString *title = @"Error!";
    NSString *message = @"Your device cannot authenticate using TouchID.";
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
  // do we need to return animation?
                                                          }];
    // open your app in Settings
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    UIApplication *application = [UIApplication sharedApplication];
    NSString *settingTitle = @"Settings";
    UIAlertAction* settingsAction = [UIAlertAction actionWithTitle:settingTitle style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                             [application openURL:url  options:@{}
completionHandler:nil];
                                                           }];
    [alert addAction:settingsAction];
    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
    return;
 }

The whole method would look like this:

- (IBAction)touchIDAction:(id)sender {
  LAContext *myContext = [[LAContext alloc] init];
  NSError *authError = nil;
  NSString *myLocalizedReasonString = @"Used for quick and secure access to the test app";
  if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
// 1. successful steps
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
   if (success) {
      dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
 //Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
// using a Keychain utility method to get the email and password
NSString *passwordFound = [KeychainUtils getPasswordForUsername:self->emailTextField.text andServiceName:@"My_app" error:nil];
self->passwordTextField.text = passwordFound;
self->usingSecureID = true; // a Bool I added to keep track
 [self loginAction:nil];
  [NSLog showWithStatus:@"Logging_In"];
  });
});
} else {
    // User did not authenticate successfully, look at error and take appropriate action 
   //I'm using a showAlert method to bring up a UIAlertViewController
   [self showAlert: @"There was a problem verifying your identity." withTitle:@"Error!"];
    return;
 }
}];
} else {
// 2. Oops. There's a error!
// Could not evaluate policy; look at authError and present an appropriate message to user
    NSString *title = @"Error!";
    NSString *message = @"Your device cannot authenticate using TouchID.";
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault
                                                          handler:^(UIAlertAction * action) {
  // do we need to return animation?
                                                          }];
    // open your app in Settings
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    UIApplication *application = [UIApplication sharedApplication];
    NSString *settingTitle = @"Settings";
    UIAlertAction* settingsAction = [UIAlertAction actionWithTitle:settingTitle style:UIAlertActionStyleDefault
                                                           handler:^(UIAlertAction * action) {
                                                             [application openURL:url  options:@{}
completionHandler:nil];
                                                           }];
    [alert addAction:settingsAction];
    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
    return;
 }
}
}

iPhone needs MultiFinder

The iPhone needs the MultiFinder from System 6 to make it truly functional. Then we can truly say that it is the best cell phone for the 1990’s!

I don’t how many of you remember System 6 (or earlier) when Macs needed MultiFinder to run more than one application at a time. Ok, yes, System 6 had MultiFinder – but it crashed all the time and it didn’t become an “all the time app” until System 7 debuted. With System 6 you opened an application in the Finder – which would quit to get out of the way and free up memory – then you ran your application. If you wanted to go back and rename an folder or move things around you had to quit the running application so you could return to the Finder. The same was true if you wanted to open another application – you quit to return to the Finder and then launch the second application.

How is this any different than iPhone 2.1? You can open an app in Springboard but if you want to do anything else you press “Home” to go back to Springboard then open the other application. If you want to email a picture the iPhone quits the Photos app and launches Mail and creates a new message with the photo attached. 

When I ran System 6, I had an application called Disktop which was a “Desk Accessory” and I could run it with a running app. I could rename a folder, move or copy a file from one place to another and even switch to another application – without going to the Finder. Hmmm.

So it begs the question: When is System 7 coming out for the iPhone or when is someone going to – or be allowed to – develop DiskTop for the iPhone?

Anyone?

Anyone?

Apple?

Anyone?

Run and get iPhone 2.01

As you might have guessed, I’ve been using an iPhone for about 6 months or so. I was really disappointed with the speed of the new iPhone 3G. For instance my Contacts app would take 45 seconds to load. After upgrading the bug fixes in 2.01 update  – the Contacts app loads in less than 10 seconds.

I highly recommend it!

Looks like Canadian iPhones are in short supply

It’s no surprise that just as Rogers reduces it’s data plan cost – Apple short ships iPhones to Canada. Rogers just announced that it would offer 6GB/mo for $30 as a special promotion  – while at that exact moment (or perhaps earlier) the iPhones arrived at the Rogers dealers. Only 20% or less of what was actually ordered arrived.

We where supposed to get some phones set aside for us – now it looks like only new activations early on Friday morning will get the iPhone. Does any one know where I can get a Nintendo Wii?

Rogers’ iPhone 3G data plan reality check!!!

If you are an existing Rogers customer and you have are eligible for an upgrade you will get your upgrade to an iPhone on Friday July 11 (depending on stock of course). It is the same as any other phone upgrade.

For instance: I currently have a voice plan and a data plan. I have agreed to the 3 year contract so my 8GB iPhone 3G will cost me $224.00 with a $50 mail-rebate (remember this is Rogers!) So it will cost me $174.00 – with no change in my voice plan or data plan!!! I pay Rogers a lot of money every month and I’m a “preferred client” and according to my source, “Rogers may be thick but they’re not stupid.”

On the Rogers web site it says:

Already an existing customer?
If you are an existing customer, you may keep your existing voice service plan and add a separate data plan. To check your upgrade eligibility, please call 1 888 ROGERS1 or visit your nearest Rogers retail location.

The plans that are posted are for NEW activations and you can mix and match once you’ve got the iPhone.

With respect to the 3 year commitment – the iPhone is a GSM phone so you can only use it with Rogers – where else are you going to go? To get out of the commitment it will cost you $20/month remaining on your contract up to a $400 maximum. Rogers is also subsidizing the cost of the iPhone by at least $450 – so it would cost you a bundle to buy the iPhone unlocked.

 

Rogers threat to unlocked iPhones

Rogers may be prepared to disable unlocked iPhones in advance of July 11 launch in Canada.

Rumor has it that the prices will be $199 and $299 each with a three year contract. There’ s no word on what happens if you are not currently eligible for an upgrade or what Rogers plans to do for the 40,000+ current iPhone users. It would seem fitting that they would destroy the relationship with current unofficial installed base. An installed base of users who are ultimately championing the platform in Canada.

Rogers is subsidizing the cost of the iPhone in Canada – which will cost the dealers about $500 a piece. And there is no confirmed data plan packages yet. There will not be any unlimited packages as AT&T and Tmobile have already lost billions with the unlimited packages.