← ブログ

透明性ダッシュボードをポケットに

Kotlin Multiplatform Compose Android エンジニアリング
透明性アプリをスワイプする様子:概要、政府による削除要請、データセットブラウザ、ライブチャートを、すべて電話の画面フレーム内で表示
概要 → 削除要請 → データセットブラウザ → ライブチャート。すべて同じAPIから。

透明性クエリAPIには、以前からWebダッシュボードがあった。なかったのは、ホーム画面のアイコンだ。そこでデータエクスプローラーをネイティブアプリにした——単一のKotlin Multiplatformコードベースから、Androidでもデスクトップでも動作し、Webサイトとまったく同じ公開APIと通信する。

Android版をダウンロードして、今すぐサイドロードできる。

そもそもなぜアプリなのか

このデータの多くは、腰を据えて研究するものではなく、ちょっと確認するものだ——削除の傾向、あるプラットフォームの数値が別の数値とどう比べられるか、ある国の要請が今期どうなっているか。それはデスクトップではなく、電話での操作だ。広い画面とマウスを前提としたダッシュボードは、その手軽な確認を必要以上に難しくする。このアプリは逆から作られている。まず電話、そして広いレイアウトはそこから広がるものであって、その逆ではない。

一つのコードベース、二つのプラットフォーム

意味のあるものはすべて、一つの共有ソースセットに収まっている。DTO、/api/overview/api/exploreを呼び出すKtorクライアント、各クエリを組み立てるリポジトリ、そしてすべての画面とチャートだ。Compose Multiplatformが、その同じUIをAndroidでもデスクトップウィンドウでも描画する。プラットフォームごとに異なるのは二つだけ——エントリポイント(AndroidではActivity、デスクトップではウィンドウ)と、HTTPエンジンだ。後者はKotlinのexpect/actualで結線され、AndroidではOkHttp、デスクトップではCIOが使われる。同期を保つべきアプリの二つ目の実装は存在しない。二つ目の実装そのものがないからだ。

APIを誠実に保つのと同じ規律が、クライアントにも引き継がれている。SQLは決して送らない。クエリは構造化されたExploreRequest——テーブル名に、型付きのフィルタ、グループ化、集計を加えたもの——であり、サーバーがそれを検証してコンパイルする。アプリはそうしたリクエストを組み立てるのであって、文字列を組み立てるのではない。新しいデータセットビューを追加するのは、手書きのクエリではなく、リポジトリのメソッドだ。

モバイルファースト、それも本気で

レイアウトは自らの幅を測って適応する。ブレークポイントを下回ると電話になる。ボトムナビゲーション、単一カラム、そして小さな画面で期待どおりにリスト→詳細と進むExploreフローだ。それを超えると、同じ画面がナビゲーションレールとマスター・ディテールビューへと広がる。画面がステートレスだから——状態は単一のビューモデルに巻き上げられ、不変のUI状態をStateFlowとして公開する——まったく同じコンポーザブルが、電話でも、デスクトップウィンドウでも、上のフレームを生成したスクリーンショットハーネスでも描画される。

チャートは画像サービスから取得するのではなく、Composeのキャンバス上に描画される。だからどんな解像度でも鮮明で、示す内容に誠実だ——帯は帯のままで、率が合計されることはなく、データのない期間はゼロではなくデータなしとして読める。

手を抜かないAndroidのディテール

ネイティブアプリはネイティブに感じられるべきで、それは小さな工夫の積み重ねだ。テーマ対応アイコン用のモノクロレイヤーを備えたアダプティブランチャーアイコン、削除要請ビューやデータセットブラウザへ直接飛べるランチャーショートカット、システムの戻るジェスチャーで遷移先をプレビューできる予測型戻る(predictive-back)、そしてAndroid自身の一覧に表示されるアプリごとの言語設定——アプリはすでに8言語に翻訳されているので、そこで選んだ言語を尊重する。リリースビルドはリソース圧縮を伴うR8を通しており、それによってフル機能のComposeアプリが約1.5MBに収まる。

入手する

Android APKは直接ダウンロードできる——ブラウザからのインストールを有効にして開くだけだ。データも、クエリモデルも、留意点もWebダッシュボードと同じで、それがいまホーム画面に載っているだけだ。ウィンドウで使いたければ、同じコードベースからデスクトップビルドも動く。

esc