Skip to content

logseq/bonsai-native

Repository files navigation

bonsai-native

bonsai-native is an OCaml native UI experiment for sharing state and actions across iOS, macOS, and Android while leaving rendering to each platform UI.

The app UI is authored in OCaml. Platform code is only the renderer bridge:

OCaml graph component
  -> bonsai_native node tree
  -> platform renderer + event table
  -> Android JNI / Apple SwiftUI bridge
  -> Jetpack Compose / SwiftUI
  -> native app UI

This is not a WebView and not a SwiftUI wrapper.

Packages

  • bonsai_native: shared OCaml graph state runtime, node DSL, JSON/event bridge, and app driver.
  • bonsai_android: Android facade over bonsai_native; rendered by Kotlin Compose through JNI.
  • bonsai_apple: iOS/macOS-facing API and renderer abstractions; SwiftUI is the maintained Apple backend.

Backend package names intentionally remain explicit. Existing Android code can continue to open Bonsai_android, and iOS code can continue to open Bonsai_apple.

OCaml UI Example

let component graph =
  let count, set_count = Bonsai_android.state graph ~key:"count" 0 in
  Bonsai_android.vstack
    [ Bonsai_android.text (string_of_int count)
    ; Bonsai_android.button "Increment" ~on_click:(set_count (count + 1))
    ]

On Android, Compose receives a native node tree JSON payload and sends event ids back to OCaml through JNI. OCaml owns the graph driver and event table, so state updates stay shared above the platform renderer.

Repository Layout

  • native/: shared bonsai_native implementation.
  • src/: Android OCaml facade.
  • android/: Gradle/Compose demo app.
  • android/examples/: Android demo components, native entrypoint, and asset export helpers.
  • android/jni/: Android JNI bridge into OCaml.
  • apple/: Apple OCaml package, SwiftUI backend, and iOS/macOS examples.
  • web/demo/: browser demo for the shared Android demo components.
  • scripts/: Android and iOS bootstrap/build helpers.
  • docs/: architecture and platform build notes.

Android Quick Check

Use a switch with the Android cross compiler and Jane preview packages. The current working path is documented in docs/android-native-build.md.

export BONSAI_NATIVE_OPAM_SWITCH=/path/to/your/ocaml-android-switch

scripts/build-android-native.sh
cd android
rtk proxy ./gradlew :app:assembleDebug

The debug APK should contain:

lib/arm64-v8a/libbonsai_android_counter.so

Run the emulator smoke test:

scripts/test-android-emulator.sh

It installs the APK, launches the counter, taps Increment, and verifies the UI changes from 0 to 1. It also switches through the Android Todo and Search tabs, which mirror the current iOS demo tabs.

iOS Quick Check

The iOS package is under apple/ and builds through opam-cross-ios contexts. See docs/apple-native-build.md.

The simulator app target is:

opam exec -- dune build apple/examples/BonsaiNativeDemos.app \
  --workspace dune-workspace.simulator

Status

Working now:

  • Shared OCaml DSL for text, button, text fields, stacks, scroll views, keyed lists, navigation stacks, images, custom views, and common modifiers.
  • Android JNI native library built with OCaml 5.2.1 and the local graph runtime.
  • Android Compose renderer loads real native OCaml state and dispatches clicks back into OCaml.
  • Android and iOS demo apps expose the same Counter, Todo, and Search OCaml views.
  • Apple source/backend scaffolding is included in the same repo.

Still early:

  • Android release-size optimization.
  • More complete iOS packaging automation.
  • AppKit backend.
  • Shared persistence/sync packages above the UI layer.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors