Mobile
Mobile Tooling
The zornux mobile CLI covers the full development lifecycle —
from first run to Play Store submission — without leaving the terminal.
Environment check
Run doctor before anything else. It verifies your SDK, JDK,
ADB, connected devices, and project configuration in one pass:
zornux mobile doctor
Build and run
Build the app and install it on a connected device or emulator:
zornux mobile run android
Build without installing:
zornux mobile build android
Validate the project without building:
zornux mobile check android
Device and emulator management
zornux mobile devices # list connected devices
zornux mobile emulators # list available AVDs
zornux mobile emulator start Pixel_7_API_34 # boot an emulator
Each device shows its serial, state (Online, Offline, Unauthorized), type (Physical or Emulator), model, Android version, and API level.
Pass --device <serial> to any command that targets a device. Without it, Zornux picks the first online device.
Hot reload
Add --watch to run and the toolchain watches
your .zx files for changes. When you save, it re-generates
the Compose code, rebuilds, reinstalls, and relaunches the app
automatically:
zornux mobile run android --watch
Changes to text, layout, and state within existing screens are hot-reloaded without a full restart. Changes that affect permissions, capabilities, or the project file trigger a full rebuild — the watcher tells you which path it took.
Adding a new permission, a new capability (camera, biometrics, etc.), or changing zornux.project requires a full rebuild. The watcher detects this and rebuilds automatically.
Logs
Stream the device logcat filtered to your app's process:
zornux mobile logs android
Debugging
Launch a debug session with breakpoint support:
zornux mobile debug android
The debugger injects a runtime bridge into the app, forwards a debug port over ADB, and connects. You can:
- Set breakpoints on Zornux source lines — the toolchain maps them to the generated Kotlin. Breakpoints snap to the nearest executable line within 3 lines.
- Step through code: continue, pause, step over, step into, step out.
- Inspect variables in the current scope.
- View stack traces mapped back to your Zornux source locations.
Debug events are tracked at five location types: lifecycle, action, state mutation, navigation, and capability call. When a breakpoint hits, the debugger shows which type of operation you are in.
The debug bridge uses a TCP protocol compatible with standard debug adapters. ZnxStudio connects to it natively.
Testing
Write tests in .zx files alongside your app code, then
discover and run them:
zornux mobile test android
Test kinds
The test runner classifies tests automatically based on what they do:
| Kind | What it tests | Needs a device? |
|---|---|---|
| Host logic | Pure logic — functions, calculations, data transforms. | No |
| UI component | Screen structure — screens exist, widgets are present. | No |
| Android interaction | On-device behavior — tap, enter text, assert visible. | Yes |
Host logic and UI component tests run on the host machine with no device attached — fast and CI-friendly. Interaction tests launch the app on a device or emulator.
Test options
zornux mobile test android --filter "login" # run matching tests
zornux mobile test android --device emulator-5554
zornux mobile test android --verbose # full output
zornux mobile test android --json # machine-readable results
zornux mobile test android --timeout 120 # per-test timeout (seconds)
Results are written to .zornux-test-results/android/.
Test doubles
The test framework provides mock implementations for device capabilities and HTTP, so host-logic tests can exercise code that calls them without a real device:
- Capability doubles — camera, location, biometrics, connectivity, files, notifications, sharing.
- HTTP doubles — mock responses with
OnGet,OnPost,OnPut,OnDelete,OnAny. Simulate timeouts and offline mode.
Profiling
Profile the app on a real device to find performance problems:
zornux mobile profile android
zornux mobile profile android --duration 30 # profile for 30 seconds
What the profiler measures
| Category | Metrics |
|---|---|
| Startup | Cold/warm start time, startup phases. |
| Screen rendering | Open-to-ready time per screen. |
| Recomposition | Count per screen — flags excessive (> 20). |
| HTTP | Method, URL, status, size, timeout detection. |
| State updates | Timing per state mutation. |
| Capability calls | Timing for camera, biometrics, and other device calls. |
| Navigation | Transition timing between screens. |
| Memory | Current, peak, Java heap. Flags growth > 20% across the session. |
| Frames | Slow (> 16ms), frozen (> 700ms), jank %, P95 frame time. |
| Main-thread blocking | Operations exceeding 32ms on the main thread. |
The profiler also analyzes package size — DEX, resources, native libraries, assets, generated Kotlin — and compares against your performance budgets.
Performance budgets
Set budgets in zornux.project and the profiler warns when
they are exceeded:
android.performance.startup_ms = 2000
android.performance.apk_mb = 20
android.performance.aab_mb = 15
Sessions are saved to .zornux-profile/android/ as both a
human-readable report and a JSON file.
Release builds
When the app is ready for distribution, the release pipeline validates, builds, and optionally publishes in three steps.
Step 1: Pre-flight check
zornux mobile release check
This validates:
- Application ID is set and follows reverse-domain format.
- Version code is positive and incremented from the previous release.
- Signing configuration is complete (keystore, alias, password env vars).
- Certificate is valid and not expired.
- Icons are configured.
- Cleartext traffic is disabled.
- Extension dependencies are pinned (no
SNAPSHOTor+versions). - Privacy declarations match capability usage (Data Safety).
- Store metadata (title, descriptions, feature graphic) is present.
Step 2: Build the release
zornux mobile release build
This produces:
- A signed release APK and AAB (Android App Bundle).
- ProGuard mapping file for crash de-obfuscation.
- Release manifest (JSON) with artifact hashes, permissions, SDK levels.
- SBOM in CycloneDX 1.5 format.
- SHA-256 checksums.
- Build provenance record (Zornux version, source revision, build timestamp).
zornux mobile release artifacts # list what was built
Step 3: Publish
zornux mobile release publish --track internal # internal testing
zornux mobile release publish --track production # production release
zornux mobile release publish --dry-run # validate without uploading
Supported tracks:
| Track | Audience |
|---|---|
internal | Internal testers only. |
closed | Closed alpha testers. |
open | Open beta — anyone can opt in. |
production | All users on the Play Store. |
Always run --dry-run before your first real publish. It validates the entire pipeline — credentials, metadata, artifact integrity — without uploading anything.
Signing configuration
Release builds must be signed. Configure the keystore in
zornux.project:
android.signing.keystore_path = release.jks
android.signing.key_alias = release
android.signing.keystore_password_env = KEYSTORE_PASSWORD
android.signing.key_password_env = KEY_PASSWORD
Passwords are read from environment variables — they never appear in the project file. Set them in your shell or CI secrets:
export KEYSTORE_PASSWORD="..."
export KEY_PASSWORD="..."
The keystore password env vars (KEYSTORE_PASSWORD, KEY_PASSWORD) must be set in the environment, not in the project file. The signing configuration stores only the names of the env vars.
Store metadata
Play Store listing fields go in zornux.project:
store.title = My App
store.short_description = A short tagline for the store listing
store.full_description = A longer description of what the app does
release.notes = Bug fixes and performance improvements
| Field | Limit |
|---|---|
store.title | 30 characters. |
store.short_description | 80 characters. |
store.full_description | No fixed limit. |
release.notes | No fixed limit. |
Publishing credentials
Google Play publishing requires a service account JSON key. Point to it
in zornux.project:
publishing.credential_file = play-service-account.json
Or reference an environment variable that holds the path:
publishing.credential_file_env = PLAY_CREDENTIALS
Privacy declarations (Data Safety)
The Play Store requires a Data Safety section. Declare what your app
collects in zornux.project — the release check validates
that these declarations match the capabilities your code actually uses:
privacy.location = true
privacy.photos = true
privacy.identifiers = false
privacy.auth_data = false
privacy.user_content = false
privacy.analytics = false
Cleaning up
Remove generated Android project files (the .zx source is
never touched):
zornux mobile clean
Inspect the generated Kotlin and Compose code:
zornux mobile generated
Project configuration reference
Every mobile-specific key in zornux.project:
| Key | Default | Purpose |
|---|---|---|
type | — | Must be mobile. |
entry | main.zx | Entry source file. |
android.application_id | com.zornux.app | Reverse-domain app ID. |
android.version_name | 1.0 | User-facing version string. |
android.version_code | 1 | Play Store integer version. |
android.min_sdk | 24 | Minimum Android API level. |
android.target_sdk | 34 | Target Android API level. |
android.compile_sdk | 34 | Compile SDK version. |
android.allow_cleartext | false | Allow HTTP traffic. |
android.icon.foreground | — | Adaptive icon foreground image path. |
android.icon.background_color | #FFFFFF | Adaptive icon background color. |
android.splash.icon | — | Splash screen icon path. |
android.splash.background_color | #FFFFFF | Splash screen background color. |
android.environment | development | Environment name. |
android.build_config.<FIELD> | — | Custom BuildConfig string fields. |
CI mode
Pass --ci to any mobile command for non-interactive,
stricter validation. Pair with --json for machine-readable
output:
zornux mobile test android --ci --json
zornux mobile release check --ci
zornux mobile release build --ci
CLI command reference
| Command | Purpose |
|---|---|
zornux new mobile <Name> | Scaffold a new mobile project. |
zornux mobile doctor | Check environment prerequisites. |
zornux mobile build android | Compile to an Android project and build. |
zornux mobile run android | Build, install, and launch on device. |
zornux mobile run android --watch | Run with hot reload. |
zornux mobile check android | Validate without building. |
zornux mobile devices | List connected devices. |
zornux mobile emulators | List available AVDs. |
zornux mobile emulator start <avd> | Boot an emulator. |
zornux mobile logs android | Stream filtered logcat. |
zornux mobile debug android | Launch a debug session. |
zornux mobile test android | Discover and run tests. |
zornux mobile profile android | Profile on-device performance. |
zornux mobile release check | Pre-flight release validation. |
zornux mobile release build | Build signed release artifacts. |
zornux mobile release artifacts | List release build outputs. |
zornux mobile release publish | Publish to the Play Store. |
zornux mobile extension list | List installed extensions. |
zornux mobile extension info <alias> | Show extension details. |
zornux mobile extension check | Validate extension compatibility. |
zornux mobile clean | Remove generated files. |
zornux mobile generated | Inspect generated Kotlin code. |
What's next
- Mobile Development — screens, layouts, widgets, state, and navigation.
- Mobile Capabilities — camera, location, notifications, secure storage, biometrics, HTTP, and native extensions.