Mobile
Mobile Capabilities
Zornux mobile apps access device features through built-in capability APIs. The toolchain detects which capabilities your code uses, generates the native runtime helpers, and wires the Android permissions automatically.
Permissions
Capabilities that require user consent — camera, location, notifications —
must be declared with a permissions block. The semantic
analyzer refuses to compile a capability call without a matching
permission:
mobile app "PhotoApp"
permissions
camera because "Take product photos"
location while using app because "Tag photos with where they were taken"
notifications because "Notify when uploads finish"
end
| Capability | Permission syntax |
|---|---|
| Camera | camera because "reason" |
| Location | location while using app because "reason" |
| Notifications | notifications because "reason" |
If your code calls camera.take_photo() but the permissions block does not declare camera, zornux check reports a diagnostic and the build fails. The rationale string is shown to the user at runtime when Android requests consent.
The while using app access level applies only to
location. Camera and notification permissions do not take an
access modifier.
Camera
Take a photo with the device camera or pick one from the gallery:
screen PhotoScreen
state photo = ""
column
button "Take photo"
when tapped
photo = camera.take_photo()
end
end
button "Choose from gallery"
when tapped
photo = camera.choose_photo()
end
end
if photo is not ""
text "Photo captured!"
end
end
end
Check whether a camera is available before offering the button:
if camera.is_available()
button "Take photo"
when tapped
photo = camera.take_photo()
end
end
end
Location
Read the device's current GPS coordinates:
screen LocationScreen
state position = ""
column
button "Where am I?"
when tapped
position = location.get_current()
end
end
text position
end
end
Notifications
Send an immediate notification or schedule one for later:
button "Notify now"
when tapped
notifications.send("Reminder", "Time to check in!")
end
end
button "Notify in 60 seconds"
when tapped
notifications.schedule("Reminder", "One minute has passed", 60)
end
end
Secure storage
Store sensitive values (tokens, keys) in the platform's encrypted keystore. No permission declaration needed:
screen TokenScreen
state token = ""
when screen opens
token = secure_storage.get("auth_token")
end
column
text "Token: " + token
button "Save new token"
when tapped
secure_storage.save("auth_token", "abc123")
show "Token saved"
end
end
button "Clear token"
when tapped
secure_storage.remove("auth_token")
token = ""
end
end
end
end
| Method | Purpose |
|---|---|
secure_storage.save(key, value) | Encrypt and store a value. |
secure_storage.get(key) | Retrieve a stored value. |
secure_storage.remove(key) | Delete a stored value. |
Biometrics
Prompt the user for fingerprint or face authentication. The result indicates whether authentication succeeded:
screen SecureScreen
state authenticated = false
column
if authenticated
text "Access granted"
else
button "Authenticate"
when tapped
authenticated = biometrics.authenticate("Confirm your identity")
end
end
end
end
end
Check whether biometric hardware is available with
biometrics.is_available():
if biometrics.is_available()
button "Use fingerprint"
when tapped
authenticated = biometrics.authenticate("Unlock with fingerprint")
end
end
else
text "Biometrics not available on this device"
end
HTTP
Make network requests with the http object. Requests run
asynchronously and return the response body:
screen ApiScreen
state data = ""
when screen opens
data = http.get("https://api.example.com/items")
end
column
text data
end
end
All standard HTTP methods are available:
| Method | Usage |
|---|---|
http.get(url) | GET request. |
http.post(url) | POST request. |
http.put(url) | PUT request. |
http.delete(url) | DELETE request. |
Cleartext HTTP is disabled by default. Set android.allow_cleartext = true in zornux.project for development against a local server — never ship with this enabled.
Local storage
Persist simple key-value data (preferences, drafts, settings) across app restarts. Unlike secure storage, this is not encrypted — use it for non-sensitive data:
screen NotesScreen
state note = ""
when screen opens
note = store.load("saved_note")
end
column
input note "Write a note..."
button "Save"
when tapped
store.save("saved_note", note)
show "Note saved"
end
end
end
end
| Method | Purpose |
|---|---|
store.save(key, value) | Write a value to local storage. |
store.load(key) | Read a value back. |
Files
Let the user pick a file from their device:
button "Choose a file"
when tapped
create file = files.choose("application/pdf")
end
end
Sharing
Share text or a file through the system share sheet:
button "Share text"
when tapped
share.text("Check out this app!")
end
end
button "Share file"
when tapped
share.file(filePath)
end
end
Connectivity
Check whether the device is online before making network calls:
if connectivity.is_online()
data = http.get("https://api.example.com/sync")
else
show "No internet connection"
end
Capability reference
Every built-in capability, whether it requires a permission declaration, and the generated Android runtime helper:
| Capability | Methods | Permission required |
|---|---|---|
| Camera | take_photo(), choose_photo(), is_available() | Yes |
| Location | get_current() | Yes |
| Notifications | send(title, msg), schedule(title, msg, delay) | Yes |
| Secure storage | save(key, val), get(key), remove(key) | No |
| Biometrics | authenticate(msg), is_available() | No |
| HTTP | get(url), post(url), put(url), delete(url) | No |
| Local storage | save(key, val), load(key) | No |
| Files | choose(mimeType) | No |
| Sharing | text(text), file(path) | No |
| Connectivity | is_online() | No |
Native extensions
When a built-in capability is not enough, native extensions let you call
Kotlin code from Zornux. An extension is a directory under
.zornux/extensions/ with a manifest and a Kotlin runtime
file:
.zornux/extensions/
barcode-scanner/
mobile-extension.json
BarcodeScanner.kt
Extension manifest
The mobile-extension.json declares the extension's name,
version, operations, dependencies, and Android permissions:
{
"name": "barcode-scanner",
"version": "1.0.0",
"platform": "android",
"operations": [
{
"name": "scan",
"returns": "Text",
"async": true,
"parameters": [],
"description": "Scan a barcode and return its value"
}
],
"android": {
"dependencies": [
{ "group": "com.google.mlkit", "artifact": "barcode-scanning", "version": "17.3.0" }
],
"permissions": ["CAMERA"],
"runtime": "BarcodeScanner.kt"
}
}
Calling an extension
In Zornux code, call an extension by its alias and operation name:
screen ScanScreen
state result = ""
column
button "Scan barcode"
when tapped
result = barcode_scanner.scan()
end
end
text result
end
end
Only google(), mavenCentral(), and mavenLocal() repositories are allowed. Release builds refuse dynamic dependency versions (SNAPSHOT, +, latest) — pin every version.
Managing extensions
zornux mobile extension list # list installed extensions
zornux mobile extension info scanner # show details of one
zornux mobile extension check # validate compatibility
What's next
- Mobile Development — screens, layouts, widgets, state, and navigation.
- Mobile Tooling — hot reload, debugging, testing, profiling, and Play Store publishing.