首页 > 解决方案 > 如何优雅地处理 AVCaptureDeviceInput.init 中的拒绝授权?

问题描述

文档将AVCaptureDeviceInput.init(device:)其参数记录为:

device 从中捕获输入的设备。

outError 如果在初始化期间发生错误,则返回时包含NSError描述问题的对象。

这个outError输出参数在 Swift 中表示为 throwed Error。我可以像这样捕捉并显示它:

do {
    let deviceInput = try AVCaptureDeviceInput(device: device)
    // ...
}
catch {
    print("Error: \(error)")
}

我想优雅地处理一种特殊情况:当用户拒绝授权应用程序使用相机时。在这种情况下,我得到以下输出:

Error: Error Domain=AVFoundationErrorDomain Code=-11852 "Cannot use FaceTime HD Camera (Built-in)" UserInfo={NSLocalizedFailureReason=This app is not authorized to use FaceTime HD Camera (Built-in)., AVErrorDeviceKey=<AVCaptureDALDevice: 0x100520a60 [FaceTime HD Camera (Built-in)][0x8020000005ac8514]>, NSLocalizedDescription=Cannot use FaceTime HD Camera (Built-in)}

我需要将此错误类型与其他意外错误区分开来,如下所示:

do {
    let deviceInput = try AVCaptureDeviceInput(device: device)
    // ...
}
catch AVError.Code.applicationIsNotAuthorizedToUseDevice {
  // Expected error, handle gracefully
  errorMessageBox(errorText: "You have denied authorization to access your camera. Fix this in System Preferences > Security & Privacy.")
}
catch {
  // Unexpected errors
  errorMessageBox("Error: \(error)")
}

这是伪代码,无法编译。我知道错误代码-11852AVError.Code.applicationIsNotAuthorizedToUseDevice. 但是,我不知道如何从不透明error对象中获取错误代码以对其进行测试。

抛出的错误的具体类型是AVCaptureDeviceInput.init(device:)什么?如何从中提取AVError.Code以处理此特定错误?

标签: swiftavfoundation

解决方案


有两种可能的方法。一种是在您尝试之前进行检查,例如

if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
    offerToOpenSettings()
    return
}

另一种方法是catch未授权错误:

let input: AVCaptureDeviceInput
do {
    input = try AVCaptureDeviceInput(device: camera)
} catch AVError.applicationIsNotAuthorizedToUseDevice {
    offerToOpenSettings()
    return
} catch {
    print("some other error", error)
    return
}

请注意,这是捕捉AVError.applicationIsNotAuthorizedToUseDevice,而不是AVError.Code.applicationIsNotAuthorizedToUseDevice.

例如,如果这是一个 iOS 应用程序,您可以提供一个功能来将用户重定向到设置应用程序:

func offerToOpenSettings() {
    guard
        let settings = URL(string: UIApplication.openSettingsURLString),
        UIApplication.shared.canOpenURL(settings)
    else { return }

    let alert = UIAlertController(title: nil, message: "Would you like to open Settings to enable permission to use the camera?", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
        UIApplication.shared.open(settings)
    })
    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))

    present(alert, animated: true)
}

请注意,由于这可能会显示警报,因此您不想触发它viewDidLoad(这在此过程中为时过早),而是viewDidAppear.

或者,在 macOS 上,可能类似于:

func offerToOpenSettings() {
    let preferences = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Camera")!
    let alert = NSAlert()
    alert.messageText = #"The camera is disabled. Please go to the “Camera” section in Security System Preferences, and enable this app."#
    alert.addButton(withTitle: "System Preferences")
    alert.addButton(withTitle: "Cancel")
    if alert.runModal() == .alertFirstButtonReturn {
        NSWorkspace.shared.open(preferences)
    }
}

推荐阅读