Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTING_IDEAS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ October 2026; "fork" means the fix is on one of the branches listed in
screen in 3.3–3.6 s through an ssh adb tunnel, state kept) and reloads
the library without reinstalling (8.3 s). gpui-mobile only needs a
loader for the pushed library (`GpuiLibraryLoader`, fork branch
`dev-hot-loader`). Next: ask upstream where they want it. A desktop-hosted
`dev-hot-loader`). Next: ask upstream where they want it
([issue draft](docs/upstream/hot-reload-discussion.md)). A desktop-hosted
phone-size preview is not started.
5. **Binary size.** Measured in [docs/binary-size.md](docs/binary-size.md);
every PR's job summary shows the APK and `.so` sizes.
Expand Down
3 changes: 2 additions & 1 deletion MOBILE_PATCHES.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ has pushed one, else the packaged library. Release builds always load the
packaged one. It replaces the `loadLibrary()` the lab's `LabActivity`
carried; `build.sh` copies it with the other helpers. Host-driven Activities
only (`NativeActivity` loads the packaged library itself). Not proposed
upstream yet.
upstream yet: an [issue draft](docs/upstream/hot-reload-discussion.md) asks
the maintainers first.

### Clear the Java exceptions the accessibility bridge leaves pending — branch `android-a11y-clear-exceptions`, now part of `android-accessibility`

Expand Down
1 change: 1 addition & 0 deletions docs/upstream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ captures in [../demos](../demos) and say where a capture is missing.
| 17 | kit | `input-purpose` (fork branch only) | ⛔ | #4, plus the same GPUI change; conflicts with `main` (to rebase then) | yes | — |
| 18 | mobile | `android-activity-requests`, `android-picker-files` (fork only) | ⛔ | the JNI rework (issue #31): built on its `jni.rs` | partly ([picker screenshots](../demos/platform-apis)) | — |
| 19 | mobile | `android-string-arrays` (fork only) | ⛔ | #6, plus the JNI rework (#31): `contacts/android.rs` was rewritten there | no | — |
| 20 | mobile | [`dev-hot-loader`](https://github.com/Bombatomica64/gpui-mobile/tree/dev-hot-loader) (`GpuiLibraryLoader`) | ⏳ ask first: an issue asking where hot reload should live; the PR only if they want it | — | phone strip from the A1 spike | [issue draft](hot-reload-discussion.md) |

Notes on the triage:

Expand Down
89 changes: 89 additions & 0 deletions docs/upstream/hot-reload-discussion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Draft: hot reload for gpui-mobile apps (not posted)

> **Status: draft for review, not posted.** longbridge/gpui-mobile has GitHub
> Discussions turned off, so this would be an **issue**. Title:
> "Hot reload for Rust on Android: interested, and where should it live?"

---

Hi! While building a test app on gpui-mobile we made Rust hot reload work on
Android, and we'd like to know whether you find it useful and where you'd
like it to live.

## What it is

[cargo-gpui](https://github.com/Bombatomica64/cargo-gpui) is a small dev tool
plus an app-side crate:

- **Hot patching.** On save, `cargo gpui dev` recompiles only the app crate,
links a small patch library against the running app and pushes it. The app
swaps in the new code between frames, and the screen, typed text and view
state stay. It's built on [Subsecond](https://docs.rs/subsecond) from
[Dioxus](https://github.com/DioxusLabs/dioxus); the patch builder adapts
parts of the Dioxus CLI (`dx serve --hotpatch`), with credit and its MIT
notice in the repo.
- **Reload without reinstalling**, for the changes a patch can't make (struct
layout, dependencies): the tool rebuilds the library, pushes a zstd delta
(~1.4 MB) and restarts the app on the same screen. No Gradle, no APK
install.

Views opt in with an attribute on their `Render` impl:

```rust
#[gpui_hot::hot]
impl Render for Counter {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div().child(format!("{}", self.count))
}
}
```

It's debug-only: release builds compile the hooks to nothing.

## Numbers

Measured on a OnePlus phone (Android 16) reached over an ssh adb tunnel,
with a 32-screen test app:

| Step | Time |
|---|---|
| Save → change on screen (patch) | 3.3–3.6 s |
| Reload with a 1.4 MB delta, same screen | 8.3 s |

Over USB the push part (~1.5 s of each patch) should shrink; we haven't
measured that yet.

![Patches applied on the phone](https://raw.githubusercontent.com/Bombatomica64/Gpui-android/main/docs/demos/subsecond-buttons-patches.png)

*From our first prototype: a title, a colour and a layout changed live while
the click counter kept its value (3).*

## How it's split

- **Outside gpui-mobile** (the repo above, MIT OR Apache-2.0): the
`cargo gpui` CLI, the `gpui-hot` crate and its attribute macro. They depend
on GPUI and Subsecond, not on gpui-mobile.
- **Inside gpui-mobile**, one small piece: a Java helper,
`GpuiLibraryLoader`, that a host-driven Activity calls instead of
`System.loadLibrary`. In a debuggable build it loads
`files/dev/lib<name>.so` when a dev tool has pushed one; release builds
always load the packaged library. It's opt-in, about 50 lines, and adds no
Rust code or dependency. It's on our fork as branch
[`dev-hot-loader`](https://github.com/Bombatomica64/gpui-mobile/blob/dev-hot-loader/example/android/gradle/app/src/main/java/dev/gpui/mobile/GpuiLibraryLoader.java),
based on your `main`.

## Questions

1. Is this useful to you?
2. Where would you like it?
- keep it as a separate project that apps opt into;
- move the tool under longbridge;
- or bring it into gpui-mobile itself.
3. Would you take `GpuiLibraryLoader` as a small PR? We can open it
whenever you like.

Known limits: Android arm64 debug builds only; host-driven Activities only
for reloads (`NativeActivity` loads the packaged library itself); statics in
the app crate restart from their initial values after a patch.

Thanks for gpui-mobile!
Loading