MediaDevices.getUserMedia() permission denied in webview while camera is allowed

Hi everyone, I’m trying to use MediaDevices.getUserMedia() api in my webview app, but after a lot of effort I keep getting “permission denied” error even though camera access is allowed, here is what i added

app.module.ts

import { AndroidPermissions } from '@ionic-native/android-permissions/ngx';
...
providers: [    
AndroidPermissions,
]

app.component.ts

this.androidPermissions.checkPermission(this.androidPermissions.PERMISSION.CAMERA).then(
        result => console.log('Has permission?',result.hasPermission),
        err => this.androidPermissions.requestPermission(this.androidPermissions.PERMISSION.CAMERA)
      );
      
      this.androidPermissions.requestPermissions([this.androidPermissions.PERMISSION.CAMERA]);

config.xml

<plugin name="cordova-plugin-android-permissions" spec="1.1.2" />

AndroidManifest.xml

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

angular.json

"scripts": [
              "node_modules/webrtc-adapter/out/adapter.js"
            ]

In my web use api

function startVideo() {
     const constraints = { audio: false, video: { facingMode: "user" } }
     navigator.mediaDevices.getUserMedia(constraints)
     .then(function(mediaStream) {
     window.stream = mediaStream; 
     video.srcObject = mediaStream;
     video.onloadedmetadata = function(e) {
               video.play();
      };
     })
     .catch(function(err) { showAlert(err.name + ": " + err.message); });
}

It working on browser but not in my ionic app
Can anyone point out where I am missing?

I’ve tried your code and it’s working fine on my device.
You don’t even need to request the permission, that’s handled by the WebView as long as you have it in the AndroidManifest.xml

I’m not sure how relevant this is, but there are two words I see in your snippet that I don’t like seeing in Ionic apps: window and function.

A better alternative to polluting window is to use service providers to communicate across parts of the app. Arrow functions are more robust than old-school function functions, protecting you from situations where this isn’t what you think it is.

I’m similarly nervous about the reference to an off-screen video variable that is presumably some other global.

I still don’t understand why I get permission error on both my android devices even though I see permission is allowed

Was you able to resolve this issue? I have the same problem

Hi, if you use inappbrowser, set the option to _self it will work

Hi, i am facing the same issue with microphone permission. Please help me with the solution as i didnt understand it.

are you using cordova or capacitor? and if you use inappbrowser plugin have you tried set option=“_self”, tell me more about your case

In our platform, we record and analyze audio. To record the audio, we utilize the AudioContext and MediaStream by obtaining microphone permissions from the user. Therefore, when the user clicks to initiate audio recording, the browser prompts for microphone permission.
we have integrated our website into the Android application using WebView, which is a native Android application.
However, a challenge arises wherein the prompt for microphone permission does not appear when the user clicks the record button on the Android app. Consequently, we are unable to acquire the necessary user permission. We are using navigator.mediaDevice.getUserMedia API in javascript to get permission for the microphone.

MainActivity.kt

class MainActivity : ComponentActivity() {
    private lateinit var webView: WebView
    private val RECORD_AUDIO_PERMISSION_CODE = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        webView = findViewById(R.id.webView)
        webView.webViewClient = WebViewClient()
        webView.loadUrl("https://webapp.io")

        val webSettings: WebSettings = webView.settings
        webSettings.javaScriptEnabled = true
        webSettings.domStorageEnabled =true

        WebView.setWebContentsDebuggingEnabled(true)

        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.RECORD_AUDIO
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            println("DEBUG -> checking permission")
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.RECORD_AUDIO),
                RECORD_AUDIO_PERMISSION_CODE
            )
        }
    }


    // Handle permission request result
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == RECORD_AUDIO_PERMISSION_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted, you can inform your WebView or handle the logic accordingly
                println("DEBUG -> Permission granted.")
                webView.evaluateJavascript("requestPermission()") { result ->
                    // Handle the JavaScript function's result if needed
                    println("DEBUG -> ${result}")
                }
            } else {
                println("DEBUG -> Permission denied.")
                // Permission denied, handle accordingly (e.g., show a message)
            }
        }
    }
}

AndroidManifest.xml

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

ActivityMain.xml

  <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

js in website

window.requestPermission = () => {
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({ audio: true })
            .then(function (stream) {
                // Handle the media stream, e.g., start recording
                console.log("Start streaming.. ", stream);
            })
            .catch(function (error) {
                console.error('Media access error:', error);
            });
    } else {
        console.error('getUserMedia is not supported');
    }
}

You are using native android but the topic of the question is about Ionic.

have you granted micro permission in android manifest:

I had this problem before, and the cause of it was inappbrowser plugin, I think the cause maybe come from your webview settings

What does it show after you call mediaDevices.getUserMedia? otherwise it’s best to call the api directly when you trigger an event that needs audio access like: button.onclick = () => {
navigator.mediaDevices.getUserMedia({ audio: true })}

and let try on your real device

Vào 11:51 CH, CN, 27 thg 8, 2023 Sahushivam168 via Ionic Forum <notifications@ionicframework.discoursemail.com> đã viết: