Android - TECH PLAY - TECH PLAY

TECH PLAY

Android

イベント

マガジン

技術ブログ

はじめに こんにちは。グローバルプロダクト開発本部 グローバルアプリ部 アプリ基盤ブロックの桂川です。普段はZOZOFIT・ZOZOMETRYなどの計測アプリのAndroid開発に携わっています。 今回、Figmaのデザインとアプリの画面の差分を検知しやすくするための仕組みづくりに取り組みました。これまで、Figmaとアプリの画面が一致しているかは、人が目で見比べて確かめるしかありませんでした。 そこで、Claude CodeのSkillを使い、AIが画像から画面の構造を読み取ってFigmaとアプリを比べ、見つかった差分をレポートにまとめる仕組みを試作しました。本記事では、この仕組みの検討内容と検証の結果を通じて、次のようなレポートを出力する、AIを利用した差分検知の構築方法を紹介します。 目次 はじめに 目次 背景・課題 FigmaとアプリのUIが食い違う問題 FigmaとアプリのUI差分を人力で検知するのは難しい 解決方法 実現方法の調査 FigmaとアプリのUI差分をどのように検知するか? FigmaとアプリのUI差分をAIに検知させるには? 検知機能の実装 構造抽出Skill 概要 入力 出力データ 処理手順 差分比較Skill 概要 入力 出力データ 処理手順 レポート出力Skill 概要 入力 出力データ 処理手順 検知機能の評価 ステップ1:Figmaデザインと、差分を仕込んだAndroidアプリを用意する ステップ2:動作環境をセットアップする ステップ3:Figmaとアプリの差分を解析する 構造抽出Skillを実行する 差分比較Skillを実行する レポート出力Skillを実行する 結果 レポート画面 ステップ4:Claude Codeでアプリを修正する 修正プロンプト ステップ5:再実行して改善しているかチェックする 結果 レポート画面 今後の課題 画像の取得の自動化 画像の取り扱い 差分比較のルールの改善 実行時間とコストの削減 まとめ 背景・課題 FigmaとアプリのUIが食い違う問題 VRT(Visual Regression Testing)を使えば、実装による見た目の変化は検知できます。しかし、最新のFigmaのデザインとアプリの実装との差分は検知できません。そのため、次のようなケースで生まれた差分に、開発を進める中で気づけないことがありました。 アプリ側で画面を実装した際に、Figmaのデザインと完璧にはそろわず、そのまま差分として残る Figma側でデザインを更新した際に、アプリ側の画面実装と違いが生まれ、そのまま差分として残る FigmaとアプリのUI差分を人力で検知するのは難しい このような差分は、見つけること自体が簡単ではありません。実装工程とテスト工程で画面を確認していても、FigmaとアプリのUIが一致しているかは、人が目で見比べるしかありませんでした。そのため、次のような理由で差分を見落としやすくなっていました。 英語の文言の大文字と小文字の違いは、違いがわずかなため気づきにくい メニューや入力欄の並び順、項目の表示の有無の違いは、デザインと見比べても気づきにくい こうした差分は、仕様の取り違えや開発工程での確認漏れから生まれることもあります。気づかないまま食い違いが残ってリリースされ、いくつものバージョンをまたいでしまうこともあります。 解決方法 こうした問題は、FigmaとアプリのUI差分を自動で検知する仕組みがあれば解決できると考えました。Figmaのデザインを唯一の正解とし、アプリの画面がそのとおりに実装されているかを定期的にチェックすれば、これまで人の目では気づけなかった差分も見つけて直せます。 そこで、次のような流れで差分を確かめる仕組みを構築することにしました。 実現方法の調査 FigmaとアプリのUI差分をどのように検知するか? 差分を自動で検知するやり方として、Figmaとアプリの画像を画素単位で比較する方法、アプリのUI階層をツリー構造で取得して比較する方法、画像をAIに渡して比較する方法の3つを検討しました。ここでは順に、ピクセル比較、UI階層比較、AI比較と呼びます。 手法 内容 ピクセル比較 Figmaから書き出した画像と、アプリのスクリーンショットを画素単位で比較する UI階層比較 AndroidのViewやComposeのセマンティクスツリーなど、アプリのUI階層を比較する AI比較 画像をマルチモーダルLLMに渡し、一致を判定させる 今回のチェックの目的は、人の目では見落としやすい差分を見つけることです。そのため手法を選ぶときは、ピクセル単位の細かな違いではなく、ユーザー体験に影響する次のような要素の違いを検知しやすいかを重視しようと考えました。 要素の違いを比べられるUI階層比較とAI比較が、今回の用途に合っていそうでした。AI比較は動作コスト(APIの費用や処理時間)が最もかかりそうですが、検知したい差分を指示で要素の違いに絞れ、画像を渡すだけで複数のプラットフォームを扱えるため、採用することにしました。3つの手法を、動作コスト、検出粒度・精度、拡張性の観点で比べた結果は次のとおりです。 手法 動作コスト 検出粒度・精度 拡張性(複数プラットフォーム対応) 判定 ピクセル比較 ○:機械的に比べるため速く、費用もかからない ×:文字のにじみなどまで拾い、要素の違いが埋もれる ○:画像があれば、どのプラットフォームでも比べられる 不採用 UI階層比較 ○:構造の比較は速く、費用もかからない △:要素の有無や並び順は比べられるが、Figmaとアプリで階層構造や領域粒度をそろえるのにコストがかかる △:プラットフォームごとに構造を取り出す仕組みが要る 不採用 AI比較 △:画像1枚ごとにAPIの費用と時間がかかる ○:何を差分とみなすかを指示で調整できる。ただし判定はぶれうる ○:画像をそのまま渡せる 採用 AI比較では判定がぶれることもありますが、数画面で試した範囲では大きく間違えることはほとんどありませんでした。また、今回検知したいのは要素の有無や文言の違いといった明らかな食い違いなので、もし間違えても、人間がAIの間違いを判断できると考えて採用しました。 FigmaとアプリのUI差分をAIに検知させるには? AI比較のやり方として、2枚の画像をそのままLLMに渡して差分を答えさせる方法と、画像ごとに画面の構造をJSONとして抽出し、JSON同士を比較する方法の2つを検討しました。ここでは前者を画像比較型、後者を構造比較型と呼びます。 方法 比較のときにLLMへ渡すもの 位置やサイズの比べ方 途中に残るもの 画像比較型(画像をそのまま渡す) Figmaの画像とアプリの画像 LLMが画像を見て判断する なし 構造比較型(画像を構造化してから比較する) 各画像から抽出した構造JSON 要素の座標とサイズを数値で比べる 構造JSON 同じ画像で、通常の画面と表示順序を入れ替えた画面の2パターンを両方の方法で試したところ、要素の有無や表示順序の入れ替わりなどの主な差分はどちらでも検知でき、大きな違いは見られませんでした。そこで、精度ではなく、次の2つの運用面の利点から構造比較型を採用することにしました。 認識結果を確認できる :構造JSONをもとに、認識した要素の番号と矩形を元画像に描けるため、LLMが画面をどう認識したかを目で確かめられる 再比較しやすい :構造JSONを一度出しておけば、画像をLLMに見せ直さなくても、比較する相手を変えて何度でも比較できる 検知機能の実装 調査で決めたAI比較と構造比較型に基づき、実装を進めていきます。今回は、開発者が定期的に実行できるフローとして組み立てることにします。開発者が画像やJSONを渡して依頼すると、Claude CodeがSkillを使って処理し、結果を開発者に返す流れです。 このように、差分の検知とレポートの作成はClaude Codeが行います。そのためClaude Code向けの構造抽出Skill、差分比較Skill、レポート出力Skillの3つのSkillを実装していきます。 実装するSkill Skill名 やること 入力 出力 構造抽出Skill ui-diff-structure 画像1枚から画面の要素を読み取り、表示順序、種別、テキスト、位置、サイズを構造JSONにまとめる Figmaの書き出し画像、またはアプリのスクリーンショット 構造JSON 差分比較Skill ui-diff-compare 同じ画面のFigma側とアプリ側の構造JSONを比べ、見つかった差分を警告Level付きで書き出す Figma側とアプリ側の構造JSON 警告データ レポート出力Skill ui-diff-report 全画面分の警告データを画面ごとに並べ、認識した要素の番号と矩形を描いた画像と一緒にHTMLレポートにする 構造JSONと警告データ HTMLレポート、番号と矩形を描いた画像 以降で説明するのが、実際に作成したSkillの仕様です。この仕様を満たすように SKILL.md を書き、期待どおりに動くSkillを作成しました。 構造抽出Skill 概要 画像1枚から画面に表示されている要素を読み取り、構造JSONに変換します。Figmaの書き出し画像とアプリのスクリーンショットのどちらにも、同じ手順を適用します。 /ui-diff-structure <input> <output> /ui-diff-structure input/figma/screen-01.png output/figma/screen-01.structure.json /ui-diff-structure input/app/screen-01.png output/app/screen-01.structure.json 入力 引数 内容 例 input 構造を抽出する画像のパス input/figma/screen-01.png output 出力する構造JSONのパス output/figma/screen-01.structure.json 出力データ キー 内容 meta.sourceImage 元画像のパス(後段のSkillが元画像を参照するときにたどる) meta.width 、 meta.height 画像全体の幅と高さ(px) elements[].order 上から下、同じ行の中では左から右の読み順に振った通し番号 elements[].type テキスト、ボタン、画像、アイコン、入力欄などの要素の種別 elements[].value 要素が持つテキスト(テキストを持たない要素では null ) elements[].x 、 elements[].y 画像の左上を原点とした、要素の左上の座標(px) elements[].width 、 elements[].height 要素の幅と高さ(px) { " meta ": { " sourceImage ": " path/to/screen.png ", " width ": 375 , " height ": 812 } , " elements ": [ { " order ": 1 , " type ": " text ", " value ": " 商品名 ", " x ": 24 , " y ": 60 , " width ": 200 , " height ": 32 } , { " order ": 2 , " type ": " button ", " value ": " 購入する ", " x ": 24 , " y ": 120 , " width ": 328 , " height ": 56 } ] } 処理手順 手順 処理 処理ルール 備考 1 画像全体の幅と高さを確かめる なし なし 2 縦に長い画像を分割する 高さが1,000pxを超える画像は、スクリプトで重なりを持たせながら分割し、分割した範囲ごとに座標を見積もる 一度に見ると、下の要素ほど座標の誤差が大きくなるため 3 画面に見える要素を1つずつ認識する 意味のある最小の単位で区切り、ボタンの中のテキストはボタン1要素の value として扱う 部品の単位で比べるため 4 要素ごとに種別、テキスト、位置、サイズを求める テキストを持たない画像やアイコンの value は null にする なし 5 order を振る 縦方向の範囲が重なる要素を同じ行とみなし、上の行から順に、行の中では左から順に振る 表示順序の入れ替わりの検知に使う 6 構造JSONを保存する なし なし 差分比較Skill 概要 同じ画面を表すFigma側とアプリ側の構造JSONを比べ、見つかった差分を警告データとして出力します。 /ui-diff-compare <figma> <app> <output> /ui-diff-compare output/figma/screen-01.structure.json output/app/screen-01.structure.json output/compare/screen-01.warnings.json 入力 引数 内容 例 figma Figma側の構造JSONのパス output/figma/screen-01.structure.json app アプリ側の構造JSONのパス output/app/screen-01.structure.json output 出力する警告データのパス output/compare/screen-01.warnings.json 出力データ キー 内容 source.figmaImage 、 source.appScreenshot 比べた2つの構造JSONの元画像のパス(それぞれの meta.sourceImage を写す) warnings 差分1件につき1つの警告を入れた配列(差分がなければ空の配列) warnings[].level 警告を見た人が次にとる対応を表す警告Level(修正、確認、参考のいずれか) warnings[].category 差分のカテゴリ(レイアウト・配置、テキスト内容、画像・アイコン、コンポーネントの状態、要素の有無のいずれか) warnings[].description 差分の内容を、対象の要素が何かが分かるように自然な文で書いたもの { " source ": { " figmaImage ": " path/to/figma.png ", " appScreenshot ": " path/to/screenshot.png " } , " warnings ": [ { " level ": " 修正 ", " category ": " 要素の有無 ", " description ": " Figmaにある「送料無料」バッジがアプリ画面に存在しない " } , { " level ": " 確認 ", " category ": " コンポーネントの状態 ", " description ": " 通知のトグルがFigmaではオンだが、アプリではオフになっている " } ] } 処理手順 手順 処理 処理ルール 備考 1 2つの構造JSONの座標を同じ基準にそろえる 画像の幅の比率だけをスケール係数にする 高さの比率も使うと、余白の違いで縦方向がゆがむため 2 Figma側とアプリ側の要素を対応づける 中心座標の近い要素同士を対応づけ、種別( type )が一致する候補を優先する 座標だけでは、表示順序が入れ替わった画面で対応を誤るため 3 対応する相手のない要素を確かめる もう片側の1要素の領域に収まり、その要素が同じ内容を含むなら、要素の有無の差分にしない。判断がつかなければ「参考」にする 同じ範囲を、片側では1要素、もう片側では複数の要素として抽出することがあるため 4 表示順序の入れ替わりを確かめる order の番号ではなく大小関係で判定し、メニュー項目1つ分のようなまとまりが入れ替わったときだけ警告にする 番号は、手前の要素の数が違うだけでずれるため 5 5つのカテゴリの観点で比べる 位置、余白、大きさの細かなpxの違いは警告にしない。色と文字の太さは比べない。「レイアウト・配置」では、手順4で見つけた表示順序の入れ替わりや、整列の崩れのような見て分かるほどの配置の違いを扱う 画像から見積もった値で、抽出のたびに揺れるため 6 テストデータの違いによる差分を除く 氏名や金額のように、アカウントやビルドで変わる値の違いは警告にしない。判断がつかなければ「参考」にする。一覧に並ぶデータの件数もこの決まりに含め、メニューの項目のような画面の部品の有無には当てはめない Figmaの仕様との食い違いではないため 7 差分ごとに警告Levelを決める Figmaの仕様に反すると明確に判断できる要素の有無、文言、表示順序の入れ替わりは「修正」、実装ミスと断定できないコンポーネントの状態などの差分は「確認」、OSのフォントレンダリングや解像度など実装で吸収しきれない差分は「参考」にする 重要度の高低ではなく、警告を見た人が次にとる対応を名前にしている 8 警告データを保存する 1件の警告には1つの要素の1つの違いだけを書く なし レポート出力Skill 概要 全画面の構造JSONと警告データを読み、警告を画面ごとに並べた1つのHTMLレポートにまとめます。レポートには、認識した要素の番号と矩形を元画像に描いた画像も並べます。 /ui-diff-report <figma> <app> <compare> <output> /ui-diff-report output/figma output/app output/compare output/report 入力 全画面の組み合わせを比べ終えてから、1回だけ呼び出します。 引数 内容 例 figma Figma側の構造JSONのディレクトリ output/figma app アプリ側の構造JSONのディレクトリ output/app compare 警告データのディレクトリ output/compare output レポートと画像を書き出すディレクトリ output/report 出力データ 引数 output で渡したディレクトリに、HTMLのレポートと、認識した要素の番号と矩形を描いた画像を書き出します。各出力の内容は次のとおりです。 出力 ファイル 内容 HTMLのレポート report.html 画面ごとに、Figmaとアプリの画像と警告の一覧を並べたレポート 番号と矩形を描いた画像 overlay/figma/<画面名>.png 、 overlay/app/<画面名>.png 組み合わせごとに、認識した要素の番号と矩形を元画像に描いた画像 処理手順 手順 処理 処理ルール 備考 1 2つのディレクトリの構造JSONを照合し、組み合わせを決める 同じファイル名の構造JSONを同じ画面の組み合わせとみなし、片側にしかない画面は比較する相手がいない画面として一覧に載せる 比べ忘れに気づけるようにするため 2 認識した要素の番号と矩形を元画像に描く 組み合わせごとに、スクリプトで描く 警告が指す要素を、画面の上で見つけやすくするため。PythonのPillowなどを使って描画する 3 全画面分を1つのHTMLに書き出す スクリプトで書き出す。左に組み合わせの一覧、中央にFigmaとアプリの画像、右に警告を並べ、中央の画像は番号と矩形の表示をボタンで切り替えられるようにする。警告は警告データに書かれたとおりに載せ、画像は埋め込まずに相対パスで参照する どの差分を直すかは、レポートを見た人が決めるため 検知機能の評価 差分を仕込んだアプリでレポートを作り、レポートをもとにClaude Codeでアプリを修正したあと、もう一度レポートを作って差分が残っていないかを確かめます。作成した検知機能がどのような差分を検知できるかを、次の5つのステップで評価しています。 ステップ1:Figmaデザインと、差分を仕込んだAndroidアプリを用意する 評価には、比べる元になるFigmaのデザインと、そのデザインを実装したアプリが必要です。そこで、次のようなFigmaのデザインと、それを再現したAndroidアプリを用意し、アプリにFigmaとの差分を意図的に仕込んで検知できるかを確かめることにします。 Figmaにはあるがアプリにはない画面も、1つ用意しました。ホームとプロフィールの画面は、差分を仕込まずにFigmaのデザインのとおりに作りました。画面の中に仕込む差分は、文言、要素の有無、表示順序に絞りました。色の差分や、文字の大きさ、余白の細かな差分は、差分比較Skillで警告の対象から外しているためです。仕込んだ差分は次のとおりです。 このFigmaとアプリから、比較に使う画像を書き出しています。後段のSkillが同じ画面の画像を組み合わせ、画面の内容の違いだけを比べられるよう、画像を書き出すときのルールは次のように決めました。 項目 決まり 理由 命名規則 同じ画面の画像にはFigma側とアプリ側で同じファイル名を付ける 後段のSkillは、ファイル名で同じ画面の組み合わせを照合するため 画像サイズ Figmaとアプリの画像は、同じ大きさ(例えば375×812px)にそろえる 大きさが違うと画面に収まる範囲が変わり、片側にしか写らない要素が出るため 画像内容 Figmaの画像は、ステータスバーを除いた画面フレームから書き出す アプリの画像にはステータスバーが写らず、Figma側にだけある要素として検知されるため このルールに沿って、Figmaの画像は画面フレームから書き出し、アプリの画像はプレビューを書き出しています。初回に書き出した画像は、Figmaとアプリで4枚ずつです。ホーム、プロフィール、設定の3画面は両方にあり、オンボーディング画面はFigmaだけに、デバッグメニュー画面はアプリだけにあります。 ステップ2:動作環境をセットアップする 次に、Skillと画像を決まったディレクトリに置き、Skillの出力先を決めます。Skillは .claude/skills/ 、ステップ1で書き出した画像は input/ に置き、Skillが書き出すファイルはSkillごとに分けて output/ の下に置くこととします。ディレクトリ構造は、次のように定義しました。 output/ の下は、ステップ3でSkillが書き出す予定のファイルです。 <プロジェクトのルート>/ ├── .claude/skills/ │ ├── ui-diff-structure/ 構造抽出Skill │ │ ├── SKILL.md │ │ └── split_image.py 縦に長い画像を分割する │ ├── ui-diff-compare/ 差分比較Skill │ │ └── SKILL.md │ └── ui-diff-report/ レポート出力Skill │ ├── SKILL.md │ ├── annotate_structure.py 認識した要素を元画像に描く │ └── build_report.py レポートを書き出す ├── input/ │ ├── figma/ Figmaの書き出し画像 │ │ ├── home.png │ │ ├── onboarding.png │ │ ├── profile.png │ │ └── settings.png │ └── app/ アプリのスクリーンショット │ ├── debug.png │ ├── home.png │ ├── profile.png │ └── settings.png └── output/ Skillの出力先(ステップ3で書き出す予定) ├── figma/<画面名>.structure.json Figma側の構造JSON(構造抽出Skillが書き出す) ├── app/<画面名>.structure.json アプリ側の構造JSON(構造抽出Skillが書き出す) ├── compare/<画面名>.warnings.json 警告データ(差分比較Skillが書き出す) └── report/ レポートと画像(レポート出力Skillが書き出す) ├── report.html HTMLのレポート ├── overlay/figma/<画面名>.png 番号と矩形を描いた画像 └── overlay/app/<画面名>.png 番号と矩形を描いた画像 ステップ3:Figmaとアプリの差分を解析する Claude Code内で、構造抽出、差分比較、レポート出力の順にSkillを実行します。ここでは、Skillを実行するたびに output/ の下に増えていくファイルを、順に見ていきます。 構造抽出Skillを実行する まず、構造抽出Skillで、8枚の画像それぞれから構造JSONを作ります。1回の呼び出しで扱うのは画像1枚なので、画像の数だけ呼び出します。設定画面の場合は、次のとおりです。 /ui-diff-structure input/figma/settings.png output/figma/settings.structure.json /ui-diff-structure input/app/settings.png output/app/settings.structure.json … 実行すると、 output/figma/ と output/app/ に、画像と同じ名前の構造JSONができます。 output/ ├── figma/ Figma側の構造JSON │ ├── settings.structure.json │ └── … └── app/ アプリ側の構造JSON ├── settings.structure.json └── … 差分比較Skillを実行する 次に、差分比較Skillで、Figma側とアプリ側の構造JSONを画面ごとに比べます。比べるのは、両方にあるホーム、プロフィール、設定の3画面です。設定画面の場合は、次のとおりです。 /ui-diff-compare output/figma/settings.structure.json output/app/settings.structure.json output/compare/settings.warnings.json … 実行すると、 output/compare/ に、画面ごとの警告データができます。 output/ ├── figma/ 構造抽出Skillの出力 ├── app/ 構造抽出Skillの出力 └── compare/ 警告データ ├── settings.warnings.json └── … レポート出力Skillを実行する 最後に、レポート出力Skillで、全画面分の警告データを1つのレポートにまとめます。 /ui-diff-report output/figma output/app output/compare output/report 実行すると、 output/report/ に、HTMLのレポートと、番号と矩形を描いた画像ができます。 output/ ├── figma/ 構造抽出Skillの出力 ├── app/ 構造抽出Skillの出力 ├── compare/ 差分比較Skillの出力 └── report/ レポートと画像 ├── report.html HTMLのレポート └── overlay/ 番号と矩形を描いた画像 ├── figma/settings.png ├── app/settings.png └── … 結果 初回のレポートで、仕込んだ差分を検知できているかを確かめます。設定画面に仕込んだ5件の差分は、すべて「修正」の警告として検知できています。また、比較する相手がいない画面として、オンボーディングとデバッグメニューの2つが検知されました。オンボーディングはFigmaにだけある画面で、アプリでの実装ミスとして仕込んだ差分です。デバッグメニューは開発用にアプリにだけある画面で、Figmaには存在しないため、意図どおりの結果です。 画面 修正 確認 参考 設定 5 0 0 プロフィール 0 0 0 ホーム 0 0 0 仕込んだ差分と検知結果の対応は、次のとおりです。 画面 仕込んだ差分 検知結果 設定 「Push notifications」が「Push Notifications」になっている 修正 設定 「Newsletter」の行のトグルがない 修正 設定 「Units」と「Help」の表示順序が入れ替わっている 修正 設定 Figmaにない「Debug menu」の行がある 修正 設定 「Log out」が「Sign out」になっている 修正 オンボーディング Figmaにある画面が、アプリにない 比較する相手がいない画面(Figmaだけにある画面) デバッグメニュー なし(開発用にアプリにだけある画面) 比較する相手がいない画面(アプリだけにある画面) レポート画面 ステップ4:Claude Codeでアプリを修正する レポートをClaude Codeに渡し、警告と、比較する相手がいない画面をもとにアプリを修正できるか確認します。Claude Codeには、次のプロンプトで警告の修正を依頼します。 修正プロンプト @output/report/report.html の警告と、比較する相手がいない画面をもとに、アプリをFigmaのデザインに合わせて直して するとClaude Codeは、これらの警告と比較する相手がいない画面を踏まえて、次の表のとおりアプリの修正を終えました。ただし、この時点では修正の精度を確かめておらず、直した画面がどうなっているかはまだ分かりません。 対象 修正の内容 設定画面 「Push Notifications」を「Push notifications」にし、「Newsletter」をトグルの行にし、「Units」と「Help」の順序をFigmaに合わせ、「Sign out」を「Log out」にする。「Debug menu」の行は削除する オンボーディング画面 Figmaにだけある画面を、Figmaのデザインをもとにアプリに新しく作る ステップ5:再実行して改善しているかチェックする 修正後のアプリから、ステップ1と同じルールで画像を書き出して置き直し、ステップ3と同じ手順で差分を解析します。実行するコマンドは、次のとおりです。 /ui-diff-structure input/figma/settings.png output/figma/settings.structure.json /ui-diff-structure input/app/settings.png output/app/settings.structure.json … /ui-diff-compare output/figma/settings.structure.json output/app/settings.structure.json output/compare/settings.warnings.json … /ui-diff-report output/figma output/app output/compare output/report 結果 2回目のレポートで、差分が残っていないかを確かめます。4画面とも「修正」と「確認」の警告は出ていません。設定画面で出ていた「修正」の警告5件は、すべて解消されました。新しく作ったオンボーディング画面には「参考」の警告が1件出ましたが、Figmaとアプリで要素の読み取り方が違ったことによるもので、直す必要のある差分ではありません。仕込んだ差分については、AIで検知し、Claude Codeで直すと警告が解消されることを確かめられました。 画面 修正 確認 参考 設定 0 0 0 プロフィール 0 0 0 ホーム 0 0 0 オンボーディング 0 0 1 2回目のレポートに残った検知結果は、次のとおりです。 画面 検知結果 内容 オンボーディング 参考 イラストの中の円を、アプリ側だけ別の要素として読み取ったことによる違いで、直す必要のある差分ではない デバッグメニュー 比較する相手がいない画面(アプリだけにある画面) 開発用の画面でFigmaには存在しないため、修正の対象にしていない レポート画面 今後の課題 今回は、開発者の端末で差分を検知し、レポートをもとに修正するところまでを実現できました。これで、開発者が手元の環境でFigmaとアプリを照らし合わせながら、改善を進められるようになりました。一方で、今回の評価は、検証用アプリに仕込んだ差分を対象に各ステップを1回ずつ実行したものです。差分ではないものを警告する誤検知や、差分の見逃しがどれくらいの率で起きるかは測っていません。評価に使ったアプリの画像はプレビューを書き出したもので、実データ、端末のフォントレンダリング、画面サイズの違いは含まれていません。実プロダクトの画面での精度の定量評価は、今後の課題です。また、定期的に自動で実行する環境もまだありません。CI環境で動かすことを前提に、次の課題に取り組む必要があります。 画像の取得の自動化 今は、Figmaの書き出し画像もアプリのスクリーンショットも、手で所定のディレクトリに置いています。継続して実行するには、次の作業を自動化する必要があります。 比較の対象にする画面を整理する(Figmaとアプリで、枚数も1枚の画像に収める範囲もそろっていないため) アプリのスクリーンショットを書き出す(Compose Previewを Roborazzi で画像にする方法を検討中) Figmaの書き出し画像を取得する( Figma MCPサーバー や Figma REST API を使う方法を検討中) 画像の取り扱い 実プロダクトで運用するときは、画像を外部のLLMへ送ることになります。今回の検証で使ったのは、ダミーのデータだけを表示する検証用のFigmaとアプリなので、問題になりませんでした。社内の情報取り扱いルールに沿って、次のような画像の送信ルールを決めて、安全に運用できるようにする必要があります。 未公開のデザインが写った画像は送らない 個人情報が写った画像は送らない 差分比較のルールの改善 今回の差分比較では、抽出のたびに値がぶれやすい色や文字の太さ、pxの違いを対象から外し、要素の有無、表示順序、文言の違いに絞りました。見た目の細かな食い違いまで検知するには、ぶれにくい比べ方が必要です。判定そのものの安定性も含め、差分比較のルールには次のような改善の余地があります。 色や文字の太さを比べる(構造JSONに文字色、背景色、太さを持たせる方法も試したが、抽出のたびに値がぶれて誤検知が出たため、今回は比べないことにした) 文字の大きさや余白を比べる(pxの違いは警告にしていないため、文字の大きさや間隔の差分は検知できない) 判定のぶれを減らす(同じ構造JSONを比べ直したとき、Figmaにない行の警告Levelが「修正」と「参考」で分かれることがあった) 実行時間とコストの削減 AIで画像を分析・比較すると、画像1枚ごとに時間がかかり、トークンを消費します。各Skillを1回ずつ呼び出したときの目安は、下の表のとおりです。トークン量は、Claude Codeが記録した入力と出力の合計で、入力にはキャッシュの書き込みと読み込みを含みます。時間とトークン量は、解析する画像の枚数に比例して増えます。 今回の評価では、構造抽出SkillにはSonnet 5.5を、差分比較SkillにはOpus 5.5を使いました。当初は構造抽出SkillにもOpus 5.5を使っていましたが、費用が高く運用に向かないうえ、Sonnet 5.5でも十分な精度が得られたため切り替えました。 この構成で画像100枚(50画面分)の構造抽出と差分比較を1件ずつ順に実行すると、約3,100万トークン(約38ドル)と約75分かかる計算です。どちらもOpus 5.5で実行すると、約5,100万トークン(約75ドル)と約2.5時間かかります。Figmaのデザインが変わっていなければ、Figma側の構造JSONは使い回せます。2回目以降の実行では、アプリ側の画像だけを構造抽出すればよいため、構造抽出にかかる時間とトークン量を半分にできます。判定のぶれを抑えるために同じ比較を複数回実行する場合は、その回数の分だけ差分比較の時間とトークン量も増えます。実際に運用するには、運用コストを考えたうえで、最適なモデルや実行頻度を検討する必要があります。 Skill 呼び出しの単位 Sonnet 5.5の実行時間 Sonnet 5.5のトークン量(ドル換算) Opus 5.5の実行時間 Opus 5.5のトークン量(ドル換算) 構造抽出Skill 画像1枚 22〜26秒 約23万トークン(約0.18ドル) 53〜85秒 約36万〜49万トークン(約0.49〜0.60ドル) 差分比較Skill 1組 14秒 約12万トークン(約0.15ドル) 41秒 約17万トークン(約0.40ドル) レポート出力Skill 3組分を1回 7〜9秒 約11万トークン(約0.10〜0.12ドル) 8〜12秒 約11万トークン(約0.21〜0.24ドル) ※ドル換算は、 Amazon Bedrockの料金 で試算した額です。2026年10月時点の、米国東部(オハイオ)リージョンの地理的およびリージョン内クロスリージョン推論の料金を使いました。キャッシュの書き込みは、計測時のClaude Codeに合わせて、1時間保持する場合の単価で試算しています。 ※Sonnet 5.5の単価は、100万トークンあたり入力2.20ドル・出力11.00ドル・キャッシュの書き込み4.40ドル・キャッシュの読み込み0.11ドルです。 ※Opus 5.5の単価は、100万トークンあたり入力4.40ドル・出力22.00ドル・キャッシュの書き込み8.80ドル・キャッシュの読み込み0.22ドルです。 まとめ 本記事では、FigmaとアプリのUI差分を検知するために、Claude CodeのSkillで作った仕組みを紹介しました。画像から画面の構造をJSONとして抽出し、構造同士を比べることで、Figmaとアプリの差分を警告Level付きのレポートで一覧できるようになりました。 検証用のアプリに仕込んだ差分については、要素の有無、並び順、大文字と小文字のようなわずかな文言の違い、アプリにない画面を検知できました。 FigmaとアプリのUI差分の検知や、AIエージェントによる画像の比較を検討している方がいれば、ぜひ参考にしてみてください。今後は、判定の精度を確かめながら画像の取得を自動化し、Figmaを正解として運用できる体制づくりを進めていきたいと考えています。最後までお読みいただき、ありがとうございました。 ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。 corp.zozo.com
こんにちは、人材プラットフォーム本部プロダクト統括部CTO室モバイルアプリケーショングループの吉岡です。株式会社メドレーの人材プラットフォーム本部では現在、 Flutter を用いて複数のモバイルアプリを開発しています。 2026年10月29日(木)〜30日(金)、日本国内で Flutter をメインに扱う技術カンファレンス「 FlutterKaigi 2026 」が開催されました。FlutterKaigi は有志によって運営されているカンファレンスです。メドレーは今回 Bronze スポンサーとして協賛し、複数のメンバーが参加しました。技術カンファレンスへの継続的な協賛を通じて、技術コミュニティの支援を行っています。 本記事では、FlutterKaigi 2026への参加をレポートします。 会場の様子 FlutterKaigi 2026 は、浜松町コンベンションホールで開催されました。 2日間にわたる開催で、4部屋並行セッションにブースエリアという構成でした。 スポンサーブースが並ぶエリアは、2日間を通して多くの参加者で賑わっていました。 中でも印象的だったのが、ブースにトレーニング器具を置いて懸垂チャレンジを実施していた企業です。写真の右手に写っているのがその器具で、技術カンファレンスのブースとしては珍しい光景が目を引きました。私もチャレンジしてみましたが、結果は3回でした。 説明を聞くだけでなく、実際に体を動かして体験することで自然とプロダクトへの興味が湧いてくる、楽しいブースでした。 会場には参加者が自由に書き込めるメッセージボードも設置されていました。日本各地はもちろん海外から参加された方のメッセージもあり、FlutterKaigi が国内外の Flutter エンジニアをつなぐ場になっていることを実感しました。 また、公式アプリを使ったミッションや、スポンサーブースを回って集めるスタンプラリーなど、会期中ずっと楽しめる企画も用意されていました。2日目の夕方にはクイズ大会や Google の Flutter チームに質問できる Q&A が行われ、そのまま懇親会へと続きました。 メドレーメンバーの登壇 今年は、メドレーから2名がライトニングトーク(LT)に登壇しました。 CocoaPodsからSPMへ安全に移行するための対応とつまづき(成瀬) Day 1(10月29日)の Cupertino 会場で、成瀬が登壇しました。 - YouTube Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube. www.youtube.com CocoaPods は2026年12月に読み取り専用となり、Firebase や Sentry など主要な SDK も、すでに CocoaPods への新バージョン公開を止め始めています。そのため、 Swift Package Manager (SPM)への移行は、CocoaPods を使っている Flutter iOS アプリにとって避けられない課題となりました。 pubspec.yaml に数行の設定を追加すれば完了する想定でしたが、予期しない問題が発生しました。本 LT では、CocoaPods から SPM に移行したときのハマりどころの実例を挙げて、その対応策を共有しました。 登壇資料はこちらです。 FlutterKaigi2026_SPM移行LT.pdf speakerdeck.com Flutterにおけるオフラインファースト設計〜実践パターンと落とし穴〜(奥澤) Day 2(10月30日)の Material 会場で、奥澤が登壇しました。 - YouTube Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube. www.youtube.com メドレーがターゲットとしている医療現場では、電波状況に左右されず、いつでも快適にアプリを使えることが欠かせません。そこで有効なのが「オフラインファースト」での設計です。 一方で、オフラインファースト設計はデータ同期や競合解決の難易度が高く、バックエンドとのインターフェースまで含めた慎重な設計が求められます。本 LT では、オフラインファースト設計の重要性と、どのように Flutter アプリで実現したのかを紹介しました。 登壇資料はこちらです。 Flutterにおけるオフラインファースト設計 〜実践パターンと落とし⽳〜 | ドクセル FlutterKaigi 2026での発表資料です。 www.docswell.com セッションの様子 セッションは JTCC ホール、UPSIDER ホール、Material、Cupertino の4部屋で並行して行われました。どの時間帯も興味を引かれるセッションが並んでいて、どれを聞きに行くか迷うほどの充実ぶりでした。 印象に残ったセッション 弊社エンジニアが気になった・聴講して面白かったセッションをご紹介します。 AIに任せられるFlutterコードベースを作る — 仕様をコードで表し、ハーネスで守る by yohei さん - YouTube Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube. www.youtube.com 申請・経費精算の Flutter アプリを題材に、AI に実装を任せられるコードベースをどう作ってきたかを紹介したセッションでした。 特に印象に残ったのは、「決定的なもの」と「非決定的なもの」を分けるという考え方です。型や lint は何度実行しても同じ結果になるため、守らせたいルールはできる限りこちらに置き、それでも表せない業務知識だけを Skill や Subagents として AI に渡す。そして非決定的な Skill や Subagents が狙いどおりに動くかは、途中の過程を縛らずに最終的なアウトプットを複数回・機械的に評価して確かめる。「ハーネスがモデルの成長を邪魔しないように」という視点も含めて、AI と付き合うための設計の軸がはっきりしていました。 一方で、ローディング中の見せ方のような体験の設計は、人間が責任を持つべきだという話もありました。AI と人間の効果的な役割分担は私たちも向き合っているテーマです。 「それ、Flutterで作れるの?」― Fragment Shaderで魅せるUIを実現する by ゴールドナ ルーカス さん - YouTube Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube. www.youtube.com 「Shader は使い道がない」「難しそう」「Flutter のサンプルが少ない」といったイメージを覆したい、という思いから始まったセッションでした。 Flutter の内部でも、Container の色やグラデーション、ぼかし、影、Material のタップエフェクトなど、多くの場面で Fragment Shader が使われているとのことでした。 印象的だったのは、Android でリストを引っ張ったときに伸びるストレッチエフェクトの話です。以前は Transform による均一なストレッチで再現していたためネイティブとの違和感があったものが、Impeller 上では Fragment Shader を使い、引っ張った距離に応じて伸び方を変えることでネイティブに近い見た目になったそうです。Shader は 3D グラフィックスや派手な見た目を作るものという印象もありますが、普段の UI 開発にも使える可能性を感じました。 おわりに FlutterKaigi 2026 の運営の皆様、スピーカーの皆様、参加者の皆様、スポンサーの皆様、ありがとうございました。 今後もメドレーは技術コミュニティの一員としてイベントに参加し、協賛を通じた貢献も続けていきます。 またカンファレンスでお会いしましょう。 We’re hiring! メドレーでは、Flutter をはじめとしたテクノロジーを活用して、医療ヘルスケアの未来をつくるプロダクトを開発しています。エンジニア・デザイナー・PM など様々な職種で募集していますので、ご興味のある方からのカジュアル面談のお申し込みをお待ちしております。 メドレーで働く|株式会社メドレー メドレーでの働き方や人事制度、求人情報など、採用に関する情報をご紹介します。 www.medley.jp Medley Engineer Entrance Book この度は株式会社メドレーに興味をお寄せいただきありがとうございます。本資料は、メドレーへの転職をご検討いただいている皆様に、当社をより深くご理解いただくために作成いたしました。 medley-inc.notion.site
はじめに 2026年10月29日から2026年10月30日にかけて開催される FlutterKaigi 2026 に RevComm のエンジニア 横内 優作 が登壇します。 イベント概要 2026.flutterkaigi.jp 日程: 2026年10月29日 (木) 〜 2026年10月30日 (金) 会場: 浜松町コンベンションホール 主催: FlutterKaigi 実行委員会 チケット申し込みはこちらをご参照ください。 medium.com 登壇情報 FlutterでオンデバイスAI音声議事録はどこまで作れるのか 〜iOS/Androidの録音・文字起こし・要約の実装と限界〜 録音から文字起こし、要約までをすべて端末内で完結させる音声議事録アプリを、Flutterでどこまで作れるのか。 本セッションでは、実際に動くサンプルアプリの実装と実測データをもとに、その可能性と限界を検証します。対象はiOS/Androidです。 文字起こしには自社開発のAIモデルを端末上で動かし、要約にはiOSのFoundation Models、AndroidのGemini NanoといったOS標準のオンデバイスAIを利用します。 日時: 2026年10月29日 (木) 13:25 - 13:55 登壇者: 横内 優作 協賛について RevCommでは、音声解析AI「MiiTel」シリーズの開発のなかで、モバイルアプリケーションの開発に Flutter を活用しています。 音声×AIというドメインかつリアルタイム性が求められるアプリケーション開発においては、様々な技術的課題に取り組む必要があります。そうした経験などを共有することで、少しでもコミュニティーに貢献できれば幸いです。 当日はブースも出展予定のため、ぜひお立ち寄りください! おわりに ぜひ発表やブースにお越しいただけると幸いです! 当日は会場でお会いできることを楽しみにしています!

動画

書籍