UIImagePickerController and info.plist issue - ios

In my project I tried to add two things:
A camera source for a person's avatar.
add permission for the camera and photo library access in the info.plist file.
But when I tried to test my app in a real device the app doesn’t show any permission, and when I chose the camera the app exit without error message in the log console?
For the info.plist I use this two line:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) camera use</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) photo use</string>
And add a photo I use this code:
#objc func addNewPerson(){
let picker = UIImagePickerController()
let ac = UIAlertController(title: "Choose image", message: nil, preferredStyle: .actionSheet)
let camera = UIAlertAction(title: "Camera", style: .default){
[weak self] _ in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.allowsEditing = false
picker.delegate = self
picker.sourceType = .camera
self?.present(picker,animated: true)
}else{
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self?.present(alert, animated: true, completion: nil)
}
}
ac.addAction(camera)
let galerie = UIAlertAction(title: "Photo library", style: .default){
[weak self] _ in
picker.allowsEditing = true
picker.delegate = self
self?.present(picker,animated: true)
}
ac.addAction(galerie)
ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(ac,animated: true)
}
Thank you.

in your addNewPerson() method before showing the alert you should check if the user already granted access to his Camera you can do that by :
if AVCaptureDevice.AVCaptureDevice.authorizationStatus(AVMediaTypeVideo) == AVAuthorizationStatus.Authorized {
// Already Authorized
} else {
AVCaptureDevice. requestAccess(AVMediaTypeVideo, completionHandler: { (granted: Bool) -> Void in
if granted == true {
// User granted
} else {
// User rejected
}
})
}
and before that make sure you added

Just to mention, in iOS 11 camera access is not required to use the UIImagePicker
Here is copy-pasted fragment from rickster's post.
in iOS 11, UIImagePickerController runs as a separate process from your app. That means:
Your app can't see the user's whole Photos library — it gets read-only access just for whichever asset(s) the user chooses in the image picker.
Because of (1), your app doesn't need the standard privacy authorization for Photos library access. The user explicitly chooses a
specific asset (or multiple) for use in your app, which means the user is granting your app permission to read the asset(s) in question.

Related

Request iOS face id permission again when it was denied first time by user

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)
}
}

Not able to show the alert if user denied the camera access

If user dennied the camera access, i am showing one alert with cancel and setting button to show it. But the code is not working.
#IBAction func ProfileImageButton(_ sender: UIButton) {
print("profile image Button is pressed")
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
profileimgbool = true
let actionSheet = UIAlertController(title: "Photo Source", message: "choose a Source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: {(action:UIAlertAction) in imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}
func checkCameraPermission() {
let cameraMediaType = AVMediaType.video
AVCaptureDevice.requestAccess(for: cameraMediaType) { granted in
if granted {
//Do operation
print("Granted access for camera")
// self.setCamera()
} else {
self.noCameraFound()
print("Denied access for camera ")
}
}
}
func noCameraFound(){
let alert = UIAlertController(title: "CallDoc", message: "Please allow camera access in phone settings", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Back", style: UIAlertActionStyle.cancel, handler: {(action:UIAlertAction) in
}));
alert.addAction(UIAlertAction(title: "Open setting", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction) in
UIApplication.shared.open(NSURL(string:UIApplicationOpenSettingsURLString)! as URL, options: [:], completionHandler: nil)
}));
self.present(alert, animated: true, completion: nil)
}
in my above code my method was checkCameraPermission where i will call this to show alert. I needs to show when user click camera, and when if user denied that black screen will show instead of camera. There i need to show that alert pop up.
Where i can call this checkCameraPermission method to show my popup ?.
Any idea ?
for reference purpose I taken the answer from this tutorial.
step 1
add the avfoundation framework in your project
import AVFoundation
step 2
dont forget to Set Camera Usage Description in Info.plist
When you request permission to use the device’s camera, a short message will appear in the default iOS system dialog. You customize this message by adding the Privacy - Camera Usage Description key to your Info.plist file.
step 3
on your image profile change button action verify the permission, etc.
#IBAction func ProfileImageButton(_ sender: UIButton) {
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
switch cameraAuthorizationStatus {
case .notDetermined: requestCameraPermission()
case .authorized: presentCamera()
case .restricted, .denied: alertCameraAccessNeeded()
}
}
based on the above action the condition will satisfy,
If the user has never responded to a request to access his/her camera, you need to prompt with the iOS system alert to request permission:
func requestCameraPermission() {
AVCaptureDevice.requestAccess(for: .video, completionHandler: {accessGranted in
guard accessGranted == true else { return }
self.presentCamera()
})
}
there after the camera access will continue
func presentCamera() {
let photoPicker = UIImagePickerController()
photoPicker.sourceType = .camera
photoPicker.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
self.present(photoPicker, animated: true, completion: nil)
}
To use the image that the camera captured, you need to set up your view controller to adhere to and implement couple of delegate protocols:
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
// ...
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let photo = info[UIImagePickerControllerOriginalImage] as! UIImage
// do something with the photo... set to UIImageView, save it, etc.
dismiss(animated: true, completion: nil)
}
If camera access has been denied or restricted, you can alert the user and direct them to the Settings app to make the appropriate permissions adjustment:
func alertCameraAccessNeeded() {
let settingsAppURL = URL(string: UIApplicationOpenSettingsURLString)!
let alert = UIAlertController(
title: "Need Camera Access",
message: "Camera access is required to make full use of this app.",
preferredStyle: UIAlertControllerStyle.alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel, handler: { (alert) -> Void in
UIApplication.shared.open(settingsAppURL, options: [:], completionHandler: nil)
}))
present(alert, animated: true, completion: nil)
}

