I can access iOS Photo Library without requesting permission - ios

I am trying to access the photo library for a new app that I am writing. I have an actionSheet that allows the user to choose between their camera and their photo library. When opening the camera, it asks the user for permission but when opening the photo library it does not. Despite this, it still brings the user to their photo library. I specifically referenced it in my info.plist, but there is still no difference. Any help? My code:
#IBAction func allowAccessToPhotos(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a Source", preferredStyle: .actionSheet)
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: "Camera", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(actionSheet, animated: true, completion: nil)
}

As per UIImagePickerController behaviour, It never gives dialogue to the user for Photos access. UIImagePickerController only ask for the Camera permission.
You have to ask for Photos permission manually to the user. By using the below code you can ask the user for Photos permission.
import Photos
#IBAction func allowAccessToPhotos(_ sender: Any) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let actionSheet = UIAlertController(title: "Photo Source", message: "Choose a Source", preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .photoLibrary
let photoAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
switch photoAuthorizationStatus {
case .authorized:
self.present(imagePickerController, animated: true, completion: nil)
case .notDetermined:
PHPhotoLibrary.requestAuthorization({
(newStatus) in
DispatchQueue.main.async {
if newStatus == PHAuthorizationStatus.authorized {
self.present(imagePickerController, animated: true, completion: nil)
}else{
print("User denied")
}
}})
break
case .restricted:
print("restricted")
break
case .denied:
print("denied")
break
}}))
actionSheet.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action:UIAlertAction) in imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}))
}
Please refer reference.
Important Note:
If you're not asking for Photos permission to the user then It will cause rejection by the apple team. It depends on your luck, Sometimes the apple team ignore it and sometimes reject our app.

From iOS 11, UIImagePickerController is running remotely on a separate process.
So, your app doesn't need the standard privacy authorization for Photos library access, it gets read-only access just for whichever asset(s) the user chooses in the imagePicker.
To add new asset into photo-library you need NSPhotoLibraryAddUsageDescription in your Info.plist - forum thread

yes you can access photos by PhotosUI library without permission
import PhotosUI
var config = PHPickerConfiguration()
config.selectionLimit = 4
config.filter = .images
let vc = PHPickerViewController(configuration: config)
vc.delegate = self
self.present(vc, animated: true)
extension UIViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
var images = [UIImage]()
for image in results {
if image.itemProvider.canLoadObject(ofClass: UIImage.self) {
image.itemProvider.loadObject(ofClass: UIImage.self) { (newImage, error) in
if let error = error {
print(error.localizedDescription)
} else {
self.images.append(newImage as! UIImage)
}
}
} else {
print("Loaded Assest is not a Image")
}
}
picker.dismiss(animated: true)
}
}

Related

Photo Library is not accessible only camera option available swift code

I am using Swift 5 code and in code I have to capture image. My source type would be .camera or .photoLibrary. I have perfectly set everything even the permission settings in Info.plist but for unseen reason photo library is not accessible for selecting image. Only camera option is available every time. Please suggest and look into my code what am I doing wrong?
Permission Info.plist:
Privacy - Photo Library Additions Usage Description
Privacy - Photo Library Usage Description
Privacy - Media Library Usage Description
Privacy - Camera Usage Description
Code:
var imagePicker: UIImagePickerController!
enum ImageSource {
case photoLibrary
case camera
}
//MARK: - Take image
func takePhoto() {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
selectImageFrom(.photoLibrary)
return
}
selectImageFrom(.camera)
}
func selectImageFrom(_ source: ImageSource){
imagePicker = UIImagePickerController()
imagePicker.delegate = self
switch source {
case .camera:
imagePicker.sourceType = .camera
case .photoLibrary:
imagePicker.sourceType = .photoLibrary
}
present(imagePicker, animated: true, completion: nil)
}
You always prioritize camera in your guard
//MARK: - Take image
func takePhotoLib() {
guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
return
}
selectImageFrom(.photoLibrary)
}
//MARK: - Take image
func takePhotoCamera() {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
return
}
selectImageFrom(.camera)
}
func selectimage(_ sender: UIButton)
{
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Take Photo", style: .default, handler: { _ in
self.openCamera()
}))
alert.addAction(UIAlertAction(title: "Choose Photo", style: .default, handler: { _ in
self.openGallary()
}))
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
//If you want work actionsheet on ipad then you have to use popoverPresentationController to present the actionsheet, otherwise app will crash in iPad
switch UIDevice.current.userInterfaceIdiom {
case .pad:
alert.popoverPresentationController?.sourceView = sender
alert.popoverPresentationController?.sourceRect = sender.bounds
alert.popoverPresentationController?.permittedArrowDirections = .up
default:
break
}
self.present(alert, animated: true, completion: nil)
}
//MARK: - Open the camera
func openCamera(){
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)){
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
//If you dont want to edit the photo then you can set allowsEditing to false
// imagePicker.allowsEditing = true
imagePicker.delegate = self
imagePicker.modalPresentationStyle = .overCurrentContext
self.present(imagePicker, animated: true, completion: nil)
}
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)
}
}
func openGallary(){
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary)){
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.tabBarController?.tabBar.isHidden = true
//If you dont want to edit the photo then you can set allowsEditing to false
// imagePicker.allowsEditing = true
imagePicker.delegate = self
imagePicker.modalPresentationStyle = .overCurrentContext
self.present(imagePicker, animated: true, completion: nil)
}
I think this function is shorter and reduces the extra code.
func selectImageFrom(_ source: UIImagePickerController.SourceType) {
guard UIImagePickerController.isSourceTypeAvailable(source) else {
return
}
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = source
present(imagePicker, animated: true, completion: nil)
}
Change the argument type from ImageSource to UIImagePickerController.SourceType
func selectImageFrom(_ source: UIImagePickerController.SourceType){
imagePicker = UIImagePickerController()
imagePicker.delegate = self
switch source {
case .camera:
imagePicker.sourceType = .camera
case .photoLibrary:
imagePicker.sourceType = .photoLibrary
}
present(imagePicker, animated: true, completion: nil)
}
It should work now.
Sorry, you seem to check whether the device have a camera and then proceed to select that. Show an action sheet for the user to select one of them. It would work.
use this function:
func showOptions(sender: AnyObject) {
let alertController = UIAlertController.init(title: "Choose Option", message: "", preferredStyle: .actionSheet)
let cameraAction = UIAlertAction.init(title: "Camera", style: .default) { (action) in
self.selectImageFrom(.camera)
}
alertController.addAction(cameraAction)
let photoLibraryAction = UIAlertAction.init(title: "Photo Library", style: .default) { (action) in
self.selectImageFrom(.photoLibrary)
}
alertController.addAction(photoLibraryAction)
let cancelAction = UIAlertAction.init(title: "Cancel", style: .cancel) { (action) in
}
alertController.addAction(cancelAction)
present(alertController, 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)
}

