OthmaneBlial/droidless

Run Android apps without Android.

Rust

2

177 commits

updated Oct 2, 2026

See the code

See what people are saying

SourceMessageScoreDate

DROIDLESS: Run Android APKs Without Android 🤖🦀 (r/SideProject)

Okay, this started as one of those **“this is probably a terrible idea… so obviously I have to build it”** projects. 😂 # 🤖 DROIDLESS **What if you could run Android APKs on desktop… without Android?** No Android emulator. No ART. No Dalvik. No hidden Android VM sitting somewhere pretending not to…

1

Oct 3, 2026

README

DROIDLESS — Android apps. New desktop habitat. An experimental Rust runtime with native views.

Release Rust License Checks

📦 Download v0.3.0 · 🌐 Explore the website · 📖 Open the notebook

Original APK bytecode → our Rust engine → native desktop views.

👋 A little runtime with a big idea

Give an Android app a new home on your desktop. Open a note, change its title and body, save it, then restart: the original APK brings your edits back. ✍️

DROIDLESS is an experimental Android compatibility runtime written in Rust. It owns the DEX interpreter, managed heap, resource system, Android API bridge and View model. AppKit supplies native macOS controls; clicks and keyboard input return to the APK's own callbacks.

The execution path runs without an Android emulator, ART, Dalvik or a hidden Android installation. Android SDK tools are used only to compile authored test fixtures. Compatibility is narrow, and unsupported APIs report explicit errors.

✨ What can it actually do?

Real appVerified native interactionVerified headless replay
📓 Notepad 1.0.0Mouse selection, keyboard title/body edits, Back save and exact restoration in a fresh processTwo persistent SQLite notes; edit/restart; Delete/Undo; drawer; folder create/rename/delete; exact database backup/restore and fresh-launch recovery
🖼️ SwpieView 1.3.2Folder chooser → three thumbnails → JPEG/PNG/WebP viewer → Escape back; taps hide/show controlsOriginal image swipes, first/last bounds, control visibility, Parcelable transfer and Back
🧮 Simple Calculator 1.0Original clicks produce 7 + 5 = 12, 8 × 8 = 64 and 9 / 3 = 3Seven arithmetic and input scenarios

Public APKs are pinned, SHA-256 checked and executed unchanged. They are fetched from upstream and never bundled in our release. Native observations and headless checks have separate evidence; authored fixtures establish engine contracts, not arbitrary APK compatibility. Read the verification record.

Illustrated headless Notepad View tree showing two saved notes.
📓 Save. Reopen. Keep writing.
Illustrated View-tree preview, not a native capture.
Actual public Simple Calculator APK in a native macOS window, showing 12.
🧮 Original clicks. Original result.
Earlier native capture at a 192 × 400 viewport.

📥 Open → ✍️ Edit → 💾 Save → 🗂️ Back up → 🔁 Restore → 🚀 Reopen

Backup/restore is verified on an isolated data copy. Current main maps the original APK's System.exit(0) to CLI status 0; the v0.3.0 archive predates that follow-up and reports the guest exit after data recovery.

🚀 Get your first APK running

v0.3.0 is a macOS ARM64 preview. The archive contains the CLI, five authored fixtures, three hash-checking public APK fetch helpers and release provenance. It has no Apple developer signature or notarization.

Download the archive and SHA256SUMS, then, from their download directory:

shasum -a 256 -c SHA256SUMS
tar -xzf droidless-0.3.0-macos-arm64.tar.gz
cd droidless-0.3.0-macos-arm64

# Your first guest callback 🤖
./droidless run --headless --ephemeral fixtures/counter.apk --click Increment

Try the original public notes app, using a dedicated local data directory:

sh tools/fetch-notepad.sh

# Notes → editor → save → return to the list
./droidless run --headless --size 390x844 --data-dir ./test-apps \
  --click "+" --input "Hello, desktop" --input-at 1 "Made of Rust and curiosity." \
  --back artifacts/apks/notepad-v1.0.0.apk

# A fresh process restores your note
./droidless run --headless --size 390x844 --data-dir ./test-apps \
  artifacts/apks/notepad-v1.0.0.apk

