はじめに
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はその操作レイヤーとして使うのがベストです。