5

In my app, I have a WKWebView loading a website with file input that allows a user to upload images via the Camera or the Photo Library.

My app has both privacy usage descriptions for the Camera and Photo Library.

If a user has denied access to the Camera, the WKWebView will still show the option to upload images via the Camera, and the Camera modal presents (though it only shows black where you'd normally see an image of what the camera is showing). If a user swipes to the Video option in the Camera modal, the app crashes.

The relevant stack trace shows:

3   TCC __TCCAccessRequest_block_invoke_2.80 + 222
4   TCC __CRASHING_DUE_TO_PRIVACY_VIOLATION__ + 682

Is it possible from the native app side (suppose I can't edit the HTML loaded) to prevent the WKWebView from presenting the Camera modal in this case?

Nazim Kerimbekov
  • 4,712
  • 8
  • 34
  • 58
M-P
  • 4,909
  • 3
  • 25
  • 31

2 Answers2

2

Because you mentioned __CRASHING_DUE_TO_PRIVACY_VIOLATION__ the app is probably actually crashing because you haven't added the iOS10 permission description for using the microphone. The camera view will trigger this additional microphone permissions popup if you choose Video. In iOS10, you must fill in the description that is presented to the user or the app will crash as you have reported. In iOS9, it just presents the generic permissions popup.

Try adding a description for the key NSMicrophoneUsageDescription in your Info.plist file. In Xcode this is called Privacy - Microphone Usage Description

This other answer will give you more details of the various privacy keys and their descriptions.

Joe Schofield
  • 124
  • 1
  • 4
1

It'd appear to be a bug since it only crashes when Video is selected. I found a workaround by injecting JS:

  • Set the content type to only allow photos. (sample code included below)
  • Delete/Hide the input-file
  • Disable the input-file
func requestCamera() {
    AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { response in
        if response {
            self.injectJavascript()
        } else {
            self.webView = WKWebView(frame: .zero)
        }


        self.setupRequest()
    }
}

func injectJavascript() {
    let webConfiguration = WKWebViewConfiguration()
    let contentController = WKUserContentController()
    let js = "var fileInput = document.getElementById('allMedia'); fileInput.setAttribute('accept', 'image/*');"
    let userScript = WKUserScript(source: js, injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: false)
    contentController.addUserScript(userScript)
    webConfiguration.userContentController = contentController
    webView = WKWebView(frame: .zero, configuration: webConfiguration)
}

func setupRequest() {
    let url = URL(string: "...")!
    let request = URLRequest(url: url)
    webView.load(request)
}

Flow is as follows:

  1. Camera access allowed ?
    • Yes
      1. Load WKWebView normally
    • No
      1. Inject JS
      2. Setup WKWebView
      3. Load WKWebView's request
nathan
  • 9,329
  • 4
  • 37
  • 51
  • This is an interesting workaround. I up-voted since it can help resolve the crash, but I'll wait to accept in case anyone else has an answer that may solve the core issue. Thanks for the response! – M-P Aug 08 '17 at 15:27
  • Awesome. I sent a bug report just in case, will update the post if I have any answer from the Support Team – nathan Aug 08 '17 at 15:29