# Open a native desktop window
./droidless run --size 390x720 --data-dir ./test-apps \
  artifacts/apks/notepad-v1.0.0.apk

Escape delivers Back in the native window. The package also includes fetch-simple-calculator.sh and fetch-swpieview.sh. Release scope and known limits.

🛠️ Prefer building from source?

Use Rust 1.95.0 and Apple's Command Line Tools on macOS:

git clone https://github.com/OthmaneBlial/droidless.git
cd droidless
cargo build --release --locked
sh tools/fetch-notepad.sh
target/release/droidless run --headless --ephemeral --size 390x844 \
  --click "+" --input "Hello, desktop" artifacts/apks/notepad-v1.0.0.apk

Normal builds and tests need no Android SDK or emulator. Linux has a headless code path; Linux builds and native UI have not been verified.

⚙️ Follow the bytecode

APK → Rust DEX interpreter → Android API bridge → native AppKit controls; input returns to APK callbacks.
CrateWhat it owns
droidless-formatsBounded APK, binary XML, DEX and compiled-resource parsers
droidless-runtimeRegister interpreter, managed objects, GC, lifecycle, framework APIs and Views
droidlessCLI, native macOS rendering and input bridge

Architecture · DEX VM · Framework

🧰 Inside v0.3.0

CapabilityImplemented scope
🧠 Our own VMDEX 035–040; arithmetic, wide values, branches, arrays, fields, dispatch, managed continuations, Java throw/catch and retained DEX stack diagnostics
🪟 Native viewsText, buttons, editors, nested layouts, bounded adapter grids, a targeted support-RecyclerView notes path and separate dialog panels
🧭 NavigationSame-APK Intents, typed Bundle extras, same-runtime Serializable references, retained Back stack, results, real Parcelable writers/CREATORs and lifecycle observers
📓 PersistenceIsolated SharedPreferences and the public Notepad's SQLite save/edit/restart workflows
🖼️ ImagesPackaged XML, typed resources, PNG/JPEG/WebP decoding, granted read-only document streams and native ImageViews
⏱️ Scheduled workMain Handler/Looper/Message queue, guest Timer tasks, deferred workers, executor/Future results and main-thread delivery
🗂️ Java foundationsBounded collections, guest equality, reflection, primitive metadata, weak references and handle-based mark/sweep GC
✂️ Layout and inputMeasured text, UTF-16 ellipsis metadata, host-font ascent/descent, full accessibility labels for shortened text, clipping, focus and single-pointer gesture contracts
💾 Bounded file I/OApp-private reads/writes and package-isolated external files; staged output commits atomically up to 64 MiB; input/output channels share position and close state, with bounded transfers
🧩 Everyday APIsToast feedback, filtered file listing, selected reflected fields, UTF-8 form URLs, file-extension MIME lookup and fragment containers

These are bounded profiles with explicit ceilings. The unchanged Notepad APK creates a byte-exact .nbu backup and restores a tampered database; a fresh process shows the original note and folder rows. On current main, the APK's post-restore System.exit(0) returns CLI status 0; the tagged v0.3.0 archive retains its earlier unsupported-exit behavior. Custom Bundle serializables are same-runtime references, not Java serialization or durable snapshots. Physical public folder/dialog input, Android font/pixel parity, GIF animation and usable slideshow remain unverified. Broad AndroidX/Compose, JNI, networking, JIT and games are future work. Exact compatibility · Storage limits

🔎 Inspect, replay and trace
target/release/droidless inspect app.apk
target/release/droidless manifest app.apk
target/release/droidless dex app.apk
target/release/droidless classes app.apk
target/release/droidless methods app.apk
target/release/droidless resources app.apk

target/release/droidless run --headless --ephemeral fixtures/generated/intents.apk \
  --click "Open detail" --back
target/release/droidless run --headless --ephemeral fixtures/generated/scheduling.apk \
  --click "Start timer" --advance-ms 1500 --advance-ms 1500 --advance-ms 1500

Use --trace-bytecode, --trace-methods, --trace-framework and --trace-lifecycle to follow the real execution path. --stats and --heap-stats report measured counters. --click, --tap, --key, --back, --input-at, --focus-at and --menu-item replay guest input. --advance-ms advances the deterministic headless clock. CLI reference.

