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#
"media": { "audioPlayback": true, "videoPlayback": true, "cameraCapture": true, "microphoneCapture": true, "cameraUsageDescription": "Camera is used for video capture.", "microphoneUsageDescription": "Microphone is used for audio capture."}| Key | What it enables |
|---|---|
audioPlayback / videoPlayback | Play audio / video. |
cameraCapture / microphoneCapture | Capture from the camera / microphone. On Android, microphoneCapture also enables voice recording, see below. |
cameraUsageDescription / microphoneUsageDescription | The 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.
const id = await host.recorder.start() // begins a new recordingawait host.recorder.pause()await host.recorder.resume()const { peak } = { peak: await host.recorder.amplitude() } // 0..32767, for a waveformconst memo = await host.recorder.stop() // { id, url, durationMs, sizeBytes, createdAtMs } await host.recorder.state() // 'idle' | 'recording' | 'paused'await host.recorder.list() // stored recordings, newest firstawait 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
getUserMediaaudio stream while recording; take your level meter fromhost.recorder.amplitude()instead. - A clip too short to encode is discarded and
stop()reports the failure, rather than leaving an unplayable entry inlist().
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)#
"contacts": { "read": true, "write": true }read reads contacts; write creates/updates/deletes them.
photos: photo/video library (Android)#
"photos": { "readImages": true, "readVideos": true }Read the device's photo and video library (distinct from live media capture).
telephony: calling (Android)#
"telephony": { "placeCalls": true, "readCallState": true, "defaultDialer": false }| Key | What it enables |
|---|---|
placeCalls | Place outgoing calls. |
readCallState | Read call state. |
defaultDialer | Act as the device's default dialer. |
messaging: SMS (Android)#
"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)#
"alarm": { "alarms": true }Schedule real alarms that ring over the lock screen and survive reboot.
launcher: home launcher (Android)#
"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).
"host": { "actions": true, "vault": true, "fs": true }| Key | What it enables |
|---|---|
actions | Agent action helpers (host.actions). |
env | Read non-secret env values (window.host.env). Required to use the top-level env block. |
vault | Secure secret storage (window.host.vault). |
fs / path | Filesystem access / path helpers. |
intent | Android intents (launch / take-pending). |
shell | Shell 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.