Elide builds, runs, tests and ships Android applications and libraries from elide.pkl, with no Gradle and no
Android Gradle Plugin. The Android SDK’s own tools (aapt2, d8, R8, zipalign, apksigner, bundletool) run as
build tasks, so elide build --inspect lists every step and a second build runs only what changed.
Create and run an app
mkdir hello-android
cd hello-android
elide init --template android --plain --skip-defaults -- package=com.example.hello
elide run
On a machine with nothing but Elide installed, elide run:
- Looks for an Android SDK in
ANDROID_HOME,ANDROID_SDK_ROOTand the location Android Studio installs it in, and uses Elide’s managed SDK under~/.elide/toolchains/androidwhen none is found (Android SDK). - Asks once to accept the Android SDK licenses, then installs the platform, build-tools, platform-tools, emulator and system image the project needs.
- Builds the
appAPK and signs it with the Android debug keystore,~/.android/debug.keystore, created on first use. - Installs it on the one attached device, or creates and boots the project’s emulator when none is attached.
- Launches the app and prints its log until you press Ctrl+C or the app exits.
The license question is asked only on a terminal. In CI, accept the licenses explicitly and install first:
elide install --accept-android-licenses
elide build
The emulator needs hardware acceleration. On Linux that is /dev/kvm and membership of the kvm group; without
it the emulator fails before booting and says so (Headless hosts, CI and WSL).
The template
elide.pkl
src/main/kotlin/com/example/hello/MainActivity.kt
src/androidTest/kotlin/com/example/hello/MainActivityTest.kt
amends "elide:project.pkl"
import "elide:Android.pkl" as Android
name = "android-app"
version = "1.0.0"
android {
namespace = "com.example.hello"
compileSdk = 36
minSdk = 30
// Generates `AndroidManifest.xml`; a `src/main/AndroidManifest.xml`, if added, is merged over it.
application {
label = "@string/app_name"
theme = "@android:style/Theme.Material.Light.NoActionBar"
allowBackup = false
activities { ["MainActivity"] { launcher = true } }
}
resources {
strings {
["app_name"] = "Elide Android App"
["greeting"] = "Hello Elide!"
}
}
}
kotlin {
features {
compose = true
}
}
dependencies {
android {
androidx { ["activity-compose"] = "1.9.3" }
compose { version = "1.7.8"; modules { "foundation"; "ui-tooling" } }
test { runner = "1.6.2"; modules { "ext-junit" } }
}
}
artifacts {
["app"] = new Android.AndroidApk {}
}
androiddeclares the namespace (the packageRlives in, and the application id), the API levels, the application’s manifest entries and its strings. NoAndroidManifest.xmlorstrings.xmlis needed (Manifest and resources).kotlin.features.composeturns on the Compose compiler, anddependencies.androiddeclares the Compose, AndroidX and AndroidX Test libraries by family (Android dependencies).appleavesreleaseunset, so it is a debuggable build signed with the debug keystore;elide build --releasebuilds it as a release instead (Signing and release).src/androidTestholds an instrumented test, whichelide test --deviceruns on a device (Android tests).
elide init --template android --parameters lists the template’s parameters (project_name, app_name,
package, greeting).
Commands
Android projects use the commands every project has. Device behaviour is behind flags, and each command runs a build
target that elide build can also run by name (Android build targets).
| Command | Does |
|---|---|
elide run [app] | Build, install, launch and follow the app’s log. |
elide run --emulator | The same, on the project’s emulator. |
elide run --debugger[= | Launch suspended and forward a JDWP port. |
elide run --watch | Rebuild, reinstall and relaunch on every source change. |
elide test | Host tests, under Robolectric. |
elide test --device | Instrumented tests on a device or emulator. |
elide build [artifact] | Build APKs, bundles and libraries. |
elide install | Install dependencies and the SDK components the project needs. |
elide project info | The SDK, its components, devices and emulators. |
Artifacts
| Artifact | Publishes |
|---|---|
Android.AndroidApk | An application package: .. |
Android.AndroidAab | An app bundle for a store: .. |
Android.AndroidAar | A library archive: .. |
Android.AndroidFeature | A dynamic feature module inside a bundle. |
An application consumes the libraries of its own workspace and published AARs alike: classes, resources, manifests, assets and native libraries merge in one pass (Manifest and resources).
Limits
-
Android support ships with every standard Elide distribution. A custom build made without it (
--no-android) refuses to build, run or test an Android project, and says so. -
There are no build types or product flavors. Declare one artifact per variant, with its own
applicationId,releaseand resource directories. -
No
BuildConfigclass is generated, and Android Lint does not run. -
Host tests run against one artifact of a project, chosen by
android.hostTests. -
src/androidTestinstruments one application: the first APK that is neither a test APK nor minified. -
A bundle with dynamic feature modules cannot be minified.
-
A Java resource that several jars carry ships from the first; only
META-INF/servicesfiles are merged. -
elide lspserves Java sources only; Kotlin sources get no language server from it.