🧪 Small lab. Executable evidence.

150 Rust tests, warning-free Clippy, optimized builds, five native component checks and 4,096 seeded parser mutations run locally. The public APK replay checks the original app flows and certifies one unchanged CLI SHA-256. Release packaging extracts the archive into a clean directory and checks Counter, navigation/Back, UTF-8 preferences and original Notepad save/restart.

# CI runs on your machine. GitHub Actions stays disabled.
sh tools/ci.sh
sh tools/fetch-kascalc.sh                 # Earlier regression fixture
sh tools/fetch-simple-calculator.sh
sh tools/fetch-notepad.sh
sh tools/fetch-swpieview.sh
python3 tools/compatibility.py
python3 tools/package-macos.py

Evidence catalog · Verification record · Changelog

🔧 Rebuild fixtures or a development app bundle
python3 tools/build-fixtures.py --sdk "$ANDROID_SDK_ROOT"
sh tools/macos-app.sh

SDK tools compile fixtures only. The app bundle is unsigned and intended for local development.

🗺️ On the road to 50%

The 20% milestone demonstrated an unmodified APK rendering, accepting input, executing its own logic and updating native UI. Everyday-app workflows now add multiple screens, persistent notes, folders, images and scheduled callbacks.

50% remains the active target. These labels describe project milestones, not measured Android API coverage. Each step needs a working app flow and a clear compatibility boundary. Follow the roadmap.

🔐 Bring trusted APKs

DROIDLESS is an experimental runtime, not an audited security sandbox. Package storage is confined to the host-selected app root; external storage is a package-isolated virtual directory. Granted document access is bounded and read-only. General file access, networking and native-library/process APIs remain unavailable. Security boundaries.


DROIDLESS robot explorer

Built in Rust. A little stubborn by design. 🤖

Apache-2.0 · Third-party artifacts retain their upstream licenses.

Website · Notebook · Release

android
android-runtime
apk
compatibility-layer
dalvik
dex
macos
runtime
rust
systems-programming
virtual-machine

OthmaneBlial/droidless

Run Android apps without Android.

Rust

2

177 commits

updated Oct 2, 2026

See the code

See what people are saying

SourceMessageScoreDate

DROIDLESS: Run Android APKs Without Android 🤖🦀 (r/SideProject)

Okay, this started as one of those **“this is probably a terrible idea… so obviously I have to build it”** projects. 😂 # 🤖 DROIDLESS **What if you could run Android APKs on desktop… without Android?** No Android emulator. No ART. No Dalvik. No hidden Android VM sitting somewhere pretending not to…

1

Oct 3, 2026

README

DROIDLESS — Android apps. New desktop habitat. An experimental Rust runtime with native views.

Release Rust License Checks

📦 Download v0.3.0 · 🌐 Explore the website · 📖 Open the notebook

Original APK bytecode → our Rust engine → native desktop views.

👋 A little runtime with a big idea

Give an Android app a new home on your desktop. Open a note, change its title and body, save it, then restart: the original APK brings your edits back. ✍️

DROIDLESS is an experimental Android compatibility runtime written in Rust. It owns the DEX interpreter, managed heap, resource system, Android API bridge and View model. AppKit supplies native macOS controls; clicks and keyboard input return to the APK's own callbacks.

The execution path runs without an Android emulator, ART, Dalvik or a hidden Android installation. Android SDK tools are used only to compile authored test fixtures. Compatibility is narrow, and unsupported APIs report explicit errors.

✨ What can it actually do?

Real appVerified native interactionVerified headless replay
📓 Notepad 1.0.0Mouse selection, keyboard title/body edits, Back save and exact restoration in a fresh processTwo persistent SQLite notes; edit/restart; Delete/Undo; drawer; folder create/rename/delete; exact database backup/restore and fresh-launch recovery
🖼️ SwpieView 1.3.2Folder chooser → three thumbnails → JPEG/PNG/WebP viewer → Escape back; taps hide/show controlsOriginal image swipes, first/last bounds, control visibility, Parcelable transfer and Back
🧮 Simple Calculator 1.0Original clicks produce 7 + 5 = 12, 8 × 8 = 64 and 9 / 3 = 3Seven arithmetic and input scenarios

