I cannot access the camera in a UIViewController - ios

I really hope I'm not making a duplicate - but I read a ton different camera-questions inhere and implemented all of their answers, with the same result: Nothing happens!
No errors, the app doesn't crash, no problems whatsoever - only there is no sign of the camera, which should be activated! My goal is to get it activated in viewDidAppear or viewDidLoad, but I also tried testing it by connecting the code to a button - same result; nothing. Both on my own device and on the simulator: nothing!
What am i getting wrong in this simple code?? - Or which setting do I need to change? I have tried playing with the "data protection": nothing!
Code:
class CreateNewPerson: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func viewDidAppear () {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
present(imagePicker, animated: true, completion: nil)
}
private func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]!) {
PersonPhoto.image = info[UIImagePickerControllerOriginalImage] as? UIImage
dismiss(animated: true, completion: nil)
}
Hope someone can help me!
Photo of info.plist (where I can't seem to find the camera ussage description) - maybe I'm an idiot...:
Thanks!

You need to add a Camara usage description into your info.plist file and ask permission for your app to access the camera.
Add this to your plist file:
Privacy - Camera Usage Description
With some text like
"We need your permission to access the device camera"
To request permission:
AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in
if granted {
// show the image picker
} else {
// show an error
}
}
It is usually best to check if you need permission or what state the permissions are in, so I would do it like this...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
checkCameraPermissions()
}
private func checkCameraPermissions() {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .authorized:
self.presentPicker()
case .notDetermined:
self.requestPermissions()
case .denied:
// user denied access
self.permissionDenied()
}
}
private func requestAccess() {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { granted in
if !granted {
// show an error
}
// call it again in to recheck now that permissions have changed.
checkCameraPermissions
}
}
private func presentPicker() {
// permissions are all set, continue as planned.
}
private func permissionDenied() {
// show an alert and link to app settings to turn on
// usually I would show a view which explains they have denied permission to the camera so this functionality isn't available until they manually change the setting in the app settings.
}

You have to add CreateNewPerson in UINavigationController after that run your code.
Don't forget to add Privacy - Camera Usage Description in info.plist

Related

UIImagePickerController does not present when triggered from delegate function

I have one weird case where UIImagePickerController will not present.
Context: I'm using UIImagePicker to let a user pick a profile image from their photos. They tap to add a profile image and initially a modal is triggered where they can pick between using their local photos and their facebook profile photo.
This modal delegates back to the profile view controller where all the functions below exist. The modal fires didSelectProfilePhotoOption - in this case with .fromPhotos.
func didSelectProfilePhotoOption(photoSource: PhotoSource) {
switch photoSource {
case .fromFacebook:
useFacebookPhotoForProfile()
case .fromPhotos:
selectProfileImageFromPhotoLibrary()
}
}
This is important, because I have tried just triggering selectProfileImageFromPhotoLibrary from the view controller (rather than the modal delegate) and the UIImagePickerController shows every time.
func selectProfileImageFromPhotoLibrary() {
let status = PHPhotoLibrary.authorizationStatus()
handleImageAuthStatus(status: status)
}
func handleImageAuthStatus(status: PHAuthorizationStatus) {
switch status {
case .authorized:
presentImagePicker()
case .denied:
//show an error message
case .notDetermined:
PHPhotoLibrary.requestAuthorization( { status in
self.handleImageAuthStatus(status: status)
})
case .restricted:
//show an error message
}
}
func presentImagePicker() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = false
imagePicker.sourceType = .photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
The added weirdness is that UIImagePickerController will show when it's chained as part of requesting the photo permissions.
So in the case:
didSelectProfilePhotoOption(photoSource: .fromPhotos) >>> selectProfileImageFromPhotoLibrary >>> handleImageAuthStatus(status: .notDetermined) >>> (grant permissions) >>> handleImageAuthStatus(status: .authorized)
...UIImagePickerController shows every time.
Any ideas what's going on here? Many thanks in advance!

Contacts and Microphone request access does not work on iOS 9

I've been stuck on a bug since last Monday, so I'm asking for help now ..
Contacts and Micriohpone request access does not work on iOS 9. I use this piece of code in order to request access to contacts :
let contactsStore = CNContactStore()
func requestAccess(completionHandler: #escaping (Permission) -> ()) {
self.contactsStore.requestAccess(for: .contacts, completionHandler: { (granted, error) in
if granted {
completionHandler(.granted)
} else {
completionHandler(.denied)
}
})
}
This function is called, no problem with that, the problem is it always return .denied and an error set with "Access denied", even though no alert has been shown to the user. The same with microphone.
The key 'Privacy - Contacts Usage Description' is present in my Info.plist
EDIT :
I also know that when the user denied once the usage it is not shown anymore, but the other problem is that there is not "switch" in the settings section of the app. I tried to restore the device (Working on simulator as I don't have a real iOS 9 device), but still the same behaviour.
This code works perfeclty on iOS 10 and iOS 11. But no chance on iOS 9
If you could help me on this issue that would be awesome.
Thanks !
I tried this on 9.3 in the simplest way imaginable, and I did get a prompt:
import UIKit
import Contacts
class ViewController: UIViewController {
let contactsStore = CNContactStore()
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.async {
self.requestAccess(completionHandler: { (permission) in
print("The user said \(permission)")
})
}
}
func requestAccess(completionHandler: #escaping (Permission) -> ()) {
self.contactsStore.requestAccess(for: .contacts, completionHandler: { (granted, error) in
if granted {
completionHandler(.granted)
} else {
completionHandler(.denied)
}
})
}
}
enum Permission {
case granted
case denied
}
This works fine. I think the issue is that you already denied it.
The only solutions are:
Change the bundle id, which will make your app act as a different one
Reset your device/simulator (easier if a simulator of course)
Change the privacy setting from Off to On
For end users, I've seen the UI prompt the user to change the setting if they see "denied".
You can do that like this:
self.requestAccess(completionHandler: { (permission) in
print("The user said \(permission)")
if ( permission == .denied ) {
let urlStr = UIApplicationOpenSettingsURLString
if let url = URL(string:urlStr) {
UIApplication.shared.openURL(url)
}
}
})

