cargo-makepad is not a generic packager. Its Android half carries the
Java activity (tools/cargo_makepad/src/android/java/dev/makepad/android/ MakepadActivity.java), and that activity is the Android side of the
framework: every JNI call the Rust backend makes lands in a method the
activity declares. The tool compiles that Java from the checkout it was
built in — its own CARGO_MANIFEST_DIR is baked into the binary — while
the Rust comes from the pinned checkout .sources/makepad (prepared by
python3 scripts/setup-home.py) through the [patch] section of
Cargo.toml, whatever tool runs the build. So the tool and the framework
must come from the same fork revision, and the installed binary is the one
thing the pin cannot see.
Measured on 2026-09-18, fork OctoSense-org/makepad main at 6e5898fe
against upstream makepad/makepad at 16ccd92:
tools/cargo_makepad/src/… |
Upstream | Fork | Differing lines |
|---|---|---|---|
android/java/…/MakepadActivity.java |
3104 lines | 4395 | 1301 |
android/java/…/MakepadNative.java |
91 | 134 | 43 |
android/compile.rs |
3281 | 3324 | 45 |
font_assets.rs |
807 | 852 | 45 |
apple/compile.rs |
1383 | 1383 | 0 |
android/mod.rs, MakepadNetwork.java and open_harmony/compile.rs differ
too. Almost all of it is the activity. What it has that upstream's does not:
- The system browser —
spawnSystemBrowser(long, String, boolean)and its WebView overlay, behind the News reader and the web app cards. - The HOME intent forward —
onHomeIntent, which is what lets OctoSense be the phone's Home app. - Deep links and share intents —
onDeepLink. - One activity instance per process —
sNativeActivity: a launcher started by a plain component intent gets a second instance from the Home button, and the older one must stop reaching native (MOBILE-05). - In
font_assets.rs: this crate buildssrc/main.rsas a lib and a bin, so the binary carries two identical font manifests; the fork's packager accepts that, upstream's refuses it.
Upstream's tool will therefore never build this app correctly; that is
expected, not a bug. If these features are to reach upstream one day,
MakepadActivity.java is the file, and the diff is about 1300 lines.
A stock tool with the fork's Rust builds and installs without complaint —
the Rust compiles against .sources/makepad either way — and fails at the first
JNI call the stock activity lacks. With News that is the first tap on a
headline:
Android panic hook: … payload=JNI method not found:
spawnSystemBrowser(JLjava/lang/String;Z)V — the makepad buildtool is out
of sync with the framework.
The render thread is gone after that panic; the shell keeps its last frame
and stops responding, and the log shows surfaceOnSurfaceDestroyed: render thread did not acknowledge within 2s. Force-stop the app and rebuild with
the right tool.
cargo makepad runs ~/.cargo/bin/cargo-makepad. Install the fork's tool
there once, and again whenever the fork's tool code or Java changes (a pin
move that touches tools/cargo_makepad is the usual trigger):
# from the repository root
cargo install --path .sources/makepad/tools/cargo_makepad --forceThe shared release selects Makepad main d653bc44, which includes App Hub's
isolate containment (#22), contained script apps (#30), the QR scanner
(#31), Splash reapply_text (#35) self-confirmed assistant tools (#36) and the one-call-site Slug, cursor and glass shaders (#37, #39), the terminal's confirmed runs (#41), trackpad scrolling (#42), gestures (#46), Chinese text (#48), tabs and installed fonts (#47), and every app's system-font fallback (#49, #51), WebReader's close ending the page (#43), the OpenHarmony packager's workspace target dir (#52), the sys.dataset and sys.news_digest helpers (#53) the peer-link client (#54), the Linux Vulkan build (#45), the map's hosted-archive source (#55) HTTPS on OpenHarmony (#56) the keyboard's hide after a cancelled search (#57, #59) and the terminal's tab titles, wide-character reflow, non-blocking PTY writes, control-request timeout and running-job close confirmation (#61–#65), and its grapheme clusters, Kitty keyboard and synchronized output, close handshake and rendering polish (#66–#69), text shaping and drag-select (#70–#72), clickable links and scrollback search (#73, #74), keyboard shortcuts (#76) and OpenHarmony run (#91), GL GPU timing (#81), atlas text on phones (#82), the Android touch-down power hint (#83) and Vulkan without a debug messenger (#92), Linux GL remote grabs (#93), a hidden map's idle frame loop (#79), and OpenHarmony's keyboard, Studio, GL lifetimes and idle frames (#84, #85, #87–#89), a library target and an own agent for each Makepad app OctoSense makes native (#94, #95), hosted Notes and Reminders that start empty (#96), Files' read-only chat panel (#97), a CEF profile under MAKEPAD_HOME (#98), Calculator's keypad laid out again after every apply (#99), the Terminal's own agent with its read tools only (#100) the kernel port for an app that is an octos client (#101), the renderer, Android, Linux and TextFlow work of #110–#116, and no per-app Splash runtime gates (#117, #118); the consumer lock
needs no makepad_override.
To see which checkout an installed tool reads its Java from:
strings ~/.cargo/bin/cargo-makepad | grep -o '/[^ "]*tools/cargo_makepad' | sort -uThe Android toolchain lives under the tool's own directory
(tools/cargo_makepad/android_33_macos_aarch64); cargo makepad android install-toolchain puts it there, or a symlink to another tool's copy does.
Nothing checks that the installed binary was built from the pinned fork:
tools/setup-native.py --check verifies the sibling checkouts and the
Cargo graph, not ~/.cargo/bin. A check in the tool (compare its baked
checkout against the fork revision the manifests pin) or in
setup-native.py would close it.