Public APKs are pinned, SHA-256 checked and executed unchanged. They are fetched from upstream and never bundled in our release. Native observations and headless checks have separate evidence; authored fixtures establish engine contracts, not arbitrary APK compatibility. Read the verification record.

Illustrated headless Notepad View tree showing two saved notes.
📓 Save. Reopen. Keep writing.
Illustrated View-tree preview, not a native capture.
Actual public Simple Calculator APK in a native macOS window, showing 12.
🧮 Original clicks. Original result.
Earlier native capture at a 192 × 400 viewport.

📥 Open → ✍️ Edit → 💾 Save → 🗂️ Back up → 🔁 Restore → 🚀 Reopen

Backup/restore is verified on an isolated data copy. Current main maps the original APK's System.exit(0) to CLI status 0; the v0.3.0 archive predates that follow-up and reports the guest exit after data recovery.

🚀 Get your first APK running

v0.3.0 is a macOS ARM64 preview. The archive contains the CLI, five authored fixtures, three hash-checking public APK fetch helpers and release provenance. It has no Apple developer signature or notarization.

Download the archive and SHA256SUMS, then, from their download directory:

shasum -a 256 -c SHA256SUMS
tar -xzf droidless-0.3.0-macos-arm64.tar.gz
cd droidless-0.3.0-macos-arm64

# Your first guest callback 🤖
./droidless run --headless --ephemeral fixtures/counter.apk --click Increment

Try the original public notes app, using a dedicated local data directory:

sh tools/fetch-notepad.sh

# Notes → editor → save → return to the list
./droidless run --headless --size 390x844 --data-dir ./test-apps \
  --click "+" --input "Hello, desktop" --input-at 1 "Made of Rust and curiosity." \
  --back artifacts/apks/notepad-v1.0.0.apk

# A fresh process restores your note
./droidless run --headless --size 390x844 --data-dir ./test-apps \
  artifacts/apks/notepad-v1.0.0.apk

# Open a native desktop window
./droidless run --size 390x720 --data-dir ./test-apps \
  artifacts/apks/notepad-v1.0.0.apk

Escape delivers Back in the native window. The package also includes fetch-simple-calculator.sh and fetch-swpieview.sh. Release scope and known limits.

🛠️ Prefer building from source?

Use Rust 1.95.0 and Apple's Command Line Tools on macOS:

git clone https://github.com/OthmaneBlial/droidless.git
cd droidless
cargo build --release --locked
sh tools/fetch-notepad.sh
target/release/droidless run --headless --ephemeral --size 390x844 \
  --click "+" --input "Hello, desktop" artifacts/apks/notepad-v1.0.0.apk

Normal builds and tests need no Android SDK or emulator. Linux has a headless code path; Linux builds and native UI have not been verified.

⚙️ Follow the bytecode

APK → Rust DEX interpreter → Android API bridge → native AppKit controls; input returns to APK callbacks.
CrateWhat it owns
droidless-formatsBounded APK, binary XML, DEX and compiled-resource parsers
droidless-runtimeRegister interpreter, managed objects, GC, lifecycle, framework APIs and Views
droidlessCLI, native macOS rendering and input bridge

Architecture · DEX VM · Framework

🧰 Inside v0.3.0

CapabilityImplemented scope
🧠 Our own VMDEX 035–040; arithmetic, wide values, branches, arrays, fields, dispatch, managed continuations, Java throw/catch and retained DEX stack diagnostics
🪟 Native viewsText, buttons, editors, nested layouts, bounded adapter grids, a targeted support-RecyclerView notes path and separate dialog panels
🧭 NavigationSame-APK Intents, typed Bundle extras, same-runtime Serializable references, retained Back stack, results, real Parcelable writers/CREATORs and lifecycle observers
📓 PersistenceIsolated SharedPreferences and the public Notepad's SQLite save/edit/restart workflows
🖼️ ImagesPackaged XML, typed resources, PNG/JPEG/WebP decoding, granted read-only document streams and native ImageViews
⏱️ Scheduled workMain Handler/Looper/Message queue, guest Timer tasks, deferred workers, executor/Future results and main-thread delivery
🗂️ Java foundationsBounded collections, guest equality, reflection, primitive metadata, weak references and handle-based mark/sweep GC
✂️ Layout and inputMeasured text, UTF-16 ellipsis metadata, host-font ascent/descent, full accessibility labels for shortened text, clipping, focus and single-pointer gesture contracts
💾 Bounded file I/OApp-private reads/writes and package-isolated external files; staged output commits atomically up to 64 MiB; input/output channels share position and close state, with bounded transfers
🧩 Everyday APIsToast feedback, filtered file listing, selected reflected fields, UTF-8 form URLs, file-extension MIME lookup and fragment containers