Issue with access camera after denied the camera

In my application I used camera implementation in that if the user enter very first means that time they choose allow means they have to access camera and photo library in entire application, if it is chosen denied means the user cannot access the camera so that time we need to change camera and photo library in settings.After that we have to access the camera in my case it is not working properly, anyone helps me, much appreciated.
You can check first whether camera permission is allowed or not. If not then you can navigate to settings screen & ask user for permission.
override func viewDidLoad() {
super.viewDidLoad()
checkCameraPermission()
}
func checkCameraPermission() {
let cameraMediaType = AVMediaTypeVideo
AVCaptureDevice.requestAccess(forMediaType: cameraMediaType) { granted in
if granted {
//Do operation
print("Granted access for camera")
self.setCamera()
} else {
self.noCameraFound()
print("Denied access for camera ")
}
}
}
func noCameraFound(){
let alert = UIAlertController(title: "AppName", message: "Please allow camera access in phone settings", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Back", style: UIAlertActionStyle.cancel, handler: {(action:UIAlertAction) in
}));
alert.addAction(UIAlertAction(title: "Open setting ", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction) in
UIApplication.shared.open(NSURL(string:UIApplicationOpenSettingsURLString)! as URL, options: [:], completionHandler: nil)
}));
self.present(alert, animated: true, completion: nil)
}

Request Camera Permission Dialog Priming (Prime Permissions) in iOS

