アプリがiOS 8で初めてカメラにアクセスしようとすると、iOS 7のマイクアクセス用のマイクのように、ユーザーにカメラ許可ダイアログが表示されます。
IOS 7では、事前にマイク許可ダイアログを呼び出し、許可が付与されているかどうかを確認することができました(たとえば、 この質問 を参照)。 iOS 8でカメラ許可ダイアログを呼び出す同様の方法はありますか?ダイアログをマイクとカメラのアクセス許可に組み合わせることができますか?
最終的に使用したアプローチは次のとおりです。
if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
// Will get here on both iOS 7 & 8 even though camera permissions weren't required
// until iOS 8. So for iOS 7 permission will always be granted.
if (granted) {
// Permission has been granted. Use dispatch_async for any UI updating
// code because this block may be executed in a thread.
dispatch_async(dispatch_get_main_queue(), ^{
[self doStuff];
});
} else {
// Permission has been denied.
}
}];
} else {
// We are on iOS <= 6. Just do what we need to do.
[self doStuff];
}
ユーザーが最初のプロンプトでカメラへのアクセスを拒否した場合、同様の問題が発生します。ボタンを押してスナップショットを撮ると、カメラモードで黒い画面が表示されます。
ただし、ユーザーがアクセスを拒否したことを検出し、オンにする必要があることを要求しますが、現在のユーザーのカメラアクセスを確認する機能が見つかりません、そのような機能はありますか?
編集:次のチェックにより、IOS 8でカメラアクセスについて知ることができます。
#import <AVFoundation/AVFoundation.h>
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(status == AVAuthorizationStatusAuthorized) { // authorized
}
else if(status == AVAuthorizationStatusDenied){ // denied
}
else if(status == AVAuthorizationStatusRestricted){ // restricted
}
else if(status == AVAuthorizationStatusNotDetermined){ // not determined
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if(granted){ // Access has been granted ..do something
} else { // Access denied ..do something
}
}];
}
この情報は、次の質問で見つかりました( アプリケーションがカメラにアクセスできるか、iOS8でプログラム的にアクセスできないかを知る方法 ):
ここに私のSwiftソリューション(iOS 8)があります。QRスキャンにカメラが必要だったので、使用を促す必要がありました。
これにより提供されます
デフォルトのカメラアクセスを許可する質問の前に許可を選択するようにユーザーに促します
ユーザーが最初の要求を拒否した場合に設定にアクセスする簡単な方法。
それを実行するには、ViewDidAppear /またはViewDidLoadなどでカメラをチェックします。カスタムカメラビューの制約が設定されるようにviewDidAppearを使用する必要がありました。
func checkCamera() {
let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch authStatus {
case .authorized: break // Do your stuff here i.e. allowScanning()
case .denied: alertToEncourageCameraAccessInitially()
case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
default: alertToEncourageCameraAccessInitially()
}
}
func alertToEncourageCameraAccessInitially() {
let alert = UIAlertController(
title: "IMPORTANT",
message: "Camera access required for QR Scanning",
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.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
}))
present(alert, animated: true, completion: nil)
}
func alertPromptToAllowCameraAccessViaSetting() {
let alert = UIAlertController(
title: "IMPORTANT",
message: "Please allow camera access for QR Scanning",
preferredStyle: UIAlertControllerStyle.alert
)
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
DispatchQueue.main.async() {
self.checkCamera() } }
}
}
)
present(alert, animated: true, completion: nil)
}
Dispatch_asyncを使用するためのヒントを提供してくれたjamixのおかげで、新しく設定されたカメラ機能を非常に高速に表示するように応答できます。
末尾のクロージャーが混在して申し訳ありません。試してみたかったです。
どの回答も、マイクとカメラの両方の許可をチェックするようには見えません。私たちのコードは、カメラの許可は与えられているが、マイクへのアクセスは拒否されているシナリオに対してチェックします。
Swiftが初めてなので、ひどくネストされたクロージャーとif
ステートメントが最適である可能性は低いです。コードを改善するための提案を共有してください!しかし、少なくともこれまでのところテストでは機能しています。
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (videoGranted: Bool) -> Void in
if (videoGranted) {
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeAudio, completionHandler: { (audioGranted: Bool) -> Void in
if (audioGranted) {
dispatch_async(dispatch_get_main_queue()) {
// Both video & audio granted
}
} else {
// Rejected audio
}
})
} else {
// Rejected video
}
})
Swift 3.0 Solution
aVFoundationのインポート
注:プライバシーの追加-Info.plistのカメラ使用説明キー
// MARK:カメラの取り扱い
func callCamera(){
let myPickerController = UIImagePickerController()
myPickerController.delegate = self;
myPickerController.sourceType = UIImagePickerControllerSourceType.camera
self.present(myPickerController, animated: true, completion: nil)
NSLog("Camera");
}
func checkCamera() {
let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch authStatus {
case .authorized: callCamera() // Do your stuff here i.e. callCameraMethod()
case .denied: alertToEncourageCameraAccessInitially()
case .notDetermined: alertPromptToAllowCameraAccessViaSetting()
default: alertToEncourageCameraAccessInitially()
}
}
func alertToEncourageCameraAccessInitially() {
let alert = UIAlertController(
title: "IMPORTANT",
message: "Camera access required for capturing photos!",
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.openURL(URL(string: UIApplicationOpenSettingsURLString)!)
}))
present(alert, animated: true, completion: nil)
}
func alertPromptToAllowCameraAccessViaSetting() {
let alert = UIAlertController(
title: "IMPORTANT",
message: "Camera access required for capturing photos!",
preferredStyle: UIAlertControllerStyle.alert
)
alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel) { alert in
if AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo).count > 0 {
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
DispatchQueue.main.async() {
self.checkCamera() } }
}
}
)
present(alert, animated: true, completion: nil)
}
私にとってこれはiOS7とiOS8で動作します:
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusAuthorized:
break;
case ALAuthorizationStatusRestricted:
case ALAuthorizationStatusDenied:
break;
case ALAuthorizationStatusNotDetermined:
break;
}
Swift 3の場合、これを最初のView ControllerのviewWillAppear
メソッドに追加できます。
最初にAVFoundation
フレームワークをインポートします
import AVFoundation
次に:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let authorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch authorizationStatus {
case .notDetermined:
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { granted in
if granted {
print("access granted")
}
else {
print("access denied")
}
}
case .authorized:
print("Access authorized")
case .denied, .restricted:
print("restricted")
}
}
Privacy - Camera Usage Description
にInfo.plist
キーを追加することを忘れないでください
アプリのデリゲートでアクセスチェックを行います。
import UIKit
import AVFoundation
import Photos
func applicationDidBecomeActive(application: UIApplication) {
cameraAllowsAccessToApplicationCheck()
internetAvailabilityOnApplicationCheck()
photoLibraryAvailabilityCheck()
}
//MARK:- CAMERA ACCESS CHECK
func cameraAllowsAccessToApplicationCheck()
{
let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
switch authorizationStatus {
case .NotDetermined:
// permission dialog not yet presented, request authorization
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo,
completionHandler: { (granted:Bool) -> Void in
if granted {
print("access granted")
}
else {
print("access denied")
}
})
case .Authorized:
print("Access authorized")
case .Denied, .Restricted:
alertToEncourageCameraAccessWhenApplicationStarts()
default:
print("DO NOTHING")
}
}
//MARK:- PHOTO LIBRARY ACCESS CHECK
func photoLibraryAvailabilityCheck()
{
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.Authorized
{
}
else
{
var cameraUnavailableAlertController = UIAlertController (title: "Photo Library Unavailable", message: "Please check to see if device settings doesn't allow photo library access", preferredStyle: .Alert)
var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.sharedApplication().openURL(url)
}
}
var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
cameraUnavailableAlertController .addAction(settingsAction)
cameraUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
}
}
func internetAvailabilityOnApplicationCheck()
{
//MARK:- INTERNET AVAILABLITY
if InternetReachability.isConnectedToNetwork() {
}
else
{
dispatch_async(dispatch_get_main_queue(), {
//INTERNET NOT AVAILABLE ALERT
var internetUnavailableAlertController = UIAlertController (title: "Network Unavailable", message: "Please check your internet connection settings and turn on Network Connection", preferredStyle: .Alert)
var settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
if let url = settingsUrl {
UIApplication.sharedApplication().openURL(url)
}
}
var cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
internetUnavailableAlertController .addAction(settingsAction)
internetUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.presentViewController(internetUnavailableAlertController , animated: true, completion: nil)
})
}
}
*
私にとっての問題は、最近のビルド構成の変更のために、Info.plistでBundle name
とBundle Display Name
が設定されないことでした。ありそうもないケースのような...しかし、これを特定するのに数時間かかりました。うまくいけば、それは他の誰かのために役立ちます。