Target · Android

GEA on Android

What ships is a native Android app: geatsc compiles your UI to C++ and the NDK builds it into a native library, and every component node reconciles to a real Android view.

npx create-geastack
A GEA watch companion app running natively on Android
Surfaces

The same components, rendered as Android views

The same components that run on a microcontroller, on iOS or on a Linux panel reconcile to native Android views here. You keep one codebase, and each platform renders it with its own widgets.

A GEA home-screen UI with live widgets running natively on Android
AppHome
A GEA watch companion app running natively on Android
AppWatch companion
A GEA lock-screen UI running natively on Android
AppLock screen
A GEA quick-settings control panel running natively on Android
AppControls
A GEA assistant UI running natively on Android
AppAssistant
A GEA light-control sheet running natively on Android
AppLight control

Drag or scroll to explore

Same code

The UI is ordinary TypeScript

These are the same GEA components you run on every other target. geatsc reads each one at build time and lowers it to C++, which the Android NDK and CMake build into a native library. The app that ships carries no WebView and no JavaScript engine.

import { ReactiveComponent } from 'gea-embedded'

// One component, one reactive field. geatsc lowers count to a typed Signal;
// each tap runs a typed method whose write re-renders only the dependent node.
export class Counter extends ReactiveComponent {
  count = 0

  template() {
    return (
      <div class="counter">
        <span class="count">{this.count}</span>
        <button onClick={() => this.count++}>+</button>
      </div>
    )
  }
}
How it renders

Component nodes map to native Android views

Each node in your component tree becomes a native Android view. When it renders a frame, the native engine runs the app and computes the layout and style tree, then a thin JNI bridge (GeaNativeBridge.nativeFrame(...)) hands the result to Java as node descriptors, not as pixels. A custom GeaNativeView, set as the activity's content view by MainActivity, reconciles those nodes onto real Android views: a Text node is a TextView, every other node a FrameLayout. The renderer keeps one view per node, keyed by node id, reuses it across frames, and rebuilds it only when the node's type changes. Rendering is dirty-driven: the view re-syncs when something changes — a state update, an animation, a touch — and schedules the next frame through Choreographer only while the engine reports it still has work (nativeNeedsFrame).

// one native Android view per node, chosen by node type
View createView(int type) {
  if (type == TYPE_TEXT) return new TextView(context); // Text  → TextView
  return new FrameLayout(context);                     // View / list → FrameLayout
}

Style maps straight onto the view: background colour, corner radius and border come from a GradientDrawable, and opacity from the view's alpha. Text is laid out with Android's own text stack — during layout the engine calls back into a TextPaint / StaticLayout pass to measure each string — and drawn from fonts bundled in the app's assets through Typeface.createFromAsset. Input flows back through the same bridge as native pointer events: touches (down, move, up, multi-touch) and view clicks hit-test to a node, and your handler runs. There is no WebView and no JavaScript engine on the device; the native renderer reports itself as native-android-views.

Build & run

One command, no Gradle

The GEA CLI drives the Android SDK command-line tools for you. The NDK and CMake compile the native library, then aapt2, d8, zipalign and apksigner assemble and sign the APK. There is no Gradle.

# build and sign a debug APK → targets/android/dist/<app>/
npx gea build --app tic-tac-toe --target android

# build, install and launch it on a connected device over adb
npx gea flash --app tic-tac-toe --target android

gea build produces a signed debug APK under targets/android/dist/<app>/; gea flash --target android also installs and launches it over adb, and gea monitor --target android tails logcat. The minimum SDK is 23; the Android SDK is found under ANDROID_HOME or ANDROID_SDK_ROOT, and the device serial, ABI (default arm64-v8a), signing keystore, package name and screen orientation (default portrait) are all configurable through GEA_ANDROID_* environment variables.

See it running