What is the most effective way to prompt a User to provide access to the Camera (or other feature), while ensuring the best experience?
When accessing the Camera, iOS must ask the Customer permission to allow access. As we all know, if the Customer says "No" but then changes their mind, there is no way to reverse this decision from within your App. They must go to Settings and follow a number of steps to re-enable access, namely:
Settings -> Privacy -> Camera -> [Your App] -> turn switch on
Permission Priming is an effective way to avoid a situation where your Customer might deny access to a key feature of your app.
On iOS an App is only allowed to trigger the default system permission once per feature. Permission priming is when an app "primes" the Customer with an alert that mimics a system permission.
The benefit to doing this is so that if the Customer opts-out (selects Cancel), the App is still able to ask again in future, until they say yes — at which time the actual system permission is displayed and the Customer is statistically less likely to then change their mind and enter into the negative work flow.
Furthermore, since cameraSelected() performs this workflow, if the user declines, but then at some future point does change their settings, the App will immediately reflect the new permissions without further input (ie. the User could switch to Settings, change permissions, and then switch back to the App).
Here is some Swift 3 code to implement this feature:
[UPDATE: Included is a solution to open a deep-link to Settings where the User can enable camera access, if they have previously denied it.]
[UPDATE 2: Added sample lines for Analytics implementation.]
func cameraSelected() {
// First we check if the device has a camera (otherwise will crash in Simulator - also, some iPod touch models do not have a camera).
if let deviceHasCamera = UIImagePickerController.isSourceTypeAvailable(.camera) {
let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch authStatus {
case .authorized:
showCameraPicker()
case .denied:
alertPromptToAllowCameraAccessViaSettings()
case .notDetermined:
permissionPrimeCameraAccess()
default:
permissionPrimeCameraAccess()
}
} else {
let alertController = UIAlertController(title: "Error", message: "Device has no camera", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { (alert) in
Analytics.track(event: .permissionsPrimeCameraNoCamera)
})
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
}
func alertPromptToAllowCameraAccessViaSettings() {
let alert = UIAlertController(title: "\"<Your App>\" Would Like To Access the Camera", message: "Please grant permission to use the Camera so that you can <customer benefit>.", preferredStyle: .alert )
alert.addAction(UIAlertAction(title: "Open Settings", style: .cancel) { alert in
Analytics.track(event: .permissionsPrimeCameraOpenSettings)
if let appSettingsURL = NSURL(string: UIApplicationOpenSettingsURLString) {
UIApplication.shared.openURL(appSettingsURL)
}
})
present(alert, animated: true, completion: nil)
}
func permissionPrimeCameraAccess() {
let alert = UIAlertController( title: "\"<Your App>\" Would Like To Access the Camera", message: "<Your App> would like to access your Camera so that you can <customer benefit>.", preferredStyle: .alert )
let allowAction = UIAlertAction(title: "Allow", style: .default, handler: { (alert) -> Void in
Analytics.track(event: .permissionsPrimeCameraAccepted)
if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { [weak self] granted in
DispatchQueue.main.async {
self?.cameraSelected() // try again
}
})
}
})
alert.addAction(allowAction)
let declineAction = UIAlertAction(title: "Not Now", style: .cancel) { (alert) in
Analytics.track(event: .permissionsPrimeCameraCancelled)
}
alert.addAction(declineAction)
present(alert, animated: true, completion: nil)
}
func showCameraPicker() {
let picker = UIImagePickerController()
picker.delegate = self
picker.modalPresentationStyle = UIModalPresentationStyle.currentContext
picker.allowsEditing = false
picker.sourceType = UIImagePickerControllerSourceType.camera
present(picker, animated: true, completion: nil)
}
Suppose we have two buttons (one for picking picture from library another from camera) with tags 1,2 that are linked to action:
import UIKit
import AVFoundation
#IBAction func changeImage(sender: UIButton) {
let picker = UIImagePickerController()
if sender.tag == 2 { // tag = 2 for camera button. tag = 1 for image picker
guard UIImagePickerController.isSourceTypeAvailable(.camera) else { return }
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
switch cameraAuthorizationStatus {
case .notDetermined:
requestCameraPermission()
return
case .authorized:
break
case .restricted, .denied:
alertCameraAccessNeeded()
return
#unknown default:
return
}
picker.sourceType = .camera
}
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
private func requestCameraPermission() {
AVCaptureDevice.requestAccess(for: .video) { [weak self] accessGranted in
if !accessGranted {
DispatchQueue.main.async {
self?.alertCameraAccessNeeded()
}
}
}
}
private func alertCameraAccessNeeded() {
guard let settingsAppURL = URL(string: UIApplication.openSettingsURLString),
UIApplication.shared.canOpenURL(settingsAppURL) else { return } // This should never happen
let alert = UIAlertController(
title: "Need Camera Access",
message: "Camera access is required to take pictures of item.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "Cancel", style: .default))
alert.addAction(UIAlertAction(title: "Allow Camera", style: .cancel) { _ in
UIApplication.shared.open(settingsAppURL, options: [:])
})
present(alert, animated: true)
}

How to restrict user from using Rear-Facing Camera in iOS app

I am working on an iOS app, in which at one point the user takes a picture. However, I want the user to ONLY be able to use the front facing camera. That is, they should not have access to the rear camera. Currently, my code looks like this:
#IBAction func takePicture(sender: UIButton) {
if UIImagePickerController.availableCaptureModesForCameraDevice(.Front) != nil {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .Camera
imagePickerController.allowsEditing = false
imagePickerController.cameraDevice = .Front
imagePickerController.delegate = self
presentViewController(imagePickerController, animated: true, completion: nil)
}
else {
let alertVC = UIAlertController(
title: "No Camera",
message: "Sorry, this device has no camera",
preferredStyle: .Alert)
let okAction = UIAlertAction(
title: "OK",
style:.Default,
handler: nil)
alertVC.addAction(okAction)
presentViewController(alertVC,
animated: true,
completion: nil)
}
}
Although this defaults the camera to be front facing, it still offers users the choice to switch to the rear camera. Is there a way I can restrict this functionality?
Thanks in advance
If you don't want to allow the user the freedom offered by a UIImagePickerController, simply don't use UIImagePickerController. Devise your own picture-taking interface (by way of AVFoundation), where you are in total control.

Resources