Notalib / nativescript-webview-ext

Nativescript plugin with extended WebView functionality
Apache License 2.0
76 stars 37 forks source link

How to implement onPermissionRequest() ? #78

Open TemaSM opened 4 years ago

TemaSM commented 4 years ago

Hi, thanks for your NS plugin, it's awesome! 👏

I'm trying to implement: WebChromeClient#onPermissionRequest(android.webkit.PermissionRequest) (link to android docs) to simply grant access to microphone and camera into WebView, but with no success 😢

Here's my code snippet (WebViewExt's loadStarted event handler):

let webview = null

// loadStarted event handler
webviewLoadStarted(args) {
  if (!webview) webview = args.object

  // Variant #1
  // extend original WebChromeClient by settings custom `onPermissionRequest()`
  let CustomWebChromeClient = new global.android.webkit.WebChromeClient.extend({
    onPermissionRequest: function (request) {
      // console.log('onPermissionRequest()')
      request.grant(request.getResources())
    }
  })
  webview.nativeViewProtected.setWebChromeClient(new CustomWebChromeClient())

  // Variant #2
  // directly modify `chromeClient's `onPermissionRequest()` function to handle `grant()`
  webview.nativeViewProtected.chromeClient.onPermissionRequest = function (request) {
    // console.log('onPermissionRequest()')
    request.grant(request.getResources())
  }
}

As you can see, I tried with two different variants, but no one works. Important notice - I've already added required permissions to my AndroidManifest.xml and check & request these permissions during app runtime (before WebView loaded):

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MICROPHONE" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera2.autofocus" />
<uses-feature android:name="android.hardware.audio.low_latency" />
<uses-feature android:name="android.hardware.audio.pro" />
<uses-feature android:name="android.hardware.microphone"/>

JS script loaded on page in WebView, still cannot enumerate devices by calling navigator.mediaDevices.getUserMedia(), but prototyped native Android app can get access to these devices. Where am I wrong?

Hope for your quick reply and thanks in advance 😃

m-abs commented 4 years ago

Varient 1 will probably break some of the minor features in the plugin. fullscreen, alerts, console etc.

I don't Variant 2 can work, unless the function is already defined in the JavaScript layer. The android runtime creates a Java wrapper at compile time.

I haven't tried to setup permissions like that in the webview, but I'll see what I can do.

m-abs commented 4 years ago

I think, I've solved it on Android, but I need you to test it and if the test is successful, I need a teammate to review the code. This might take a while since, we're working on a new project.

Install @nota/nativescript-webview-ext@6.5.3-mediadevices.0

You also need to install nativescript-permissions for this to work and add an requestPermissionsEvent. We don't want to depend on the nativescript-permissions, as it is a limited use-case.

    webview.on(WebViewExt.requestPermissionsEvent, (args: RequestPermissionsEventData) => {
        const wantedPerssions = args.permissions
            .map((p) => {
                if (p === "RECORD_AUDIO") {
                    return android.Manifest.permission.RECORD_AUDIO;
                }

                if (p === "CAMERA") {
                    return android.Manifest.permission.CAMERA;
                }

                return p;
            })
            .filter((p) => !!p);

        permissions
            .requestPermissions(wantedPerssions)
            .then(() => args.callback(true))
            .catch(() => args.callback(false));
     });
m-abs commented 4 years ago

According to https://bugs.webkit.org/show_bug.cgi?id=188360 we cannot add support on iOS because WKWebView doesn't support it.

farfromrefug commented 3 years ago

@m-abs could you add it in 8.0.0 ? i have the need for it on android