私は非常にシンプルなビデオアプリを開発しています。公式コントロールのUIImagePickerControllerを使用します。
ここに問題があります。 UIImagePickerControllerを初めて表示するとき、iOSは許可を求めます。ユーザーは[はい]または[いいえ]をクリックできます。ユーザーが[いいえ]をクリックした場合、コントロールは閉じられません。代わりに、ユーザーが[スタート]ボタンをクリックし続けると、画面が常に黒である間にタイマーがオンになり、ユーザーはタイマーを停止または元に戻すことができません。ユーザーができることは、アプリを強制終了することだけです。次回UIImagePickerControllerが表示されるとき、それはまだ黒い画面であり、ユーザーが[スタート]をクリックすると戻ることはできません。
私はそれがバグかどうか疑問に思っていました。 UIImagePickerControllerを表示するかどうかを決定できるように、カメラの許可を検出する方法はありますか?
AVAuthorizationStatus
を確認し、ケースを適切に処理してください。
NSString *mediaType = AVMediaTypeVideo;
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
if(authStatus == AVAuthorizationStatusAuthorized) {
// do your logic
} else if(authStatus == AVAuthorizationStatusDenied){
// denied
} else if(authStatus == AVAuthorizationStatusRestricted){
// restricted, normally won't happen
} else if(authStatus == AVAuthorizationStatusNotDetermined){
// not determined?!
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if(granted){
NSLog(@"Granted access to %@", mediaType);
} else {
NSLog(@"Not granted access to %@", mediaType);
}
}];
} else {
// impossible, unknown authorization status
}
IOS 10以降、Info.plistでNSCameraUsageDescription
キーを指定してカメラアクセスを要求する必要があります。そうしないと、実行時にアプリがクラッシュします。 使用方法の説明が必要なAPI を参照してください。
確認してください:
import AVFoundation
以下のSwiftコードは、考えられるすべての許可状態をチェックします。
let cameraMediaType = AVMediaType.video
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: cameraMediaType)
switch cameraAuthorizationStatus {
case .denied: break
case .authorized: break
case .restricted: break
case .notDetermined:
// Prompting user for the permission to use the camera.
AVCaptureDevice.requestAccess(for: cameraMediaType) { granted in
if granted {
print("Granted access to \(cameraMediaType)")
} else {
print("Denied access to \(cameraMediaType)")
}
}
}
let cameraMediaType = AVMediaTypeVideo
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: cameraMediaType)
switch cameraAuthorizationStatus {
case .denied: break
case .authorized: break
case .restricted: break
case .notDetermined:
// Prompting user for the permission to use the camera.
AVCaptureDevice.requestAccess(forMediaType: cameraMediaType) { granted in
if granted {
print("Granted access to \(cameraMediaType)")
} else {
print("Denied access to \(cameraMediaType)")
}
}
}
おもしろいことに、[設定]でカメラの権限を変更しているときに、iOSが実行中のアプリを強制終了することをご存知でしたか?
Apple開発者フォーラムから:
ユーザーが設定でcameraへのアプリのアクセスを切り替えると、システムは実際にアプリを強制終了します。同じことは、[設定]→[プライバシー]セクションの保護されたデータクラスにも適用されます。
@Raptorからの回答への追加として、次のことに言及する必要があります。 iOS 10以降、次のエラーが表示される場合があります:This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
これを修正するには、メインスレッドからの結果を次のように処理してください(Swift 3):
private func showCameraPermissionPopup() {
let cameraMediaType = AVMediaTypeVideo
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: cameraMediaType)
switch cameraAuthorizationStatus {
case .denied:
NSLog("cameraAuthorizationStatus=denied")
break
case .authorized:
NSLog("cameraAuthorizationStatus=authorized")
break
case .restricted:
NSLog("cameraAuthorizationStatus=restricted")
break
case .notDetermined:
NSLog("cameraAuthorizationStatus=notDetermined")
// Prompting user for the permission to use the camera.
AVCaptureDevice.requestAccess(forMediaType: cameraMediaType) { granted in
DispatchQueue.main.sync {
if granted {
// do something
} else {
// do something else
}
}
}
}
}
extension AVCaptureDevice {
enum AuthorizationStatus {
case justDenied
case alreadyDenied
case restricted
case justAuthorized
case alreadyAuthorized
}
class func authorizeVideo(completion: ((AuthorizationStatus) -> Void)?) {
AVCaptureDevice.authorize(mediaType: AVMediaType.video, completion: completion)
}
class func authorizeAudio(completion: ((AuthorizationStatus) -> Void)?) {
AVCaptureDevice.authorize(mediaType: AVMediaType.audio, completion: completion)
}
private class func authorize(mediaType: AVMediaType, completion: ((AuthorizationStatus) -> Void)?) {
let status = AVCaptureDevice.authorizationStatus(for: mediaType)
switch status {
case .authorized:
completion?(.alreadyAuthorized)
case .denied:
completion?(.alreadyDenied)
case .restricted:
completion?(.restricted)
case .notDetermined:
AVCaptureDevice.requestAccess(for: mediaType, completionHandler: { (granted) in
DispatchQueue.main.async {
if(granted) {
completion?(.justAuthorized)
}
else {
completion?(.justDenied)
}
}
})
}
}
}
そして、それを使用するには
AVCaptureDevice.authorizeVideo(completion: { (status) in
//Your work here
})
最初にInfo.plistでNSCameraUsageDescriptionキーを指定します。次に、Authorizedの場合はAVAuthorizationStatusを確認し、UIImagePickerControllerを提示します。それが動作します。