Accessing the camera and photo library in swift 4

I'm trying to access both the camera and photo library in swift4 using the following code
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .camera
print(1)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
but it's not working. I'm not get an access authorization request even though I made sure that the plist has the camera and photo library authorization. I manipulate the code a bit to the following
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
}
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
})
}
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .camera
print(1)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
imagePickerController.sourceType = .photoLibrary
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
Now I am getting the authorization request for both cameras and photo library and I can see the AlertView but when I press camera or Photo Album as shown in the picture nothing happens.
I tried on a device and simulator for the camera.
Here is the code to load image from photos & camera in iOS.
⁃ You need to create an outlet of your UIImageView
⁃ Then add a tap gesture on to image view
⁃ Then connect tap gesture with the didTapOnImageView function.
⁃ Then add the following extension to your view controller.
//MARK:- Image Picker
extension YourViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//This is the tap gesture added on my UIImageView.
#IBAction func didTapOnImageView(sender: UITapGestureRecognizer) {
//call Alert function
self.showAlert()
}
//Show alert to selected the media source type.
private func showAlert() {
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .camera)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .photoLibrary)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
self.present(alert, animated: true, completion: nil)
}
//get image from source type
private func getImage(fromSourceType sourceType: UIImagePickerController.SourceType) {
//Check is source type available
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = sourceType
self.present(imagePickerController, animated: true, completion: nil)
}
}
//MARK:- UIImagePickerViewDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
self.dismiss(animated: true) { [weak self] in
guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
//Setting image to your image view
self?.profileImgView.image = image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
Note: Don't forget to add the privacy settings in info.plist
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
First of all, you need to import these libraries:
import Photos
import UIKit
#IBOutlet weak var loadPhoto: UIButton!
And you need setup delegates:
class YourClass: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UNUserNotificationCenterDelegate
func displayUploadImageDialog(btnSelected: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self
picker.allowsEditing = true
let alertController = UIAlertController(title: "", message: "Upload profile photo?".localized(), preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel action"), style: .cancel, handler: {(_ action: UIAlertAction) -> Void in
alertController.dismiss(animated: true) {() -> Void in }
})
alertController.addAction(cancelAction)
let cameraRollAction = UIAlertAction(title: NSLocalizedString("Open library".localized(), comment: "Open library action"), style: .default, handler: {(_ action: UIAlertAction) -> Void in
if UI_USER_INTERFACE_IDIOM() == .pad {
OperationQueue.main.addOperation({() -> Void in
picker.sourceType = .photoLibrary
self.present(picker, animated: true) {() -> Void in }
})
}
else {
picker.sourceType = .photoLibrary
self.present(picker, animated: true) {() -> Void in }
}
})
alertController.addAction(cameraRollAction)
alertController.view.tintColor = .black
present(alertController, animated: true) {() -> Void in }
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
profileImage.image = image
let imageData = UIImageJPEGRepresentation(image, 0.05)
self.dismiss(animated: true, completion: nil)
}
func checkPermission() {
let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
switch authStatus {
case .authorized:
self.displayUploadImageDialog(btnSelected: self.loadPhoto)
case .denied:
print("Error")
default:
break
}
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.dismiss(animated: true, completion: nil)
}
func checkLibrary() {
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .authorized {
switch photos {
case .authorized:
self.displayUploadImageDialog(btnSelected: self.loadPhoto)
case .denied:
print("Error")
default:
break
}
}
}
Setup action for button:
#IBAction func loadPhotoTapped(_ sender: UIButton) {
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
if status == .authorized{
print("OKAY")
} else {
print("NOTOKAY")
}
})
}
checkLibrary()
checkPermission()
}
At the Info.plist setup the permissions:
Privacy - Media Library Usage Description
Privacy - Photo Library Usage Description
Privacy - Camera Usage Description
This should work.

