uiautomator2 MCPでAndroid全画面を自動スクリーンショット

uiautomator2 MCPでAndroid全画面を自動スクリーンショット

はじめに

Androidアプリを個人で複数管理していると、こんな作業が定期的に発生します。

  • Play Store用スクリーンショットの撮り直し
  • UIリグレッション確認
  • ダークモード対応確認
  • 多言語崩れチェック

これらをすべて手動でやると、アプリごとに何十枚もスクリーンショットを取ることになります。

uiautomator2 MCPを使えば、Claude CodeやCursorからAndroidデバイスを操作して全画面を自動で巡回・撮影できます。


基本方針:UI tree + DeepLink

画面を自動巡回する方法は2種類あります。

方法 安定性 実装コスト
座標タップで巡回 低(崩れやすい)
UI tree解析で巡回
DeepLinkで直接遷移 高(安定) 中〜高

画像認識だけでは不安定な理由:

  • LazyColumnのスクロール位置がずれる
  • アニメーション中にタップミスが起きる
  • Foldable・タブレットで座標が変わる
  • WebViewの内部は認識できない

最近のAndroid操作系エージェントも「まずUI treeを読む → 足りない時だけ画像解析」という構成が主流です。


uiautomator2系MCPの特徴

単純なADBラッパーと違い、uiautomator2系MCPはUI treeを読めることが最大の強みです。

<TextView text="Settings" resource-id="btn_settings" clickable="true"/>
<Button text="Save" resource-id="btn_save"/>

これによりAIが:

  • 「Settingsを押す」
  • 「Saveを探す」
  • 「RecyclerViewの子要素を列挙する」

といった操作を自然言語で指示できます。

tanbro/uiautomator2-mcp-server が有力な理由

現状のAndroid操作系MCPで完成度が高い選択肢の一つです。

機能 対応
screenshot
UI hierarchy取得
XPath検索
アプリ起動
DeepLink起動
back key
swipe
tool filtering(必要なツールのみ公開)

tool filteringは地味に重要で、MCPはツールが多すぎるとLLMが混乱しやすいため、必要なツールだけ絞れる設計は実運用向きです。


自動撮影の実装パターン

理想の構成

アプリ側: Screen Registry + DeepLink
  ↓
uiautomator2 MCP: start/capture/back
  ↓
出力: screens/SettingsScreen.png 等

コードで表すとこうです:

for screen in registry:
    open_deeplink(screen.url)   # adb shell am start...
    wait_idle()                  # UI安定まで待機
    screenshot(screen.name)      # 撮影して保存

撮影ファイルの命名

screens/
├── SettingsScreen.png
├── SettingsScreen_dark.png
├── SettingsScreen_ja.png
├── ProfileScreen.png
└── PurchaseDialog.png

画面名・テーマ・ロケールを組み合わせた命名にすると、比較しやすくなります。


アプリ側に Screen Registry を作ることが最重要

MCPだけに頼るとスクロール・アニメーション・LazyColumnで壊れやすいです。

アプリ側に「撮影専用の導線」を作るのが本質的に重要です。

Screen Registry の例(Kotlin)

object DebugScreens {
    val all = listOf(
        ScreenEntry("settings",  "myapp://debug/settings"),
        ScreenEntry("profile",   "myapp://debug/profile"),
        ScreenEntry("billing",   "myapp://debug/billing"),
    )
}

data class ScreenEntry(val name: String, val deepLink: String)

このRegistryを:

  • Debug Menuの表示に使う
  • DeepLinkの定義に使う
  • スクリーンショット自動化に使う

3つの用途で共通利用することで保守性が高くなります。


DeepLink方式が安定する理由

adb shell am start \
  -a android.intent.action.VIEW \
  -d "myapp://debug/settings"

DeepLinkで直接遷移することで:

  • スクロール位置に依存しない
  • タップ座標がズレない
  • Foldable・タブレットでも同じように動く
  • アニメーション待ちが最小限で済む

MCPは capture / wait / 状態確認 の役割に絞れます。


Compose testTagの活用

DeepLinkが難しい画面では、testTagを付けてuiautomator2に見つけさせる方法も使えます。

// 撮影対象にtestTagを付ける
LazyColumn(
    modifier = Modifier.testTag("debug_screen_list")
) {
    items(DebugScreens.all) { screen ->
        Text(
            text = screen.name,
            modifier = Modifier.testTag("debug_item_${screen.name}")
        )
    }
}

uiautomator2系MCPはresource-id / accessibility / testTagを読めるものが多く、testTagを統一しておくと操作の安定度が大幅に上がります。


注意点

uiautomator2の弱い場面

以下ではUI tree取得が不安定になることがあります。

状況 問題
LazyColumn 仮想化で非表示ノードが見えない
WebView 内部ツリーにアクセスできない
Canvas描画UI アクセシビリティツリーがない
アニメーション中 状態が不安定
RecyclerView仮想化 画面外の要素は取得できない

対策:画面が安定したことを確認してから操作する(wait_idle()activity_wait_appear)。

セキュリティ上の注意

uiautomator2 MCPはadb shellやファイルアクセスまでできるものがあります。

  • ローカル限定で使う(外部ネットワークに公開しない)
  • Emulatorを使う
  • Work Profileで分離する

発展:ここまでいくと何ができるか

Screen Registry + DeepLink + uiautomator2 MCPの構成が整うと:

用途 実現可能か
全画面自動キャプチャ
ダークモード比較
多言語崩れ検知
タブレット確認
Play Store素材生成
ClaudeによるUIレビュー
UIリグレッション差分検知

まとめ

ポイント 内容
MCPだけで探索は不安定 DeepLink方式との組み合わせが安定
アプリ側の準備が鍵 Screen Registry + DeepLink が最重要
UI tree取得が強み 座標タップより「要素を指定」が安定
testTagを統一する Compose操作の精度が大幅に上がる
MCPは撮影レイヤーに絞る capture / wait / state確認 だけが役割

「MCPで頑張って画面探索する」より「アプリ側にScreen Registry + DeepLinkを作る」ことが圧倒的に重要です。MCPはその操作レイヤーとして使うのがベストです。