I am implementing biometric login into my iOS app in Swift, and I have use this API :
var permissions = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,error: &failureReason)
to check whether biometric is supported. It is working normal if Face ID permission was allowed. However, after uninstall and rerun from XCode, with calling canEvaluatePolicy without any permission prompt, it still return the supported biometric in response closure. I was wondering what is the different between before allowed permission and after allowed permission.
May i know any solution/ way to know the permission state for this, thank you.
When you make a call such as:
var permissions = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &failureReason)
then iOS will run through the following checks:
Does the device have Face ID capability?
Yes: Is Face ID setup on the device?
Yes: Is the app's Face ID permission enabled?
Yes: return true
No: Fallback to device passcode
No: Fallback to device passcode
No: Fallback to Touch ID
Does the device have Touch ID capability?
Yes: Is Touch ID setup on the device?
Yes: Is the app's Touch ID permission enabled?
Yes: return true
No: Fallback to device passcode
No: Fallback to device passcode
No: Fallback to device passcode
Does the device have a passcode setup?
Yes: return true
No: return false (no Face ID, no Touch ID, no passcode)
When you call evaluatePolicy the first time after a fresh install of the app, iOS will prompt the user whether it should allow Face ID (if the device supports Face ID and Face ID has been setup on the device) and it will show the app-provided reason string entered into Info.plist for the "Privacy - Face ID Usage Description".
The user selection affects the app's Face ID permission. Once the user makes their choice, the evaluation goes through the same logic as shown above. Depending on the result, iOS will either authenticate via Face ID, Touch ID, or passcode.
If you delete an app and then do a fresh install via Xcode then the whole process starts over and the user will be prompted again on first use.
The biometryType value of LAContext is independent of the app's permission. It's what the device supports which is either Face ID, Touch ID, or neither. The value allows your app to use appropriate messaging in your user interface.
For example, you can use the value to label a switch as either "Enable Face ID Login" or "Enable Touch ID Login".
The app's permission ultimately will determine if either Face ID or Touch ID (based on the capabilities of the device) will end up falling back to just asking for the passcode.
Related
On iOS if you never asked user for notification permissions then this option will not appear in device settings for your application.
I wonder is there a way make this option appear in the settings in 'Denied' state without prompting a notificatoin permissions request so user can enable this option later by himself?
Thanks
I would say, that is not permitted. If it were possible to change authorizationStatus programmatically, or set it to some default state, then you would able to set it to 'authorized' state too, without asking user about it.
As per the WWDC video, https://developer.apple.com/videos/play/wwdc2019/705/, when you ask for "AlwaysAuthorization" permission you will see only "When In Use, Once and Don't allow". Even if you tap on "When In Use", the delegate call back will come back as kCLAuthorizationStatusAuthorizedAlways. This is working as expected. But is there a way to find out that the request is still provisional or actually-always-allow?
There is no enum associated to this permission. The only allowed enums are:
kCLAuthorizationStatusNotDetermined, kCLAuthorizationStatusDenied, kCLAuthorizationStatusAuthorizedAlways, kCLAuthorizationStatusAuthorizedWhenInUse
Because I want to show an alert as soon as user grants the "While In Use" permission, to tell them that the app will only work if you provide "Always Allow" via system preferences and I can navigate them to the system settings page of my app via a tap, just like how Zenly is doing it: https://www.macrumors.com/2019/08/16/app-developers-tracking-restrictions-ios-13/
You can check if you're getting location updates in the background for more than 10 seconds after the application gets in the background. If yes, then you have the permanent Allow Always. If not, then you have the provisional Allow Always (or any other authorization that you can check explicitly).
Problem Description: I have a main App which is widely used and handles touch id based login with a registration flow.
At the time of touch id registration within my app, we store the evaluatedDomainState in the app user defaults.
When the customer uses Touch ID/ face ID to login, we check 2 things on the device before invoking server
1. Touch id verification
2. Comparing evaluatedDomainState for identifying fingerprint changes on device. If evaluatedDomainState doesn't match, we ask the customer to re-register touch id.
We are enhancing this app by adding an keyboard extension. The keyboard will use the same login flow and user defaults.
In the login process via keyboard,
point 1 is successful. Point 2 fails from keyboard extension although successful from main app.
Here is the code.
self.touchIDHash = self.context.evaluatedPolicyDomainState;
NSData *savedHash = [[NSUserDefaults standardUserDefaults] objectForKey:#"TouchIdHash"];
BOOL fingerPrintChanged = savedHash && ![savedHash isEqualToData:self.touchIDHash];
fingerPrintChanged is always true from keyboard extension login and false from main app login.
Any inputs to make this work will be much helpful.
Due to fingerPrint is setup in your container APP,
verify it in container app then navigate back to extension, maybe it's workaround for you.
This is not a dupe of: Can we test Face ID in simulator?
I want to know how to test when a user accepts the Face ID alert below that reads "Do you want to allow "app" to use Face ID" and then decides to disable Face ID for an app in the simulator.
When you run context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) it will return false and an authError as Optional<NSError>:
Error Domain=com.apple.LocalAuthentication Code=-6 "User has denied
the use of biometry for this app." UserInfo=
{NSLocalizedDescription=User has denied the use of biometry for this app.}
Use error.code for your tests, in this case it is -6, you can find more about LAError.Code codes in Apple docs
It is actually interesting topic: apparently, if a user did not give a permission for Face ID - only way to get it on a simulator is to reinstall the app. There is a discussion on Apple forum about it.
Some background information
I'm using the silentPush feature (didReceiveRemoteNotification) to keep the iOS app synced with other platforms and my backend.
So just to be sure, that the user enabled Background Refresh in his iOS settings, I'm checking the devices settings with the following code:
// Check Background Refresh
switch UIApplication.shared.backgroundRefreshStatus {
case .available:
// iOS background refresh is enabled in iOS settings
// -> No need to ask user for permission
break
case .denied:
// iOS background refresh is disabled in iOS settings
// here is my code to notify user to enable his background refresh iOS settings
break
}
According to the Apple documentation (https://developer.apple.com/documentation/uikit/uiapplication/1622994-backgroundrefreshstatus) there is a property backgroundRefreshStatus, which indicates, if the user has enabled the background services -> This is exactly the code I implemented above.
This property reflects whether the app can be launched into the background to handle background behaviors, such as processing background location updates and performing background fetches. If your app relies on being launched into the background to perform tasks, you can use the value of this property to determine if doing so is possible and to warn the user if it is not. Do not warn the user if the value of this property is set to restricted; a restricted user does not have the ability to enable multitasking for the app.
The following phrase is now interesting in my case
you can use the value of this property to determine if doing so is possible and to warn the user if it is not
I had a look into the iOS background refresh system settings and found 3 possible values, which the user can set:
Aus (Off)
WLAN (WiFi)
WLAN & Mobile Daten (WiFi & Cellular / Mobile Data)
Now my question:
I would like to ask the user for background service permission, if the settings are either on off or only on Wifi (see red rectangle). According to Apples documentation, there is only the possibility to check the general settings -> either on or off. Is there any possibility to check it like I mentioned it on the screenshot?