Selecting "camera" causes Terminated due to signal 9

In iOS Swift 3.1 I'm trying to access the camera, the same way I have done successfully in other apps. However, in this one particular app, it always crashes on the self.present(imagePicker, animated: true, completion: nil) line. The message in the console is Message from debugger: Terminated due to signal 9. Does this usually signal a memory related error?
#IBAction func onChooseImageClick(_ sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.savedPhotosAlbum){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
//Create the AlertController and add Its action like button in Actionsheet
let actionSheetControllerForImage: UIAlertController = UIAlertController(title: "Please select", message: "Option to select", preferredStyle: .actionSheet)
let cancelActionButton: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel) { action -> Void in
print("Cancel")
}
actionSheetControllerForImage.addAction(cancelActionButton)
let cameraActionButton: UIAlertAction = UIAlertAction(title: "Camera", style: .default)
{ action -> Void in
print("Camera")
if(UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)) {
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
let mediaTypes:[String] = [kUTTypeImage as String]
imagePicker.mediaTypes = mediaTypes
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "error", message: "Camera not found!", preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .cancel) { action in
// ...
}
alertController.addAction(OKAction)
self.present(alertController, animated: true)
}
}
actionSheetControllerForImage.addAction(cameraActionButton)
let galleryActionButton: UIAlertAction = UIAlertAction(title: "Image Gallery", style: .default)
{ action -> Void in
imagePicker.sourceType = UIImagePickerControllerSourceType.savedPhotosAlbum;
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
actionSheetControllerForImage.popoverPresentationController?.sourceView = self.view
actionSheetControllerForImage.addAction(galleryActionButton)
===> self.present(actionSheetControllerForImage, animated: true, completion: nil)
}
}
You need a string in your plist file that explains why your app need permission to use the camera. There's a great summary of these strings in the question at iOS 10 - Changes in asking permissions of Camera, microphone and Photo Library causing application to crash, with a list you can copy from in the answer at https://stackoverflow.com/a/40734360/968577
Without the required strings, your app will crash in this manner. However, the console output will explain what the problem is.
Try like this i hope it would be helpful!!
Add these two points in info.plist first
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
Add these two delegates in your class file
UIImagePickerControllerDelegate
UINavigationControllerDelegate
#IBAction func onclickImageAction(_ sender: Any){
print("onclickImageAction method called here")
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.isEditing = false
let actionSheet = UIAlertController(title: "Select Profile Photo", message: "", preferredStyle: UIAlertControllerStyle.actionSheet)
let libButton = UIAlertAction(title: "Select photo from library", style: UIAlertActionStyle.default){ (libSelected) in
print("library selected")
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
actionSheet.addAction(libButton)
let cameraButton = UIAlertAction(title: "Take a picture", style: UIAlertActionStyle.default) { (camSelected) in
if (UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera))
{
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
self.present(imagePicker, animated: true, completion: nil)
}
else
{
actionSheet.dismiss(animated: false, completion: nil)
let alert = UIAlertController(title: "Error", message: "There is no camera available", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: { (alertAction) in
alert.dismiss(animated: true, completion: nil)
}))
}
}
actionSheet.addAction(cameraButton)
let cancelButton = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) { (cancelSelected) in
print("cancel selected")
}
actionSheet.addAction(cancelButton)
let albumButton = UIAlertAction(title: "Saved Album", style: UIAlertActionStyle.default) { (albumSelected) in
print("Album selected")
imagePicker.sourceType = UIImagePickerControllerSourceType.savedPhotosAlbum
self.present(imagePicker, animated: true, completion: nil)
}
actionSheet.addAction(albumButton)
self.present(actionSheet, animated: true, completion:nil)
}
Implement these delegate method
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{if let PickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
{
yourimageview.image = PickedImage
dismiss(animated: true, completion: nil)
}
}
I just added exit(0) when i opened the camera settings. It's working fine

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

Resources