Enable Camera and Mic access in wkwebview

前端 未结 1 2054
盖世英雄少女心
盖世英雄少女心 2020-11-28 09:33

I have a mobile-optimized web app that makes use of getUserMedia to access webcam and mic resources.

I\'m wrapping this app in a WKWebView

相关标签:
1条回答
  • 2020-11-28 10:20

    Yes, take a look at cordova-plugin-iosrtc and cordova-plugin-wkwebview-engine. The idea behind the plugin is as follows:

    1. Create a JavaScript file (WebRTC.js) that defines the various WebRTC classes and functions, and passes the calls to the WKWebView, for example:

    (function() {
      if (!window.navigator) window.navigator = {};
      window.navigator.getUserMedia = function() {
        webkit.messageHandlers.callbackHandler.postMessage(arguments);
      }
    })();
    

    2. In the WKWebView, inject the script at the document start:

    let contentController = WKUserContentController();
    contentController.add(self, name: "callbackHandler")
    
    let script = try! String(contentsOf: Bundle.main.url(forResource: "WebRTC", withExtension: "js")!, encoding: String.Encoding.utf8)
    contentController.addUserScript(WKUserScript(source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true))
    
    let config = WKWebViewConfiguration()
    config.userContentController = contentController
    
    webView = WKWebView(frame: CGRect.zero, configuration: config)
    

    3. Listen for messages sent from the JavaScript:

    class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler {
      var webView: WKWebView!
    
      func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "callbackHandler" {
          print(message.body)
          // make native calls to the WebRTC framework here
        }
      }
    }
    

    4. If success or failure callbacks need to be performed back in JavaScript-land, evaluate the function call directly within the WKWebView:

    webView.evaluateJavaScript("callback({id: \(id), status: 'success', args: ...})", completionHandler: nil)
    

    These callbacks need to be stored in a hash in the JavaScript before calling postMessage, then the hash key must be sent to the WKWebView. This is the commandId in the plugins.

    int exec_id = 0;
    function exec(success, failure, ...) {
      // store the callbacks for later
      if (typeof success == 'function' || typeof failure == 'function') {
        exec_id++;
        exec_callbacks[exec_id] = { success: success, failure: failure };
        var commandId = exec_id;
      }
      webkit.messageHandlers.callbackHandler.postMessage({id: commandId, args: ...})
    }
    
    // the native code calls this directly with the same commandId, so the callbacks can be performed and released
    function callback(opts) {
      if (opts.status == "success") {
        if (typeof exec_callbacks[opts.id].success == 'function') exec_callbacks[opts.id].success(opts.args);
      } else {
        if (typeof exec_callbacks[opts.id].failure == 'function') exec_callbacks[opts.id].failure(opts.args);
      }
      // some WebRTC functions invoke the callbacks multiple times
      // the native Cordova plugin uses setKeepCallbackAs(true)
      if (!opts.keepalive) delete exec_callbacks[opts.id];
    }
    

    5. Of course add the NSCameraUsageDescription and NSMicrophoneUsageDescription permissions to the Info.plist for your project.

    Keep in mind this is a non-trivial task, but that's the general idea behind bridging JavaScript, WKWebView, and native framework code with asynchronous callbacks.

    0 讨论(0)
提交回复
热议问题