Skip to content

Dylanmurzello/zed-android-port

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37,805 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Zed on Android

Zdroid. The actual Zed editor workspace, project panel, multi-buffer editor, LSPs, terminal, git graph, extensions, remote SSH running natively on an Android tablet.

Experimental Android Total downloads

Experimental. Not affiliated with Zed Industries. Might be highly unstable. See Caveats for what doesn't work yet.

Under the hood this is Termux + bionic libc, not a real Linux distro. The kernel is Android's, /usr/bin/env doesn't exist, /tmp doesn't exist, /etc/resolv.conf doesn't exist, and any precompiled binary that assumes a glibc Linux runtime can fail in surprising ways. We hex-patch / shim the common cases (claude, npm tools, apt, dpkg) but each new tool you install is a fresh roll of the dice. If something errors with dlopen failed: library "libfoo.so" not found or execve: no such file or directory on a binary that "should" work, that's why.

Soft fork of zed-industries/zed.


Zed on Android: workspace, terminal, LSP demo

Zed compiled from source for Android. gpui rendering with Vulkan via wgpu. The upstream Editor, Workspace, Project, MultiWorkspace, Search, GitPanel, GitGraph, Extensions, and Terminal crates running unchanged. Not a webview (no shade at electron). Bypasses termux + SSH to a server (since we have our own bootstrap). The actual Rust .so runs as the app process; gpui composites every pixel (yes, you read that right) directly via the Adreno Vulkan driver.

The trick was basically a custom gpui_android platform backend (Vulkan surface lifecycle, JNI bridges, touch and keyboard event translation) plus a Termux userland rebuilt under our package, com.zdroid (hence the unofficial name Zdroid, also the launcher label). apt, bash, git, ssh, node, go, openjdk, rust-analyzer all run inside the app's data dir. Everything else is upstream Zed.


 What works

Remote SSH workspace Git graph Settings

  • Editor. Vulkan rendering, multi-pane workspace, vim mode, syntax highlighting, project panel, fuzzy file finder, command palette, buffer + project search.
  • Git. Git panel with staging, full git-graph commit history, diff view.
  • LSPs. rust-analyzer baked in. gopls, ts-server, pyright, jdtls install in one pkg/npm/go install.
  • Extensions. Browse, install, manage. Themes, language configs, grammars, slash commands.
  • Remote SSH. Server-picker pill in the title bar, persisted server list, native askpass.
  • Input. Hardware keyboard, mouse, trackpad. Two-finger and long-press right-click.
  • Multi-window. Android freeform and DeX, each extra window is a real Activity with OS chrome.
  • Edge-to-edge rendering with content under the display cutout.
  • App menu bar with nested submenus (Settings, Keymap, Themes, Extensions).
  • Theme follow for system light/dark.
  • ZedDocumentsProvider exposes the project root as a SAF volume, so other Android apps can browse Zed's worktrees.

 Roadmap

Documented in crates/gpui_android/docs/workarounds/. PRs welcome.

  • Soft keyboard / touch IME bridge.
  • 120Hz on 120Hz panels (currently 60Hz).
  • Mailbox present mode, FrameMetrics, ALooper spurious-wake hunt, touch-event chain shortening.

Out of scope for this proof of concept: collab, AI panels, livekit voice. Cfg-gated to mocks so the binary still compiles. Cloud-account features that need backend integration anyway.


 Tested on

Samsung Galaxy Tab S9 Ultra (Snapdragon 8 Gen 2 / Adreno 740, Android 16, One UI 8) is the daily driver. Compiles for any aarch64 Android 9+ with Vulkan 1.1, but only Adreno is exercised. Mali / Xclipse will run but may want shader tweaks.

A hardware keyboard is the supported config. Tablet plus Bluetooth keyboard, foldable in tablet mode, or DeX/desktop-mode with monitor and peripherals all work. Phones technically run but are de-prioritized; see docs/workarounds/deferred-phone-form-factor-polish.md.


 Install

adb install -r zed-android-<version>.apk
adb shell am start -n com.zdroid/.MainActivity

Or sideload via your file manager. Android prompts for unknown-source installs. First launch extracts a 250 MB Termux userland into the app's private data dir; takes about 30 seconds. Subsequent launches are instant.


 Build from source

You'll need:

  • Rust toolchain with aarch64-linux-android (rustup target add aarch64-linux-android)
  • cargo-ndk (cargo install cargo-ndk)
  • Android NDK r27 (sdkmanager "ndk;27.0.12077973")
  • Gradle 8+, adb on $PATH
  • A device with USB debugging on
cd crates/gpui_android/examples/zed_android

ANDROID_NDK_HOME=/path/to/ndk/27.0.12077973 \
  cargo ndk -t arm64-v8a -P 26 -o android/app/src/main/jniLibs build

cd android
gradle assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.zdroid/.MainActivity

adb logcat -d | grep -E "zed_android|RustPanic|FATAL"

First build is around 10 minutes. Incremental Rust rebuilds are 20 seconds, Gradle re-pack a few seconds.


 Architecture

