Inside a WebView, a web page asking for the camera or location must pass two separate gates — the OS permission and the WebView permission — and on Android the default is to deny the second one if the app does not implement the callback. Worse, Android's WebView gives the embedding app full control over web permission handling with no per-site consent like a real browser: once the OS grant exists, the app can share location or camera with any page in the WebView without another prompt. On iOS, WKWebView adds a second prompt on top of the app's, and in-app browsers like TikTok and Instagram are officially unsupported. A host-owned runtime ships one permission broker that maps native and web consent, enforces per-origin grants, requires a secure context, and shows one consistent prompt.

Two gates, and the second one defaults to no

On Android, a page calling getUserMedia or navigator.geolocation hits two checks. First the OS permission — CAMERA, RECORD_AUDIO, or location declared in the manifest and granted at runtime (API 23+). Then the WebView permission: even with the OS grant, the page surfaces to the app as WebChromeClient.onPermissionRequest (camera/mic) or onGeolocationPermissionsShowPrompt (location), and the default answer is no. Skip implementing the callback and the symptom is baffling — permission granted, getUserMedia called, nothing happens, no dialog, a rejected promise. Geolocation is only called for secure origins on apps targeting Android 7.0+, so an HTTP page is denied before anyone taps anything.

No per-site consent, unlike a browser

A 2025 study of Android's WebView permission enforcement shows the structural gap: traditional browsers prompt per site and let users grant or deny each one, but Android's WebView delegates the entire decision to the embedding app. If the app implements the callback, it can grant or deny for any origin, and there is no built-in per-site memory or user-facing control. The deeper risk is that once the OS location permission is granted to the app, the app can hand that location to any website loaded in the WebView without further user consent — the user cannot see which page is accessing what. Developers must build that consent UX themselves, or it does not exist.

iOS: a second prompt, and silent downgrades

On iOS, WKWebView's camera and microphone access requires the app to implement requestMediaCapturePermissionFor (iOS 15+) and the relevant entitlements; before that, WebRTC was simply unavailable in WKWebView. Even when implemented, the user sees two prompts — one from the app, one from the site — and the documented workaround is for the app to skip the second via a delegate, which means the user's per-page choice is decided by the app, not the page. When the page is loaded through a custom scheme handler, the prompt shows the app's name as the origin, which users find confusing. In-app browsers (Instagram, TikTok) carry additional constraints and broken UI and are explicitly not supported.

What you lose without a permission broker

  • A single source of truth. Native and web permission states live in different places; they drift and contradict.
  • Per-origin control. Android WebView has no per-site grant memory; the app either grants everything or denies everything.
  • User visibility. The user cannot tell which page is accessing the camera or location, because the consent lives in app code.
  • Secure-context enforcement. An HTTP page silently loses geolocation on modern Android, with no visible reason.
  • A consistent prompt. iOS double prompts; in-app browsers break entirely.

The runtime fix

A host-owned runtime ships one permission broker below the page. It keeps a single, unified consent store for native and web, enforces per-origin grants the way a browser does, requires a secure context before any sensitive API is offered, and presents one consistent, user-readable prompt that names the page and the resource. The app's OS grant and the page's web request are reconciled in one place, so consent is visible, revocable, and never silently shared with an unknown origin.

DimensionWebViewHost-owned runtime
Consent modelApp decides everything, no per-site memoryUnified store, per-origin grants
Android gate 2onPermissionRequest default deniesBroker grants per origin, visible
iOS promptsTwo prompts, app can skip site promptOne consistent prompt
Secure contextHTTP geolocation auto-denied, silentEnforced, explained
User visibilityCannot see which page accesses whatPrompt names page and resource
In-app browsersUnsupported, broken UIOne runtime, supported everywhere

A browser earns trust by asking the right question, to the right party, at the right moment. A stock WebView pushes that decision into opaque app code and then defaults to no. A runtime restores the browser's consent contract — per origin, visible, and revocable — so a page that needs the camera gets a prompt the user actually understands.

Sources