ตรวจสอบการอนุญาตของกล้องใน iOS


143

ฉันกำลังพัฒนาแอพวิดีโอที่ง่ายมาก ฉันใช้การควบคุมอย่างเป็นทางการ: UIImagePickerController

นี่คือปัญหา เมื่อนำเสนอ UIImagePickerController เป็นครั้งแรก iOS จะขออนุญาต ผู้ใช้สามารถคลิกใช่หรือไม่ หากผู้ใช้คลิกไม่การควบคุมจะไม่ถูกยกเลิก หากผู้ใช้คลิกปุ่มเริ่มต่อไปตัวจับเวลาจะดำเนินต่อไปในขณะที่หน้าจอเป็นสีดำเสมอและผู้ใช้จะไม่สามารถหยุดตัวจับเวลาหรือย้อนกลับได้ สิ่งเดียวที่ผู้ใช้สามารถทำได้คือฆ่าแอพ ครั้งต่อไปที่มีการนำเสนอ UIImagePickerController จะยังคงเป็นหน้าจอสีดำและผู้ใช้ไม่สามารถย้อนกลับไปได้หากคลิกเริ่ม

ฉันสงสัยว่ามันเป็นแมลงหรือเปล่า มีวิธีใดบ้างที่เราสามารถตรวจพบการอนุญาตของกล้องเพื่อให้เราสามารถตัดสินใจแสดง UIImagePickerController ได้หรือไม่?


Re: มันเป็นข้อผิดพลาดหรือไม่? IMHO ฉันคิดอย่างนั้นเพราะสิ่งที่ดูเหมือนจะเกิดขึ้นคือ VC กำลังแสดงข้อมูลจากฮาร์ดแวร์ แต่ระบบปฏิบัติการโดยทั่วไปกำลังส่งอากาศที่ตายแล้ว วิธีที่ iOS มาถึงที่นี่น่าจะเป็นผลข้างเคียงของวิวัฒนาการของตระกูลผลิตภัณฑ์ UIImageViewControllerถูกบันทึกว่ามีการเพิ่มใน iOS 2.0 และเอกสารไม่เคยมีคำอธิบายประกอบเพื่อสะท้อนว่าควรใช้ AVAuthorizationStatus แต่อาศัยอยู่ในกรอบอื่น
benc

คำตอบ:


229

ตรวจสอบ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
}

19
ต้องการ: #import <AVFoundation/AVFoundation.h>หรือคล้ายกัน
toblerpwn

9
เคล็ดลับที่มีประโยชน์ที่เป็นไปได้ - หากคุณกำลังทดสอบโค้ดที่ใช้สิ่งนี้คุณจะไม่สามารถลบแอพของคุณออกจากอุปกรณ์ทดสอบแล้วทำการติดตั้งใหม่ การทำเช่นนี้จะไม่ทำให้ iOS ส่งคำขอไปยังผู้ใช้อีกครั้ง! สิ่งที่ใช้ได้ผลสำหรับฉันคือการเปลี่ยนBundle IDแอพทุกครั้งที่ฉันต้องการทดสอบ ความเจ็บปวดในก้น แต่อย่างน้อย ก็อย่าลืมตั้งค่ากลับ ID เมื่อคุณเสร็จสิ้น ;-)
Benjohn

25
@Benjohn: การเปลี่ยน Bundle ID นั้นไม่จำเป็น คุณสามารถไปที่การตั้งค่า> ทั่วไป> รีเซ็ตและค้นหาการตั้งค่าที่จะรีเซ็ตพรอมต์การอนุญาตทั้งหมดบนอุปกรณ์ จริงอยู่ที่มันน่ารำคาญเพราะมันมีผลต่อแอพอื่น ๆ ทั้งหมดในอุปกรณ์ของคุณเช่นกัน ถ้ามีเพียง Apple เท่านั้นที่สามารถเพิ่มการควบคุมเฉพาะแอพสำหรับสิ่งนี้ได้ในหัวข้อการพัฒนาของ Settings.app ...
KennyDeriemaeker

