Developer docs

Build an app

SpringBoard is the compositor and system UI. Every app is its own process, drawing into shared memory and talking to the shell over a socket. Apps install from this store.

Specification stage. The split of the built-in apps into separate processes is being written against this spec. Details below can still change; the SDK sdk_version number rises on breaking changes.

Process model

Frames

Configure { w, h, scale, safe_top, safe_bottom, dark, text_scale, reduce_motion }

Messages

One message per SOCK_SEQPACKET packet, little-endian, with a u32 tag first. Unknown tags are ignored, so newer shells and older apps keep working.

DirectionMessages
Shell to appConfigure, Touch { kind: down|move|up|cancel, id, x, y, t_ms }, Key { text | keycode }, Release { buf }, Resume, Suspend, Quit, Open { url }
App to shellHello { sdk_version, app_id }, Buffers { w, h } (+ 2 fds), Frame { buf, damage: [x,y,w,h]* }, WantsKeyboard { on }, Haptic, OpenUrl { url }, Notify { title, body }, Log { text }

The exact byte encoding lives in springboard/sdk/src/proto.rs, shared by the shell and the SDK, with round-trip tests on both sides.

Package format

An .aap (AndroiOS app package) is an uncompressed POSIX tar holding manifest.toml, the executable, the icon and an optional assets/ directory.

id          = "is.olibuijr.calculator"   # reverse DNS
name        = "Calculator"
version     = "1.0.0"                    # semver
exec        = "bin/calculator"           # path inside the package
icon        = "icon.png"                 # 180x180 PNG
min_shell   = "0.1.0"
summary     = "A basic calculator."
category    = "Utilities"
permissions = ["network", "audio", "camera", "storage"]
tar --format=posix -cf is.olibuijr.calculator-1.0.0.aap manifest.toml bin icon.png assets

On the tablet, an install unpacks to /data/local/springboard/apps/<id>/<version>/ and points a current symlink at it. The previous version is kept until the new one has launched once, so a broken update can roll back. The tablet verifies the sha256 of every download before installing it.

SDK

The androios-app crate (in the repository under springboard/sdk) wraps the socket, buffer allocation and message loop, so an app implements a few callbacks and draws pixels. Shape of an app, sketched from the protocol above; the crate API is not final.

// Cargo.toml: androios-app = "0.1"
// cargo build --release --target aarch64-linux-android
use androios_app::{run, App, Config, Event, Frame};

struct Hello;
impl App for Hello {
    fn configure(&mut self, cfg: &Config) { /* resize your canvas */ }
    fn event(&mut self, ev: Event) { /* Touch, Key, Resume, Suspend ... */ }
    fn draw(&mut self, frame: &mut Frame) { /* write premultiplied RGBA8 */ }
}
fn main() { run(Hello) }

Store API

RequestReturns
GET /api/v1/apps.json{ "apps": [ { id, name, version, summary, category, size, sha256, icon, package, min_shell } ] } for the newest version of each app.
GET /store/<id>/<file>Package and icon files. Versioned .aap files are immutable and cached for a year. Range requests are supported.
GET /ota/springboard/latest.jsonShell update manifest (version, build, sha256, size, url) plus the binary next to it.
POST /diag/<name>Diagnostics upload, accepted only on the local network and not exposed on this public site.

icon and package are site-relative paths. Live data: /api/v1/apps.json.

Publishing

The store is a folder per app, data/store/<id>/, holding every .aap plus icon.png. The index reads the manifest out of the newest package; there is no database. Publishing is a copy, done by the maintainer:

tools/publish-app.sh is.olibuijr.calculator-1.0.0.aap
tools/publish-ota.sh springboard --version 0.1.0 --build 2e9d2423994a

The first command copies the package, extracts its icon and the index updates at once. A published version is immutable, so bump version for every change. The second command is run by tab publish for shell updates. Submissions from other developers are not open yet.