I want ask permission in the second time in my home controller, can I do it programmatically?
I mean that the user disable it in the first time and I want to allow him another option to get notification.
You´re not allowed to do that. The notification popup will prompt the first time the user opens the application. What you can do is check if the user hasn´t allowed this. Then you could open the settings page (which basically is what you can do in this case):
let isRegisteredForRemoteNotifications = UIApplication.shared.isRegisteredForRemoteNotifications
if !isRegisteredForRemoteNotifications {
UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)
}
Swift 5.x
let isRegisteredForRemoteNotifications = UIApplication.shared.isRegisteredForRemoteNotifications
if !isRegisteredForRemoteNotifications {
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
This is actually not possible. You only get one shot to prompt them for permissions. This is why most apps will present a custom view to explain why a certain permission is needed. And if the user clicks "yes", then they launch the actual permission alert.
If they have already declined the permission, you'll need to check if app has certain permission and prompt them to go into settings to activate what is needed.
Here's an example of how you can check if they have given permission.
You cannot ask for a permission after the user has chosen to allow it or not. What you can do is check if the permission was not allowed and redirect the user to the app's settings.
How you check for the permission's authorization status depends on the type of service you want to authorize. You can the redirect the user to the settings with the following code:
Swift
UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)
Objective C
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:#{} completionHandler:nil];
You cannot show the standard popup after the user enabled or refused notifications. In such situation, it is quite common to show an alertController that informs the user about this situation and provide her with a button that navigates to settings:
let alert = UIAlertController(title: "Unable to use notifications",
message: "To enable notifications, go to Settings and enable notifications for this app.",
preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(okAction)
let settingsAction = UIAlertAction(title: "Settings", style: .default, handler: { _ in
// Take the user to Settings app to possibly change permission.
guard let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) else { return }
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
// Finished opening URL
})
}
})
alert.addAction(settingsAction)
self.present(alert, animated: true, completion: nil)
The code is inspired by a similar example for camera access by Apple engineers.
In such scenario, you can show an alert which navigates user to settings
let alert = UIAlertController(title: "Allow notification Access", message: "Allow notification access in your device settings.", preferredStyle: UIAlertController.Style.alert)
// Button to Open Settings
alert.addAction(UIAlertAction(title: "Settings", style: UIAlertAction.Style.default, handler: { action in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)")
})
}
}))
alert.addAction(UIAlertAction(title: "Close", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
Related
After requesting face id permission for an application , we get the apple alert that allow the user to grant or deny the use of this technologie .
My question is :
If the user deny the use of face id , is there any solution to request it again without uninstalling the application .
You can request it again, but not in the same way as the first time. What you can do is when you request for Face ID, you should check on the authorization status, which can either be notDetermined, authorized, denied or restricted.
In the case that it is notDetermined you can bring up the request access that you are already doing, and if it is denied you can give the user the option to go to Settings -> YourAppName to give FaceID access to your app.
Here is an example taken from the following answer: Reference Question
It is for Camera Access but you should be able to apply it to FaceID pretty simply.
#IBAction func goToCamera()
{
let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
switch (status) {
case .authorized:
self.popCamera()
case .notDetermined:
AVCaptureDevice.requestAccess(for: AVMediaType.video) { (granted) in
if (granted) {
self.popCamera()
} else {
self.camDenied()
}
}
case .denied:
self.camDenied()
case .restricted:
let alert = UIAlertController(title: "Restricted",
message: "You've been restricted from using the camera on this device. Without camera access this feature won't work. Please contact the device owner so they can give you access.",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
}
}
Then in the camDenied function:
func camDenied() {
DispatchQueue.main.async {
var alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Close this app.\n\n2. Open the Settings app.\n\n3. Scroll to the bottom and select this app in the list.\n\n4. Turn the Camera on.\n\n5. Open this app and try again."
var alertButton = "OK"
var goAction = UIAlertAction(title: alertButton, style: .default, handler: nil)
if UIApplication.shared.canOpenURL(URL(string: UIApplicationOpenSettingsURLString)!) {
alertText = "It looks like your privacy settings are preventing us from accessing your camera to do barcode scanning. You can fix this by doing the following:\n\n1. Touch the Go button below to open the Settings app.\n\n2. Turn the Camera on.\n\n3. Open this app and try again."
alertButton = "Go"
goAction = UIAlertAction(title: alertButton, style: .default, handler: {(alert: UIAlertAction!) -> Void in
UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)
})
}
let alert = UIAlertController(title: "Error", message: alertText, preferredStyle: .alert)
alert.addAction(goAction)
self.present(alert, animated: true, completion: nil)
}
}
I have a button that when tap on it I have to check microphone permission.
For this reason I done this:
public func askMicrophoneAuthorization()
{
recordingSession = AVAudioSession.sharedInstance()
recordingSession.requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed
{
self.goToNextStep()
} else
{
self.denied()
}
}
}
}
my problem is this: when I tap on button and askMicrophoneAuthorization method is called, if its the first time that I ask the permission, the microphone system alert, with text inserted in plist file, shows and I can denied or not the permission. If I deny the permission and then I re-tap on button method self.denied() is executed and I dont see the microphone system alert.
Is it possibile to re-show the system-alert?
It's not possible to show the system alert if the user has already denied.
The best you can do is to check the permission and if they're denied show an alert with a button that opens the app settings.
func askPermissionIfNeeded() {
switch AVAudioSession.sharedInstance().recordPermission {
case undetermined:
askMicrophoneAuthorization()
case denied:
let alert = UIAlertController(title: "Error", message: "Please allow microphone usage from settings", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Open settings", style: .default, handler: { action in
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
case granted:
goToNextStep()
}
}
I have a really simple request that is apparently beyond me. All I want to do is allow the user to select an image from the camera roll and then store a ‘reference’ to that image in my app. I can then load the image from the camera roll when I need it.
I do not want to copy the image and save it elsewhere because I feel that it would be wasting space on the phone. I realise that the user could delete the image from their camera roll, but in the case of this app it does not matter. I will simply check for nil just before displaying the image. It will not affect the app functionality.
I can present the ImagePickerController and I am happily getting a UIImage by means of:
info[UIImagePickerControllerOriginalImage]
What I would like to do is use:
info[UIImagePickerControllerReferenceURL]
However, this is being removed and is no longer supported. I have therefore lost several hours of my life looking into PHAsset. This seems fine for retrieval, providing I have something to search for. I cannot seem to write a simple app that gets an image via the UIImagePickerController and then allows me to save a reference/URL/uniqueID etc. that I can then use via some other method to get the image back again.
I am more than happy to be laughed at, providing the person laughing shows me how silly I have been…
All help greatly appreciated.
I needed to check the PHPhotoLibrary.authorizationStatus() programatically as the app was silently failing this. Adding the following to AppDelegate.swift resolved the issue (you need to import Photos):
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
photoLibraryAvailabilityCheck()
}
//MARK:- PHOTO LIBRARY ACCESS CHECK
func photoLibraryAvailabilityCheck()
{
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized
{
}
else
{
PHPhotoLibrary.requestAuthorization(requestAuthorizationHandler)
}
}
func requestAuthorizationHandler(status: PHAuthorizationStatus)
{
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized
{
}
else
{
alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
}
}
//MARK:- CAMERA & GALLERY NOT ALLOWING ACCESS - ALERT
func alertToEncourageCameraAccessWhenApplicationStarts()
{
//Camera not available - Alert
let internetUnavailableAlertController = UIAlertController (title: "Camera Unavailable", message: "Please check to see if it is disconnected or in use by another application", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .destructive) { (_) -> Void in
let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
DispatchQueue.main.async {
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil) //(url as URL)
}
}
}
let cancelAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
internetUnavailableAlertController .addAction(settingsAction)
internetUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.present(internetUnavailableAlertController , animated: true, completion: nil)
}
func alertToEncouragePhotoLibraryAccessWhenApplicationStarts()
{
//Photo Library not available - Alert
let cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .destructive) { (_) -> Void in
let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}
}
let cancelAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
cameraUnavailableAlertController .addAction(settingsAction)
cameraUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.present(cameraUnavailableAlertController , animated: true, completion: nil)
}
if user denied access for camera or microphone i'm asking for permission when call received to app with custom alert
func showAlertForDeniedPermissions(message:String) {
if let settingsUrl = URL(string: UIApplicationOpenSettingsURLString) {
let alert = UIAlertController(title: "Access Needed!", message: message, preferredStyle: UIAlertControllerStyle.alert)
let okay = UIAlertAction(title: "OK", style: .default, handler: { (action) in
// If camera or library settings are disabled then open general settings
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil)
}
})
alert.addAction(okay)
self.present(alert, animated: true, completion: nil)
}
}
If user taps okay the app settings will be opened and in background the call will be continued.
Here if user enables permission for camera or microphone the call gets disconnected and app launches again
when i debug it shows
Message from debugger: Terminated due to signal 9
If the user did not allow access to photo album at the start, I will prompt with a pop up with Cancel and Settings to choose from. If he chooses settings, it will bring him to settings page where he can enable camera and photo Library for the app. However, as soon as the user toggles the camera or photo library switch in settings, my app crashes with "Message from debugger: Terminated due to signal 9" printout. Below is the code for my popup
#IBAction func cameraBarBtnPress(sender: AnyObject) {
let photoAuthStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthStatus {
case .Authorized:
presentFusumaCameraVC()
case .Denied, .Restricted :
showNeedPhotoAlbumAccessPopup()
case .NotDetermined:
PHPhotoLibrary.requestAuthorization({ (authStatus: PHAuthorizationStatus) in
switch authStatus {
case .Authorized:
self.presentFusumaCameraVC()
case .Denied, .Restricted :
self.showNeedPhotoAlbumAccessPopup()
case .NotDetermined:
print("Shouldnt get to here")
}
})
}
}
func showNeedPhotoAlbumAccessPopup() {
let alertController = UIAlertController(title: "Enable Photo Album Access", message: "", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
let settingsAction = UIAlertAction(title: "Settings", style: .Default, handler: { (action: UIAlertAction) in
let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.sharedApplication().openURL(url)
}
})
alertController.addAction(settingsAction)
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
What would be the correct way to handle this so that the user can go back to the app and begin selecting the photos after toggling the switch?
Apple's documentation says the following:
If permissions changes, app is quit
Background task expiration handler is called, if registered
iOS then kills the application
Haven't seen a way around so far.