Two layers of permission
A website asks the browser for the camera; the browser asks the user. An app adds a layer underneath: the APK must declare the Android permission, and Android must grant it to the app, before the WebView can pass a page's request through. The builder's Permissions step (Pro) takes care of the Android side for three capabilities — Location, Camera/files and Microphone — and the app asks the user for the ones you switched on when it starts.
Switch on only what the page uses. Every permission is a line on Google Play's Data safety form and a prompt that makes some users uninstall.
Capability table
| Web API | In the app | Notes |
|---|---|---|
getUserMedia video | Permissions → Camera | Handle NotAllowedError; test on a device |
getUserMedia audio, MediaRecorder | Permissions → Microphone | Same |
navigator.geolocation | Permissions → Location | Declare on Data safety if positions leave the device |
<input type="file"> | Pro builds: system picker, no permission | Free builds do not open a picker |
| localStorage, IndexedDB, Cache API | ✓ no permission | Private to the app; kept across updates |
clipboard.writeText | ✓ from a tap handler | Reading the clipboard is unreliable |
| Device orientation / motion | ✓ no permission | — |
navigator.vibrate | Ignored | The app does not declare VIBRATE |
| Notification API, Web Push | ✗ | Use native push (Pro, via OneSignal) |
navigator.share | ✗ undefined | Copy link, or a https://wa.me/?text= link |
| Web Bluetooth, WebUSB, Web Serial, Web NFC | ✗ | Need a native app |
| Speech recognition | ✗ | Record audio, send it to a speech-to-text API |
File System Access (showOpenFilePicker) | ✗ | Use a file input |
Write code that degrades
A missing API should hide a button, not break the page:
const shareBtn = document.querySelector('#share')
if ('share' in navigator) {
shareBtn.onclick = () => navigator.share({ title: document.title, url: location.href })
} else {
shareBtn.textContent = 'Copy link'
shareBtn.onclick = () => navigator.clipboard.writeText('https://example.com/item/42')
}
Note the hard-coded public URL in the fallback: inside the app, location.href is an appassets.androidplatform.net address that means nothing to anyone you send it to.
Handling a "no"
Users can refuse the prompt at launch, or revoke a permission later in Settings. Every call that needs one must handle failure — getUserMedia rejects, getCurrentPosition calls its error callback — and say, in the page, what the feature is for and how to turn it back on (Settings → Apps → your app → Permissions).
Screen and system UI
- Viewport. Include
<meta name="viewport" content="width=device-width, initial-scale=1">. Without it the WebView lays the page out at desktop width and zooms out. Pinch-zoom is available unless your viewport tag disables it. - Status bar colour comes from the theme colour you set in the builder, not from
<meta name="theme-color">. - Keyboard resizes the visible area; fixed-position footers ride above it. Test forms near the bottom of the screen.