iOS. How to know if faceid prompt is presented? - swift

Is there any way (in swift) to know if the system faceId prompt is being presented? I can't see any event, notification or delegate method. I should avoid the presentation of a view triggered by an asynchronous event in case the app is trying to authenticate the user.

There is no specific event, notification, or delegate method in Swift that allows you to determine if the system Face ID prompt is being presented. However, you can use the LAContext class to check the availability and state of Face ID on the device, and then use that information to determine if the prompt is likely to be displayed.
You can use the canEvaluatePolicy method of LAContext to check if the device supports Face ID and if the user has configured it.
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
//FaceID is available
}
Then you can use the evaluatePolicy method to check if the user already authenticated recently or not.
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Log in with Face ID") { success, error in
if success {
// Face ID authentication was successful
} else {
// Face ID authentication failed
}
}
It's important to notice that you should avoid presenting a view triggered by an asynchronous event in case the app is trying to authenticate the user.

Related

KVO observe AVAudioSession's recordPermission doesn't work

My application uses the microphone's permission, which is requested in another framework, and in the main application, I wasn't able to observe when microphone permission changed. I tried using KVO's observer but the application doesn't receive any events when the microphone permission is changed.
private var permissionStatusObserver: NSKeyValueObservation?
private func observeRecordPermissionChange() {
    do {
      try audioSession.setActive(true)
      permissionStatusObserver = audioSession.observe(\.recordPermission) { [weak self] _, recordPermissions in
        print("recordPermission changed")
      }
    } catch {
      print("active audio failed \(error.localizedDescription)")
    }
  }
Not going to work.
There are 3 possibilities:
App never asked user for permissions yet. In this case you should present permissions to the user and wait for their response. In this case you need to define requestRecordPermission callback instead of listening to KVO.
App previously asked user for permissions, and user granted them. In this case you can proceed working with microphone.
App previously asked user for permissions, and user denied. Typically in this case apps show the message telling user to go to settings. And user needs to go to Settings -> Privacy -> Microphone and reenable the permissions, at which point the app will be restarted. So nothing to listen to as #cora mentioned.
Something like this:
switch AVAudioSession.sharedInstance().recordPermission {
case .granted:
// start recording
case .denied:
// Present message to user indicating that recording
// can't be performed until they change their preference
// under Settings -> Privacy -> Microphone
case . undetermined:
// Ask for permissions as explained below.
}
Or you can always ask for permissions like Apple tells us to:
// Request permission to record.
AVAudioSession.sharedInstance().requestRecordPermission { granted in
if granted {
// The user granted access. Present recording interface.
} else {
// Present message to user indicating that recording
// can't be performed until they change their preference
// under Settings -> Privacy -> Microphone
}
}
This is safe to do even if the permission is already granted (the callback will be back very quickly).

Can you validate whether a user has been recently authenticated on Firebase (Swift)?

Is there a way to check if a user has recently authenticated on Firebase to avoid this message when trying to delete a user: "This operation is sensitive and requires recent authentication. Log in again before retrying this request."
I have been playing around trying to compare lastSignInDate (below) to current time but there seems to be a large margin of error on this which can cause problems:
firebase.auth().currentUser.metadata.lastSignInTime
Are there any functions that can return a simple boolean as to whether a user has recently authenticated so the user.delete() function will work properly?
Thanks so much!
The best way to do this is by checking if the response has an error, like so:
let user = Auth.auth().currentUser
user.delete { error in
if let error = error {
if (error.code == "auth/requires-recent-login") {
// The user's credentials are too old. Prompt Login screen.
}
} else {
// ...
}
}
According to Firebase Documentation, There's no other approach to this other than comparing the current date with firebase.auth().currentUser.metadata.lastSignInDate (Only if you have the Admin SDK on your app, but you most probably do not need that for enabling a user to delete themselves).

Accept notifications later than the first launch

In my application, user can use notifications sent from the app. At first launch, there is an alert with refuse or allow notifications made in the appdelegate.
If I accept notifications, all is OK.
I made a screen / viewcontroller in which user can accept or no notification with a switch. If user refused notifications at first launch, how can I access to the controls in appdelegate like if I was at first launch ?
Thanks
According to Apple's Developer Documentation and this answer (for clarification), push notifications permissions can only be requested once. iOS stores the user's decision after it has been made and there is no way to request again. Do prepare for the fact that some users might not want notifications, you can always check the status of the permission your app received:
let center = UNUserNotificationCenter.current()
center.getNotificationSettings { settings in
guard settings.authorizationStatus == .authorized else { return }
if settings.alertSetting == .enabled {
// Schedule an alert-only notification.
} else {
// Schedule a notification with a badge and sound.
}
}

CloudKit Login Missing Acount

When a user is not signed to Game Center a UI pops up in the app. If a user is logged in to iCloud the app gets the cloudkit user ID. However, I do not understand what happens if the user is not logged in to iCLoud at all. As far as I can tell the app does not promt the user. Is there a way to do this?
Thanks,
Henry
You have to test for that yourself and take the appropriate actions. For testing the status you can use the code below. At the line where the account status is logged you could show an alert where you point the user to the settings app.
container = CKContainer.defaultContainer()
database = container.publicCloudDatabase
container.accountStatusWithCompletionHandler({status, error in
if error != nil {
NSLog("Error: Initialising EVCloudKitDao - accountStatusWithCompletionHandler.\n\(error!.description)")
} else {
self.accountStatus = status
}
NSLog("Account status = \(status.hashValue) (0=CouldNotDetermine/1=Available/2=Restricted/3=NoAccount)")
})
NSLog("Container identifier = \(container.containerIdentifier)")
The code above is a snippet from EVCloudKitDao

APNS notification does not work when app is not running or background

I'm using pyapns to send notification to iPhone.
receiving notification when the app is running was success.
but, when app is not running or app is on background, it can't receive notification.
is it related with URL identifier or scheme? if not, what is the problem..?
Did you get called in
- (void)application:didReceiveRemoteNotification:
while you were in the app?
the problem from notification msg.
among the notify function args, there is notifications list arg.
note that, when you make this parameter, a dictionary of this list should contain below. so that the application can do alert reaction.
thePayLoad = {
'aps': {
'alert':'this option should be contained if you want to see the alert msg',
'sound':'k1DiveAlarm.caf',
'badge':42
},
'test_data': { 'foo': 'bar' }
}
In my case, I just sent msg not containing above. and in didReceiveRemoteNotification function, I made alert msg. but msg not containing alert information. so the device couldn't react.