Mendeteksi izin kamera di iOS

143

Saya sedang mengembangkan aplikasi video yang sangat sederhana. Saya menggunakan kontrol resmi: UIImagePickerController.

Inilah masalahnya. Saat menghadirkan UIImagePickerController untuk pertama kalinya, iOS akan meminta izin. Pengguna dapat mengklik ya atau tidak. Jika pengguna mengklik tidak, kontrol tidak diberhentikan. Sebaliknya, jika pengguna terus mengklik tombol mulai, penghitung waktu akan terus menyala sementara layar selalu hitam, dan pengguna tidak dapat menghentikan penghitung waktu atau kembali. Satu-satunya hal yang dapat dilakukan pengguna adalah mematikan aplikasi. Kali berikutnya UIImagePickerController disajikan, itu masih merupakan layar hitam dan pengguna tidak dapat kembali jika mengklik mulai.

Saya bertanya-tanya apakah itu bug. Apakah ada cara kami dapat mendeteksi izin kamera sehingga kami dapat memutuskan untuk menampilkan UIImagePickerController atau tidak?

pengguna418751
sumber
Re: apakah ini bug? IMHO, saya pikir begitu, karena apa yang tampaknya terjadi adalah bahwa VC menampilkan data dari perangkat keras, tetapi OS pada dasarnya mengirim udara mati. Bagaimana iOS sampai di sini mungkin merupakan efek samping dari evolusi keluarga produk. UIImageViewControllertercatat ditambahkan di iOS 2.0, dan dokumen tidak pernah beranotasi untuk mencerminkan bahwa Status AVAuthorization harus digunakan, tetapi hidup dalam kerangka kerja lain.
benc

Jawaban:

229

Periksa AVAuthorizationStatusdan tangani kasingnya dengan benar.

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
}
Raptor
sumber
19
juga membutuhkan: #import <AVFoundation/AVFoundation.h>atau serupa
toblerpwn
9
Tip yang mungkin berguna - jika Anda menguji kode yang menggunakan ini, Anda tidak bisa hanya menghapus Aplikasi Anda dari perangkat pengujian dan kemudian menginstal ulang. Melakukan hal ini tidak akan menyebabkan iOS mengeluarkan kembali permintaan kepada pengguna! Apa yang berhasil bagi saya adalah mengubah Bundle IDaplikasi setiap kali saya ingin menguji ini. Rasa sakit di gelandangan, tapi setidaknya ada sesuatu. Ingatlah untuk mengatur kembali ID ketika Anda selesai ;-)
Benjohn
25
@ Benjohn: tidak perlu mengubah ID Bundle. Anda dapat pergi ke Pengaturan> Umum> Atur Ulang dan menemukan pengaturan yang akan mengatur ulang semua permintaan izin pada perangkat. Memang, itu juga menjengkelkan karena mempengaruhi semua aplikasi lain di perangkat Anda juga. Jika saja Apple dapat menambahkan kontrol khusus aplikasi untuk ini di bagian Pengembangan Settings.app ...
KennyDeriemaeker
3
@KennyDeriemaeker :-) Apple mungkin menjawab bahwa kita seharusnya menggunakan perangkat khusus untuk pengujian! Bagi saya efek samping dari pengaturan ulang ponsel biasa saya akan sangat sial. Mengubah ID bundel adalah alternatif yang cukup menyakitkan. Saya ingat untuk mengubahnya kembali sebelum pengiriman juga :-)
Benjohn
8
Pastikan Anda tidak melakukan reset penuh! Menyetel ulang pengaturan Privasi & Lokasi (iOS 8) sudah cukup.
Canucklesandwich
81

Swift 4 dan yang lebih baru

Pastikan untuk:

import AVFoundation

Kode di bawah ini memeriksa semua kemungkinan status izin:

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

Karena iOS 10 Anda perlu menentukan NSCameraUsageDescriptionkunci di Info.plist Anda untuk dapat meminta akses kamera, jika tidak aplikasi Anda akan macet saat runtime. Lihat API yang Memerlukan Uraian Penggunaan .


Sebagai catatan tambahan yang menarik, tahukah Anda bahwa iOS membunuh aplikasi jika sedang berjalan saat Anda mengubah izin kameranya di Pengaturan?

Dari forum Pengembang Apple:

