Live audio and video over WebRTC is first-class on the mobile web — until it runs inside a WebView. On Android the getUserMedia permission decision is pushed to the host, and on iOS WKWebView ships media capture disabled by default. Most in-app browsers never connect a call. A host-owned runtime bridges real-time media — one API for camera, mic, and peer connection on every engine.
Android: the permission decision is the host's
When a page calls navigator.mediaDevices.getUserMedia, the WebView does not prompt the user. It calls WebChromeClient.onPermissionRequest, and the host must grant or deny. Before granting, the host has to request the Android runtime permissions CAMERA and RECORD_AUDIO and, ideally, verify the origin. If that chain is not wired, the log shows CheckMediaAccessPermission: Not supported and getUserMedia silently rejects with NotAllowedError. The Android documentation is explicit: request the Android runtime permission before calling grant(). So whether a live call connects depends entirely on whether the container implemented the bridge.
iOS: media capture is off by default
iOS 11 brought WebRTC to Safari, but WKWebView does not enable media capture by default. A third-party app must configure it explicitly: add NSCameraUsageDescription and NSMicrophoneUsageDescription to Info.plist, set allowsInlineMediaPlayback = true and mediaTypesRequiringUserActionForPlayback = [], and on iOS 14+ allow capture via WKMediaCapturePermissionsPolicy. Even then, in-app browsers such as WeChat, Douyin, and Facebook often do not enable it, so getUserMedia reports not found. Beyond capture, Agora's Web SDK notes that iOS Safari and WKWebView do not support getDisplayMedia (screen sharing), and when the app backgrounds, AVCaptureSession is not allowed to use the camera, so the remote side sees a black frame; frame-rate control via RTCRTPSender.setParameters is also unavailable.
What breaks when the call goes quiet
- Video support and telehealth stall. The call never acquires the camera.
- Voice rooms and live co-streaming go silent. No microphone stream reaches the peer.
- Screen sharing is unavailable.
getDisplayMediais unsupported on iOS WebView. - Backgrounding kills the call. The camera goes black when the app backgrounds.
- Safari works, WebView does not. A page that connects in Safari fails inside the same device's in-app browser.
The runtime fix
A host-owned runtime bridges the real-time media layer. It wraps getUserMedia with native camera and microphone permissions and exposes one uniform API for camera, mic, and peer connection. The host manages a stable RTCPeerConnection — shared STUN/TURN, ICE handling, and hardware codec negotiation (H.264/VP8) — so a live call connects on every engine and every embedded browser. Permission is requested once, natively; the stream and the connection are consistent.
| Dimension | WebView | Host-owned runtime |
|---|---|---|
| Android permission | Host's onPermissionRequest | Native grant |
| iOS capture | Disabled by default | Native enable |
| Screen sharing | getDisplayMedia unsupported | Native bridge |
| Background camera | Black frame | Host-managed session |
| Peer connection | Per-engine | Uniform |
| Consistency | Per-engine | Uniform |
A native app runs a video call on every phone. A stock WebView runs one on almost none. A runtime gives the page one media surface — and a live peer on the other end.
Sources
- Android Developers — Wrap WebView in Compose — handle
WebChromeClient.onPermissionRequest, requestCAMERA/RECORD_AUDIObeforegrant(), and verify the origin. - WebToApp — Camera & Microphone —
getUserMediain WebView requires build-time flags and usage descriptions on iOS. - webrtc-developers — WebRTC on iOS — WKWebView
getUserMediawas not supported; only Safari until iOS 14.3. - Stack Overflow — WKWebView does not allow camera access — the iOS 14.3+ configuration that makes capture possible in a self-hosted WKWebView.
- Agora — Web SDK known issues — iOS Safari/WKWebView lacks
getDisplayMediaand blacks out the camera on background.