clojure-android-demo
Health Warn
- No license — Repository has no license file
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Fail
- eval() — Dynamic code execution via eval() in mcp_server.py
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Clojure 1.13 Android Demo
clojure-android-demo
A minimal Android app that runs the patched Clojure 1.13 (theDynamicClassLoader hook + RT.VM_TYPE + Dalvik loader changes) on a device,
including on-device eval — JVM bytecode is translated to DEX at runtime byclojure.lang.DalvikDynamicClassLoader (d8 + InMemoryDexClassLoader).

Emacs cider connect
adb forward tcp:6688 tcp:6688
M-x cider-connect RET Host: localhost RET Port: 6688 RET

What it shows
On launch (MainActivity):
- AOT path — calls bundled
clojure.corefunctions directly, no compilation:(+ 1 2),(apply + (range 1 101)). vm-type— printsclojure.core/vm-type, the Var added by the patch
(:dalvik-vmon a device,:java-vmon the JVM).- Dynamic path —
load-stringcompiles fresh code and runs it through the
Dalvik loader:(+ 1 2),(do (defn sq [x] (* x x)) (mapv sq (range 1 6))). - A text box + Eval button = a tiny on-device REPL.
Prerequisites / how it was built
- Build the patched jar in the sibling Clojure repo:
It producescd ../clojure && ./build-jar.shclojure-1.13.0-master-SNAPSHOT.jar, already copied here intoapp/libs/along with its two AOT-time deps (spec.alpha,core.specs.alpha). app/src/main/java/clojure/lang/DalvikDynamicClassLoader.javais the d8 loader
copied from../clojure/android-support/(it importsandroid.*/ r8, so it
lives in the app, not the main jar).
Build & run
# Android SDK path is in local.properties (edit if yours differs).
./gradlew :app:assembleDebug # build the APK
./gradlew :app:installDebug # install on a connected device/emulator
# then launch "Clojure 1.13 Demo", or:
adb shell am start -n com.example.clojuredemo/.MainActivity
adb logcat -s ClojureDemo # watch the loader log
Or just open this folder in Android Studio and Run.
Remote nREPL (Emacs CIDER)
MyApp.onCreate also starts a network nREPL server on port 6688 (seeMyApp.NREPL_PORT). It boots on a background thread by load-string-ing(require 'nrepl.server) + nrepl.server/start-server — i.e. nREPL's own .clj
sources are compiled on-device through the same d8 path as user eval. Thenrepl:nrepl:1.0.0 dependency (clojure excluded) is in app/build.gradle, andINTERNET permission is in the manifest.
Connect from Emacs:
./gradlew :app:installDebug
adb shell am start -n com.example.clojuredemo/.MainActivity # launches → starts nREPL
adb logcat -s ClojureDemo # wait for "nREPL server listening on 0.0.0.0:6688"
adb forward tcp:6688 tcp:6688 # tunnel device port to your machine
M-x cider-connect RET Host: localhost RET Port: 6688 RET
Notes:
- The server binds
0.0.0.0, so you can alsocider-connectstraight to the
device/emulator IP on a LAN;adb forwardis the simplest/safest path. - It's a plain nREPL (no
cider-nreplmiddleware) — eval/load works; some
CIDER extras (completion, debugger) need cider-nrepl, which is heavy to compile
on-device and left out on purpose. - First connect is slow: requiring
nrepl.servercompiles all of nREPL via d8.
Watchlogcat -s ClojureDemo; start CIDER after the "listening" line.
Versions / config
| AGP | 8.5.0 |
| Gradle | 8.11.1 |
| compileSdk / targetSdk | 34 |
| minSdk | 26 (d8 + InMemoryDexClassLoader requires API ≥ 26) |
| multiDex | enabled (Clojure + r8 exceed 64K methods) |
| minify | off (Clojure relies on runtime reflection) |
| on-device translator | com.android.tools:r8:8.2.47 |
Verified on an API 36 emulator (see screenshot above): boot ≈ 4 s, both AOT
calls, and both on-device evals succeed ((+ 1 2) = 3,(mapv sq (range 1 6)) = [1 4 9 16 25]), plus interactive REPL input.
Notes & gotchas
- First boot takes a few seconds — loading the AOT'd
clojure.coreand, for
eval, running r8/d8 on the device. All Clojure work is on a background thread
to avoid ANR. largeHeap="true"is set; Clojure's runtime is memory-hungry.- The eval path bundles r8 (~MBs) into the APK so d8 can run on the device.
Errors (if any) are shown in the output pane and logged tologcat -s ClojureDemo,
not swallowed. - Two extra fixes in the patched jar were needed for on-device eval (beyond
the classloader patch), both in../clojure: a realInputStreampath inload-data-readers, and aReflector.<clinit>guard for Android's missingAccessibleObject.canAccess. Without themRTinit / dynamic compilation crash
on ART. See../clojure/android-support/README.md. app/src/main/assets/data_readers.cljis read by the patchedload-data-readersviaDalvikDynamicClassLoader.getDataReadersStream().- To use the legacy dx loader instead of d8, swap in
../clojure/android-support/DalvikDynamicClassLoader_dx_legacy.java.altand
change the r8 dependency tocom.android.tools:dx:1.16.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found