これまでこのシリーズのサンプルはすべて画面ファイルをアプリの隣に置いた。.mbd フォルダがクライアントと一緒に配布される。
両者の持ち主が同じならそれで正しい。 画面を変える人とアプリを配布する人が同じ人だからだ。
問題は画面の持ち主がアプリの持ち主でないときだ。
- ロビーに掛かったディスプレイ — ビル管理者が画面を変えたい
- フランチャイズ店舗のボード — 本部が変え、店主は触らない
- メーカーが出荷するパネル — 画面はメーカーのもの、アプリは統合業者のもの
こういう場合に画面をアプリに入れておけば、画面を変えるたびにアプリを再配布しなければならない。 そしてその配布は、画面を変えたい人にはできない。
クライアントが何も持たない
client ships: no library files at all, and no lib/ directory
server offers: ui://board, data://board
このサンプルのクライアントにはlib/ ディレクトリ自体がない。 .mbd バンドルもない。画面を説明するファイルがクライアント側に一枚もない。
検証がそれを守る。
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; }
この検査がこの編のすべてだ。後で誰かが「便宜上」画面ひとつをクライアントに置いた瞬間に失敗する。
サーバーが画面をリソースとして出す
// 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(),
),
],
),
);
画面とデータが別のリソースだ。ui://board と data://board。
分けた理由は更新の頻度が違うからだ。価格は一日に何度も変わり、レイアウトは季節に一度変わる。一緒に束ねておけば、価格ひとつ変えるたびにレイアウト全体がまた来る。
最初の画面

drew "Board v1" (sha256:592cd36cd4d0, 59 lines) — generation 1
クライアントはこの画面を初めて見る。 コードのどこにも「Americano」も「価格は右揃え」もない。