Summary
navigator.mediaDevices.getUserMedia() fails on Android even when the app has RECORD_AUDIO granted in system settings.
Two separate gaps in the stock Android WebView setup cause this:
WebChromeClient.onPermissionRequest is not implemented — the WebView never grants RESOURCE_AUDIO_CAPTURE to web content, so getUserMedia() rejects with NotAllowedError: Permission denied.
MODIFY_AUDIO_SETTINGS is missing from the merged manifest when RECORD_AUDIO is present — after fixing (1), Chromium logs Unable to select communication device! and getUserMedia() fails with NotReadableError: Could not start audio source (common when echoCancellation is requested or on recent WebView/Chromium builds).
Steps to reproduce
- Create a NativePHP Mobile app with microphone access (
RECORD_AUDIO in the built manifest, e.g. via a plugin or manual manifest entry).
- Grant microphone permission in Android app settings.
- From JavaScript in the WebView, call:
await navigator.mediaDevices.getUserMedia({ audio: true });
- Observe console / logcat.
Expected behavior
Microphone capture starts; getUserMedia() resolves with a MediaStream.
Actual behavior
Without onPermissionRequest:
NotAllowedError: Permission denied
No onPermissionRequest callback is logged.
After adding onPermissionRequest manually (still without MODIFY_AUDIO_SETTINGS):
E chromium: [ERROR:media/audio/android/audio_manager_android.cc:876] Unable to select communication device!
NotReadableError: Could not start audio source
Environment
- Device: Google Pixel 7, Android 16
- WebView: Chrome 148 / Android System WebView 148
- NativePHP Mobile: 3.x (
nativephp/mobile ^3.3)
- Reproduced with Livewire + Alpine.js voice recording via Web Audio API (
getUserMedia + AudioWorkletNode)
Proposed fix
- Implement
onPermissionRequest in WebViewManager.createWebChromeClient(), granting capture resources when the matching Android runtime permission is already held.
- When merging plugin manifest permissions, also inject
android.permission.MODIFY_AUDIO_SETTINGS whenever android.permission.RECORD_AUDIO is present (Chromium needs this for WebView audio routing / communication device selection).
Happy to submit a PR if this approach looks good.
Summary
navigator.mediaDevices.getUserMedia()fails on Android even when the app hasRECORD_AUDIOgranted in system settings.Two separate gaps in the stock Android WebView setup cause this:
WebChromeClient.onPermissionRequestis not implemented — the WebView never grantsRESOURCE_AUDIO_CAPTUREto web content, sogetUserMedia()rejects withNotAllowedError: Permission denied.MODIFY_AUDIO_SETTINGSis missing from the merged manifest whenRECORD_AUDIOis present — after fixing (1), Chromium logsUnable to select communication device!andgetUserMedia()fails withNotReadableError: Could not start audio source(common whenechoCancellationis requested or on recent WebView/Chromium builds).Steps to reproduce
RECORD_AUDIOin the built manifest, e.g. via a plugin or manual manifest entry).Expected behavior
Microphone capture starts;
getUserMedia()resolves with aMediaStream.Actual behavior
Without
onPermissionRequest:No
onPermissionRequestcallback is logged.After adding
onPermissionRequestmanually (still withoutMODIFY_AUDIO_SETTINGS):Environment
nativephp/mobile^3.3)getUserMedia+AudioWorkletNode)Proposed fix
onPermissionRequestinWebViewManager.createWebChromeClient(), granting capture resources when the matching Android runtime permission is already held.android.permission.MODIFY_AUDIO_SETTINGSwheneverandroid.permission.RECORD_AUDIOis present (Chromium needs this for WebView audio routing / communication device selection).Happy to submit a PR if this approach looks good.