3
@KennyDeriemaeker :-) Apple อาจตอบว่าเราควรใช้อุปกรณ์เฉพาะสำหรับการทดสอบ! สำหรับฉันผลข้างเคียงของการรีเซ็ตโทรศัพท์ปกติของฉันน่าจะแย่มาก การเปลี่ยนบันเดิลรหัสเป็นทางเลือกที่ไม่เจ็บปวดพอสมควร ผมจำได้เปลี่ยนกลับก่อนที่จะส่งเกินไป :-)
Benjohn

8
ตรวจสอบให้แน่ใจว่าคุณไม่ได้ทำการรีเซ็ตแบบสมบูรณ์! เพียงรีเซ็ตการตั้งค่าความเป็นส่วนตัวและตำแหน่ง (iOS 8) ก็พอเพียง
Canucklesandwich

81

Swift 4 และใหม่กว่า

ตรวจสอบให้แน่ใจว่า:

import AVFoundation

รหัสด้านล่างตรวจสอบสถานะการอนุญาตที่เป็นไปได้ทั้งหมด:

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

ตั้งแต่ iOS 10 คุณต้องระบุ NSCameraUsageDescriptionคีย์ใน Info.plist ของคุณเพื่อให้สามารถเข้าถึงกล้องได้มิฉะนั้นแอปของคุณจะทำงานล้มเหลวขณะรันไทม์ ดูAPIs การกำหนดรายละเอียดการใช้งาน


ในฐานะที่เป็นบันทึกย่อด้านที่น่าสนใจคุณรู้หรือไม่ว่า iOS ฆ่าแอปถ้ามันทำงานในขณะที่คุณเปลี่ยนการอนุญาตของกล้องในการตั้งค่า?

จากฟอรัม Apple Developer:

ระบบจะฆ่าแอปของคุณหากผู้ใช้สลับการเข้าถึงกล้องของแอพในการตั้งค่า เช่นเดียวกับดาต้าคลาสที่ได้รับการป้องกันในส่วนการตั้งค่า→ความเป็นส่วนตัว


แล้วการให้สิทธิ์กล้องและแกลเลอรี่รูปภาพล่ะ?
Hajar ELKOUMIKHI

4

โซลูชันที่รวดเร็ว

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

และจากนั้นเพื่อที่จะใช้คุณทำ

AVCaptureDevice.authorizeVideo(completion: { (status) in
   //Your work here
})

แล้วการให้สิทธิ์กล้องและแกลเลอรี่รูปภาพล่ะ?
Hajar ELKOUMIKHI

2

นอกเหนือจากคำตอบจาก @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
                }
            }
        }
    }
}

ในกรณีที่ถูกปฏิเสธเมธอด requestAccess จะไม่ทำงาน คุณจะต้องแสดงการแจ้งเตือนด้วยตนเองเพื่อขอให้ผู้ใช้ไปที่การตั้งค่าและให้สิทธิ์
อับดุลลาห์

0

ระบุคีย์ NSCameraUsageDescription ใน Info.plist ก่อน จากนั้นตรวจสอบ AVAuthorizationStatus หากได้รับอนุญาตจากนั้นแสดง UIImagePickerController มันจะทำงาน.


-4

Swift: การใช้ AVFoundation

  1. เพิ่ม AVFoundation ไปยังเป้าหมาย -> สร้างเฟส -> เชื่อมโยงไบนารีกับไลบรารี
  2. นำเข้า AVFoundation บน ViewController
  3. บน Info.plist เพิ่มสิ่งต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

  1. บนตัวควบคุมมุมมอง:

@IBAction func cameraButtonClicked (ผู้ส่ง: 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)
}

อะไรคือรายการ Info.plist แหล่งที่มา?
Bill
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.