Capabilities

By default your app has no special device permissions. Request only what it needs by adding capability blocks to waid.config.json. WAID then declares the matching OS permissions and wires up the native glue. Every flag defaults off.

Most capabilities are Android features today. They are ignored (or rejected) by the iOS/desktop packagers, as noted per block.

media: audio, video, camera, microphone#

json
"media": {
"audioPlayback": true,
"videoPlayback": true,
"cameraCapture": true,
"microphoneCapture": true,
"cameraUsageDescription": "Camera is used for video capture.",
"microphoneUsageDescription": "Microphone is used for audio capture."
}
KeyWhat it enables
audioPlayback / videoPlaybackPlay audio / video.
cameraCapture / microphoneCaptureCapture from the camera / microphone. On Android, microphoneCapture also enables voice recording, see below.
cameraUsageDescription / microphoneUsageDescriptionThe permission-prompt text on Apple platforms (defaults to a product-name string).

Voice recording (host.recorder)#

microphoneCapture also gives an Android app the host.recorder API. There is no separate capability key: recording needs exactly the microphone permission this flag already grants.

js
const id = await host.recorder.start() // begins a new recording
await host.recorder.pause()
await host.recorder.resume()
const { peak } = { peak: await host.recorder.amplitude() } // 0..32767, for a waveform
const memo = await host.recorder.stop() // { id, url, durationMs, sizeBytes, createdAtMs }
 
await host.recorder.state() // 'idle' | 'recording' | 'paused'
await host.recorder.list() // stored recordings, newest first
await host.recorder.remove(id)

Recordings are encoded to AAC .m4a in app-private storage, so they need no storage permission and are invisible to other apps. stop() returns a file:// URL you can hand straight to an <audio> element.

Three behaviours to design around:

  • The first start() raises the permission prompt and fails. Nothing else in a recorder app triggers one. The grant is asynchronous, so the user records on the next tap, so treat it as a prompt, not an error.
  • The microphone is exclusive. Don't hold a getUserMedia audio stream while recording; take your level meter from host.recorder.amplitude() instead.
  • A clip too short to encode is discarded and stop() reports the failure, rather than leaving an unplayable entry in list().

On iOS and desktop the API exists but reports NotSupportedError for capture, while list() and state() degrade quietly so a recorder UI still renders.

contacts: device contacts (Android)#

json
"contacts": { "read": true, "write": true }

read reads contacts; write creates/updates/deletes them.

photos: photo/video library (Android)#

json
"photos": { "readImages": true, "readVideos": true }

Read the device's photo and video library (distinct from live media capture).

telephony: calling (Android)#

json
"telephony": { "placeCalls": true, "readCallState": true, "defaultDialer": false }
KeyWhat it enables
placeCallsPlace outgoing calls.
readCallStateRead call state.
defaultDialerAct as the device's default dialer.

messaging: SMS (Android)#

json
"messaging": { "send": true, "read": true, "receive": true, "defaultSmsApp": false }

Send, read, and receive SMS; defaultSmsApp makes your app the default SMS app (plain SMS, no MMS).

alarm: background alarms (Android)#

json
"alarm": { "alarms": true }

Schedule real alarms that ring over the lock screen and survive reboot.

launcher: home launcher (Android)#

json
"launcher": { "homeLauncher": true, "launches": ["com.acme.other"] }

Let your app be the device home screen. launches lists the package ids it may open.

launches entries are literal package-id strings. If you rename another app's packageName, update the references here by hand; they aren't auto-updated.

host: host functions#

Native host functions your app can call. Available on desktop and Android; iOS rejects host capabilities (the build fails if declared).

json
"host": { "actions": true, "vault": true, "fs": true }
KeyWhat it enables
actionsAgent action helpers (host.actions).
envRead non-secret env values (window.host.env). Required to use the top-level env block.
vaultSecure secret storage (window.host.vault).
fs / pathFilesystem access / path helpers.
intentAndroid intents (launch / take-pending).
shellShell execution. Desktop only, rejected on mobile.

Put secrets in the runtime vault, never in waid.config.json. The env block is for non-secret values only.