Service
Raw access to a host-registered headless service — the UI-less sibling of NativeView.
A service is native code the host registered under a name
(engine.registerService("app.battery") { params, channel in … } on iOS); the app talks to
it over a JSON call/event session. First-party services ship with typed wrappers
(Geolocation, Push) — Service is for everything else: native
code you wrote in your own app shell and third-party plugins that don't ship a wrapper library.
Host-optional, like every plugin: the web editor registers no services, so always gate on
Service.isSupported(name).
if (Service.isSupported("app.battery")) {
const battery = Service("app.battery")
battery.on("change", data => { levelText.text = data.level + "%" })
const { level, charging } = await battery.call("level")
}API
Service(name, params?)— a client for the named service. The host session opens lazily on the firstcall();paramsare handed to the host factory at that moment.Service.isSupported(name)— whether this host registered a factory undername..call(method, ...args)— invoke a method; arguments and the result are JSON-serialized. Rejects when the host has no such service, or the native side reports an error..on(event, cb)/.off(event, cb)— subscribe to events the service emits while a session is open. Payloads arrive JSON-decoded..close()— close the host session (the native side stops whatever it was doing). Listeners stay registered; a latercall()opens a fresh session that delivers to them again.
Naming
First-party services own bare names (geolocation, push). Name app-local services app.*
(app.battery) and third-party plugin services with a vendor prefix (acme.bluetooth) —
bare names are reserved for the SDK.
For a one-off synchronous value (no events, no async), the host-side
engine.registerCallback("native.thing") { … } injecting a plain global can be simpler than
a service — see the app-shell docs. Reach for Service as soon as you need events, async
work, or session state.