Upload function working in safari but not in mobile wkWebView ios app

I have got a file upload system attached my my website that works perfect on the mobile safari. I can access the iCloud, Photo Libraray, and Camera.
However after I implemented it into the wkWebView in our mobile app the upload system no longer works.
When I load the wkWebView and click on the button it brings up the options of where I want to grab the file from. I select Photo Library and it closes the webview and takes me back to my first viewController.
Here is the webview code:
//Camera
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { response in
if response {
//access granted
} else {
}
}
//Photos
let photos = PHPhotoLibrary.authorizationStatus()
if photos == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
if status == .authorized{
//...
} else {}
})
}
let requestObj = URLRequest(url: URL(string: "https://example.com/chat.php?use=\(userId)")!)
corepage.load(requestObj);
}
I also have added the information to the info.plist as well. However, this didn't solve my issue of the page reverting back to the main viewController when clicking any of the options of uploading a file.
Thanks Guys!
I have gotten it figured out:
In the viewcontroller that has my webview I added:
override func dismiss(animated flag: Bool, completion: (() -> Void)?) {
if (self.presentedViewController != nil) {
super.dismiss(animated: flag, completion: completion)
}
}
This prevented the dimissal issue.

ios, displaying an alert before everything else, to inform user we'll need "some" permissions

i'm developing an app. One of the firs thing i do (in AppDelegate) is to invoke OneSignal's initwithlaunchingoptions(...)
This automatically makes my app displays "App wants to send notifications", asking for permissions.
During my app lifecycle, i'll need other permissions from user (like calendar).
I'd like to display (BEFORE all the permissions) a brief AlertView explaining what i'll ask and why.
But how can i accomplish this if i can't move the OneSignal init from AppDelegate while my "explaining alert" happens only in viewDidLoad of the Main ViewController ?
Thanks.
Victor
here is an example of UIViewController that has information about applications needs location data, when user presses UIButton, it asks for permission. you can do alike for all permissions.
class LocationRequestViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
}
//when user authorised or denied ->push next `UIViewController`
func locationManager(_: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .denied {
let destinationVC = self.storyboard!.instantiateViewController(withIdentifier: "Notifications Request")
self.navigationController?.pushViewController(destinationVC, animated: true)
}
}
#IBAction func requestLocation(_: UIButton) {
self.locationManager.requestWhenInUseAuthorization()
}
}

How to detect user has clicked Don't Allow access to camera

I am using a UIImagePicker to present the users with camera to take photos which will be used in the app.
My problem is that on the first time a user opens the image picker they are presented with a prompt saying: '"my App" Would like to Access your Camera' with two options, Don't allow and OK.
My requirement is that when the user clicks Don't Allow, the Image picker gets dismissed leaving a black view. Is there a way to detect that the user has chosen Don't allow?
Here is my code to present UIImagePicker:
var PhotoPicker:UIImagePickerController = UIImagePickerController()
PhotoPicker.delegate = self
PhotoPicker.sourceType = .Camera
PhotoPicker.cameraFlashMode = .Off
PhotoPicker.showsCameraControls = false
PhotoPicker.cameraDevice = .Rear
self.presentViewController(PhotoPicker, animated: false, completion: nil)
To detect access to your library:
You need to use AssetsLibrary for that. First, import assets library framework:
import AssetsLibrary
Then, request authorization status, and if it is not determined, use blocks to catch those events, like this:
if ALAssetsLibrary.authorizationStatus() == ALAuthorizationStatus.NotDetermined {
let library = ALAssetsLibrary()
library.enumerateGroupsWithTypes(.All, usingBlock: { (group, stop) -> Void in
// User clicked ok
}, failureBlock: { (error) -> Void in
// User clicked don't allow
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
})
}
To detect access to camera:
You need to use AVFoundation for that. First, import avfoundation framework:
import AVFoundation
Then, as previously, request user permission when you go to imagepicker and catch the event.
if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) == AVAuthorizationStatus.NotDetermined {
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
// User clicked ok
if (videoGranted) {
// User clicked don't allow
} else {
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
}
})
}
Hope it helps!
In iOS 10, use:
import Photos
let authStatus = PHPhotoLibrary.authorizationStatus()
if authStatus == .notDetermined || authStatus == .denied {
PHPhotoLibrary.requestAuthorization({ (status) in
if status == PHAuthorizationStatus.authorized {
} else {
imagePickerController.dismissViewControllerAnimated(true, completion: nil)
}
})
}
Check out this for detecting camera permission
Presenting camera permission dialog in iOS 8
Use this when user picks Don't Allow.
PhotoPicker.dismissViewControllerAnimated(false, completion: nil)

Resources