Sistem sebenarnya membunuh aplikasi Anda jika pengguna mengalihkan akses aplikasi Anda ke kamera di Pengaturan. Hal yang sama berlaku untuk setiap dataclass yang dilindungi di bagian Pengaturan → Privasi.

Nikita Kukushkin
sumber
Bagaimana dengan otorisasi galeri kamera dan foto ??
Hajar ELKOUMIKHI
4

Solusi Cepat

extension AVCaptureDevice {
    enum AuthorizationStatus {
        case justDenied
        case alreadyDenied
        case restricted
        case justAuthorized
        case alreadyAuthorized
        case unknown
    }

    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)
                    }
                }
            })
        @unknown default:
            completion?(.unknown)
        }
    }
}

Dan kemudian untuk menggunakannya Anda lakukan

AVCaptureDevice.authorizeVideo(completion: { (status) in
   //Your work here
})
Josh Bernfeld
sumber
Bagaimana dengan otorisasi galeri kamera dan foto ??
Hajar ELKOUMIKHI
2

Sebagai tambahan untuk jawaban dari @Raptor berikut ini harus disebutkan. Anda mungkin menerima kesalahan berikut ini dimulai dengan 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.

Untuk memperbaikinya, pastikan Anda menangani hasil dari utas utama sebagai berikut (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
                }
            }
        }
    }
}
Bart van Kuik
sumber
Jika ditolak, metode requestAccess tidak akan berfungsi. Anda harus secara manual menunjukkan peringatan untuk meminta pengguna pergi ke pengaturan dan memberikan izin.
Abdullah Umer
0

Tentukan kunci NSCameraUsageDescription di Info.plist terlebih dahulu. Kemudian periksa AVAuthorizationStatus jika Diotorisasi kemudian tunjukkan UIImagePickerController. Itu akan berhasil.

Yogendra Singh
sumber
-4

Swift: Menggunakan AVFoundation

  1. Tambahkan AVFoundation ke Target -> Build Phases -> Link Binary with Libraries.
  2. impor AVFoundation di ViewController.
  3. Pada Info.plist, Tambahkan yang berikut ini:

masukkan deskripsi gambar di sini

  1. Pengendali Tampilan:

@IBAction func cameraButtonClicked (pengirim: AnyObject) {

let authorizationStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
print(authorizationStatus.rawValue)

if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) ==  AVAuthorizationStatus.Authorized{
    self.openCameraAfterAccessGrantedByUser()
}
else
{
    print("No Access")

    dispatch_async(dispatch_get_main_queue()) { [unowned self] in
        AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted :Bool) -> Void in
            if granted == true
            {
                // User granted
                self.openCameraAfterAccessGrantedByUser()
            }
            else
            {
                // User Rejected
                  alertToEncourageCameraAccessWhenApplicationStarts()
            }
        });
    }
}


//Open camera

    func openCameraAfterAccessGrantedByUser()
    {
    if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera)){
        self.cameraAndGalleryPicker!.sourceType = UIImagePickerControllerSourceType.Camera
        cameraAndGalleryPicker?.delegate = self
        cameraAndGalleryPicker?.allowsEditing =  false
        cameraAndGalleryPicker!.cameraCaptureMode = .Photo
        cameraAndGalleryPicker!.modalPresentationStyle = .FullScreen
        presentViewController(self.cameraAndGalleryPicker!, animated: true, completion: nil)
    }
    else
    {

    }
}

//Show Camera Unavailable Alert

func alertToEncourageCameraAccessWhenApplicationStarts()
    {
        //Camera not available - Alert
        let cameraUnavailableAlertController = UIAlertController (title: "Camera Unavailable", message: "Please check to see if it is disconnected or in use by another application", preferredStyle: .Alert)

let settingsAction = UIAlertAction(title: "Settings", style: .Destructive) { (_) -> Void in
    let settingsUrl = NSURL(string:UIApplicationOpenSettingsURLString)
    if let url = settingsUrl {
        dispatch_async(dispatch_get_main_queue()) {
            UIApplication.sharedApplication().openURL(url)
        }

    }
}
let cancelAction = UIAlertAction(title: "Okay", style: .Default, handler: nil)
cameraUnavailableAlertController .addAction(settingsAction)
cameraUnavailableAlertController .addAction(cancelAction)
self.window?.rootViewController!.presentViewController(cameraUnavailableAlertController , animated: true, completion: nil)
}
AG
sumber
Ada apa dengan entri Info.plist? Sumber?
Bill