Deep-dives in crates/gpui_android/docs/workarounds/. Highlights:

  • AChoreographer-driven vsync via NDK FFI. No JNI hop per frame.
  • SAF integration for picker → POSIX-path translation.
  • Multi-activity OS-chromed extra windows. DeX freeform shows extra windows with Android's own task chrome.

 Userland

  • Termux, in-process. apt, bash, ssh, node, go, git, python, openjdk all native. No SSH bridge, no proot. Integrated terminal opens straight into it.
  • Claude Code. npm install -g @anthropic-ai/claude-code, then claude. If npm or any later pkg install complains about unmet deps, run apt --fix-broken install afterwards to settle them. Don't run fix-broken on a fresh bootstrap before you've installed anything: apt will treat the pre-baked Termux packages (go, openssh, etc.) as "unowned" and remove them.
  • Termux rebuilt under com.zdroid. apt/dpkg/bash userland with our package name baked into RUNPATHs and shebangs.
  • /etc/resolv.conf hex-patch. Bun-compiled CLIs statically link c-ares with /etc/resolv.conf baked into rodata. We rewrite the literal in the binary's .rodata and in our musl libc to point at /sdcard/.zed/r, populated by JNI from ConnectivityManager.getActiveDnsServers().
  • apply_runtime_patches stack at every boot: npm wrapper, launcher-gen patchelf, askpass helper, profile.d shim, DNS file refresh.

 Storage workflow

Click "Open Project" from the welcome screen. Android's storage picker opens at the device's shared storage. Two ways through:

  • Stay in the picker, open the side menu, navigate to Zdroid → projects. Zdroid's DocumentsProvider exposes ~/ as a SAF root. Anything you open from under there is in exec-mounted storage and builds run normally.
  • Pick anywhere on /sdcard/ (an existing project on internal storage). It opens in restricted mode — Android's shared storage is FUSE-mounted noexec, so cargo build's output binary can't execve(). Read / edit / save still work. Zdroid shows a yellow Builds won't run · Move chip at the top; one tap copies the folder into ~/projects/<name> once and reopens it from the exec-mounted side.

The two storage realms underneath:

  1. /data/data/com.zdroid/files/ (app-private, exposed as ~/) is exec-mounted. Same place Termux runs everything from. ~/projects/<name> is the default workspace root; cargo new, git clone, builds, debugs, integrated terminal subprocesses all run.
  2. /storage/emulated/0/ (Android's shared storage, also surfaced at ~/storage/) is FUSE-mounted noexec. Read / write / edit fine; the kernel refuses execve(). cargo run against a binary on /sdcard/... returns EACCES.
Where What for
~/projects/<name> Default workspace root. Builds, debugs, terminal subprocesses all run.
~/storage/{shared,downloads,...} Curated symlinks into shared storage. For "open / edit / save a single file" workflows. Don't workspace-root these.
File → Open (any /sdcard/ path) Restricted mode. Use the yellow Move chip to promote into ~/projects/.
File → Import from sdcard… SAF folder picker. Recursively copies the chosen folder into ~/projects/<basename>.

 LSP install recipes

# Rust: baked into the bootstrap.
rust-analyzer --version

# Go.
go install golang.org/x/tools/gopls@latest

# TypeScript / JavaScript.
npm install -g typescript typescript-language-server

# Python (Pyright).
pkg install python && npm install -g pyright

# Java (jdtls). JVM-based, no native proxy needed.
pkg install openjdk-17 maven
# Then download jdtls from https://download.eclipse.org/jdtls/milestones/
# and add an `lsp.jdtls.binary.path` override in settings.json.

Themes, grammars, and language configs from the Extensions pane always work. Some extension-shipped binaries are glibc-only and won't run on Android (see Caveats).


 Caveats

This is just a proof of concept. No promises, might be highly unstable. The list isn't comprehensive.

  • Soft keyboard not bridged. Hardware keyboard required for text input.
  • Input has rough edges. Hardware keyboard, mouse, trackpad, and touch all work for most flows, but some keystrokes / pointer events may not register or behave consistently. Touch scroll and drag are the most fragile; keyboard is the most reliable.
  • 60Hz on 120Hz panels. Haven't opted into 120Hz via ANativeWindow_setFrameRate yet.
  • Some extension-shipped LSPs are glibc-only and won't run. JVM/Node/Python LSPs work via Termux's bionic runtimes.
  • No collab / AI / livekit panels. Cfg-gated to mocks.
  • Sandboxed storage. /sdcard/ is FUSE-noexec; build inside ~/projects/.
  • MIUI / HyperOS aggressive battery management kills backgrounded Zed. Settings → Apps → Zed → Battery → "No restrictions".
  • Tested on Tab S9 Ultra only. Mali / Xclipse not tried.

 License

GPL-3.0-or-later, same as upstream Zed. The bundled bootstrap-aarch64.zip contains Termux-rebuilt packages, each under its own license (mostly BSD/MIT/Apache; gnupg/bash/coreutils are GPL). The Alpine-derived ld-musl-aarch64.so.1 is MIT.

© Dylan Murzello, distributed under GPL-3.0-or-later. Zed itself is © Zed Industries.


 Acknowledgments


 Contributing

Issues, screenshots, hardware reports, and PRs welcome. Read crates/gpui_android/docs/workarounds/README.md before adding a platform shim. Good chance the issue you're hitting has a documented workaround already, with the constraint that ruled out the obvious fix.


 So why this ?

Zed Industries' position on a mobile/tablet port: not planned.

This repo is what those threads were asking for, built independently. The Termux build attempt failed because the upstream wasmtime/cranelift deps don't compile inside Termux. We sidestep that by building the APK on a desktop with cargo-ndk and running our own custom Termux userland in process. No fork of upstream-Zed-with-android-cfg is needed; the Editor, Workspace, Project, Search, GitGraph, Terminal, Extensions crates run unchanged. The work is at the platform boundary, documented in crates/gpui_android/docs/workarounds/.

About

Native Android port of the Zed code editor, gpui rendering through Vulkan, integrated Termux for LSPs and tooling, remote SSH support. Runs as an APK on tablets and Android desktop modes. Proof of concept

Topics

Resources

License

Unknown and 2 other licenses found

Licenses found

Unknown
LICENSE-AGPL
Unknown
LICENSE-APACHE
GPL-3.0
LICENSE-GPL

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors