This is not a specific business. We constructed the shape exactly as a shop menu board works. The name and prices are invented; the code, screens and logs actually ran.
Every sample in this series so far kept its screen files next to the app. The .mbd folder ships with the client.
When both have the same owner, that is right. The person who changes the screen and the person who deploys the app are the same person.
The problem is when the screen's owner is not the app's owner.
- A display in a lobby — the building manager wants to change the screen
- A franchise shop board — head office changes it and the operator does not touch it
- A panel a manufacturer ships — the screen is the manufacturer's and the app is the integrator's
In these cases, putting the screen inside the app means redeploying the app every time the screen changes. And the person who wants to change the screen cannot do that deployment.
The client holds nothing
client ships: no library files at all, and no lib/ directory
server offers: ui://board, data://board
This sample's client has no lib/ directory at all. No .mbd bundle either. Not one file describing a screen sits on the client side.
The verification protects that.
STRAY=$(find bundle_host -name '*.json' -not -path '*/.dart_tool/*' -not -path '*/build/*' -not -name 'package_config.json' | wc -l | tr -d ' ')
[ "$STRAY" -eq 0 ] || { echo " $STRAY json file(s) on the client — it is not screenless"; exit 1; }
[ ! -d bundle_host/lib ] || { echo " the client has a lib/ — it should need none"; exit 1; }
MBD=$(find . -maxdepth 1 -name '*.mbd' | wc -l | tr -d ' ')
[ "$MBD" -eq 0 ] || { echo " there is a bundle here — this sample serves the screen instead"; exit 1; }
That check is the whole of this piece. The moment somebody later puts one screen on the client "for convenience", it fails.
The server exposes the screen as a resource
// The screen itself, as a resource. A client that can read this needs to
// ship nothing.
server.addResource(
uri: _screenUri,
name: 'Board screen',
description: 'The screen definition this board should draw',
mimeType: 'application/json',
handler: (uri, params) async => ReadResourceResult(
contents: [
ResourceContentInfo(
uri: _screenUri,
mimeType: 'application/json',
text: File(_live).readAsStringSync(),
),
],
),
);
The screen and the data are separate resources. ui://board and data://board.
They are split because their update rates differ. Prices change several times a day; the layout changes once a season. Bundle them and the whole layout comes down again every time one price changes.
The first screen

drew "Board v1" (sha256:592cd36cd4d0, 59 lines) — generation 1
The client is seeing this screen for the first time. Nowhere in its code is "Americano" or "prices right-aligned".
The owner changes the screen
owner: board now draws screens/v2_cards.json
the board was told 1 time(s) that something changed
drew "Board v2" (sha256:9dced318ad23, 88 lines) — generation 2
screen changed: sha256:592cd36cd4d0 -> sha256:9dced318ad23,
same process, no restart, nothing rebuilt

Same process. No restart, no build, no install.
The layout changed entirely. The list became cards, the header gained a background, each item gained a note. The data is unchanged — the note field was always there; the v1 screen simply did not draw it.
That it changed is announced by the server. It is the same notification used in The Screen That Never Asks.
_live = file;
// Two things changed: what to draw, and what the footer says. Say both.
server.notifyResourceUpdated(_screenUri);
server.notifyResourceUpdated(_dataUri);
This content requires Developer or above
Sign in and upgrade your plan to continue reading.
View Plans