These are bounded profiles with explicit ceilings. The unchanged Notepad APK creates a byte-exact .nbu backup and restores a tampered database; a fresh process shows the original note and folder rows. On current main, the APK's post-restore System.exit(0) returns CLI status 0; the tagged v0.3.0 archive retains its earlier unsupported-exit behavior. Custom Bundle serializables are same-runtime references, not Java serialization or durable snapshots. Physical public folder/dialog input, Android font/pixel parity, GIF animation and usable slideshow remain unverified. Broad AndroidX/Compose, JNI, networking, JIT and games are future work. Exact compatibility · Storage limits

🔎 Inspect, replay and trace
target/release/droidless inspect app.apk
target/release/droidless manifest app.apk
target/release/droidless dex app.apk
target/release/droidless classes app.apk
target/release/droidless methods app.apk
target/release/droidless resources app.apk

target/release/droidless run --headless --ephemeral fixtures/generated/intents.apk \
  --click "Open detail" --back
target/release/droidless run --headless --ephemeral fixtures/generated/scheduling.apk \
  --click "Start timer" --advance-ms 1500 --advance-ms 1500 --advance-ms 1500

Use --trace-bytecode, --trace-methods, --trace-framework and --trace-lifecycle to follow the real execution path. --stats and --heap-stats report measured counters. --click, --tap, --key, --back, --input-at, --focus-at and --menu-item replay guest input. --advance-ms advances the deterministic headless clock. CLI reference.

🧪 Small lab. Executable evidence.

150 Rust tests, warning-free Clippy, optimized builds, five native component checks and 4,096 seeded parser mutations run locally. The public APK replay checks the original app flows and certifies one unchanged CLI SHA-256. Release packaging extracts the archive into a clean directory and checks Counter, navigation/Back, UTF-8 preferences and original Notepad save/restart.

# CI runs on your machine. GitHub Actions stays disabled.
sh tools/ci.sh
sh tools/fetch-kascalc.sh                 # Earlier regression fixture
sh tools/fetch-simple-calculator.sh
sh tools/fetch-notepad.sh
sh tools/fetch-swpieview.sh
python3 tools/compatibility.py
python3 tools/package-macos.py

Evidence catalog · Verification record · Changelog

🔧 Rebuild fixtures or a development app bundle
python3 tools/build-fixtures.py --sdk "$ANDROID_SDK_ROOT"
sh tools/macos-app.sh

SDK tools compile fixtures only. The app bundle is unsigned and intended for local development.

🗺️ On the road to 50%

The 20% milestone demonstrated an unmodified APK rendering, accepting input, executing its own logic and updating native UI. Everyday-app workflows now add multiple screens, persistent notes, folders, images and scheduled callbacks.

50% remains the active target. These labels describe project milestones, not measured Android API coverage. Each step needs a working app flow and a clear compatibility boundary. Follow the roadmap.

🔐 Bring trusted APKs

DROIDLESS is an experimental runtime, not an audited security sandbox. Package storage is confined to the host-selected app root; external storage is a package-isolated virtual directory. Granted document access is bounded and read-only. General file access, networking and native-library/process APIs remain unavailable. Security boundaries.


DROIDLESS robot explorer

Built in Rust. A little stubborn by design. 🤖

Apache-2.0 · Third-party artifacts retain their upstream licenses.

Website · Notebook · Release

android
android-runtime
apk
compatibility-layer
dalvik
dex
macos
runtime
rust
systems-programming
virtual-machine

Languages

Rust

92.4%

HTML

2.7%

Python

2.5%

Objective-C

2.1%