# デスクトップアプリは実はWebページだ：これを理解すると、操作はもはや「デスクトップ自動化」ではなくなる

{初|はじ}めて chrome-use で Slack デスクトップ{版|ばん}につなぎ、`snapshot` で{出|で}てきた{名前付|なまえつ}きのボタンの{山|やま}を{見|み}たとき、{少|すこ}し{驚|おどろ}いた。これはWebページを{操作|そうさ}するのとまったく{変|か}わらない。あとで{納得|なっとく}した。Slack デスクトップ{版|ばん}は、そもそもWebページなのだ。

Electron アプリは、Chromium レンダリングエンジンに Node.js の{外殻|がいかく}を{足|た}したものだ。Slack、VS Code、Discord、Figma、Notion を「デスクトップソフト」として{使|つか}っているつもりでも、その{画面|がめん}はすべて Chromium がレンダリングした HTML で、{外側|そとがわ}にネイティブウィンドウの{殻|から}をかぶせているだけだ。この{事実|じじつ}を{受|う}け{入|い}れると、もともとかなり{難|むずか}しかったことが、{崩|くず}れるように{簡単|かんたん}になる。デスクトップアプリの{操作|そうさ}は、Webページの{操作|そうさ}へと{退化|たいか}する。

![Slack/VS Code などの Electron アプリの{殻|から}をめくると、{中身|なかみ}は{実|じつ}は Chromium のWebページであり、chrome-use は CDP のリモートデバッグポートを{通|つう}じて{接続|せつぞく}し、ボタンをスクリーンショット上の{座標|ざひょう}ではなく @e1/@e2 の{要素参照|ようそさんしょう}で{特定|とくてい}する](https://img.leeguoo.com/media/7f410f6e-6dff-45ec-961b-883a60d54520/electron-hero.webp)

## デスクトップ自動化はもともとどれほど扱いにくかったか

まず、この{道|みち}がなかったとき、プログラムにデスクトップアプリを{操作|そうさ}させるのがどれほど{難|むずか}しかったかを{話|はな}そう。

ひとつの{方法|ほうほう}は、スクリーンショットを{撮|と}り、ボタンのピクセル{座標|ざひょう}を{探|さが}し、そこをクリックすることだ。{解像度|かいぞうど}が{変|か}わり、テーマが{変|か}わり、ウィンドウが{動|うご}いただけで、{座標|ざひょう}はすべてずれる。しかもプログラムは{画面|がめん}に{何|なに}があるのかを「{理解|りかい}」できず、ただ1{枚|まい}の{画像|がぞう}を{見|み}ているだけだ。もうひとつの{方法|ほうほう}は、システムのアクセシビリティ API、つまり macOS の Accessibility や Windows の UIAutomation を{使|つか}うことだ。これならコントロールツリーを{取得|しゅとく}できるが、プラットフォームごとに API が{別|べつ}で、しかも Electron アプリがこの API に{公開|こうかい}する{情報|じょうほう}は、しばしば{不完全|ふかんぜん}だ。なぜなら、その「コントロール」は{実際|じっさい}にはネイティブコントロールではなく div だからだ。

どちらの{方法|ほうほう}も{手間|てま}がかかるし、どちらもひとつの{事実|じじつ}を{迂回|うかい}している。このアプリの{内部|ないぶ}には、{構造|こうぞう}がはっきりしていて{意味|いみ}もある DOM があるのに、{外側|そとがわ}からピクセル{越|ご}し、あるいは{変換|へんかん}された{層|そう}{越|ご}しに、それへ{手|て}を{伸|の}ばしているのだ。

## Chromium には最初から扉がある

レンダリングエンジンが Chromium なので、Electron アプリは{自然|しぜん}に Chrome DevTools Protocol を{話|はな}せる。{起動時|きどうじ}に `--remote-debugging-port` を{付|つ}けると、CDP ポートが{開|ひら}き、{内部|ないぶ}の DOM がそのまま{露出|ろしゅつ}する。

```bash
open -a "Slack" --args --remote-debugging-port=9222
chrome-use connect 9222
chrome-use snapshot -i
```

（アプリごとに{衝突|しょうとつ}しないポートを{割|わ}り{当|あ}てればよい。{全|ぜん}プラットフォームの{起動|きどう}コマンドはドキュメントサイトにあるので、ここでは{詳|くわ}しく{展開|てんかい}しない。）

`snapshot` が{返|かえ}すのは、その DOM のアクセシビリティ{視点|してん}だ。すべてのボタンや{入力欄|にゅうりょくらん}は{名前|なまえ}を{持|も}つ{要素|ようそ}であり、`@ref` で{特定|とくてい}できる。あなたは「{送信|そうしん}ボタンはたぶん{右下|みぎした}あたりのピクセルにある」と{推測|すいそく}しているのではない。`button "Send"` そのものを{取得|しゅとく}している。ウィンドウが{動|うご}いても、テーマが{変|か}わっても{影響|えいきょう}しない。{結|むす}びついているのは{座標|ざひょう}ではなく{要素|ようそ}だからだ。agent にとって、この{違|ちが}いは{本質的|ほんしつてき}だ。いまや agent は、このデスクトップアプリがどんな{姿|すがた}をしているかを{読|よ}み{取|と}れる。スクリーンショットを{相手|あいて}に{当|あ}てずっぽうでクリックしているのではない。

## 必ず知っておくべきトレードオフ

ここには、ブラウザの{場面|ばめん}とは{違|ちが}う{点|てん}がある。{思|おも}い{込|こ}みやすいので、{別|べつ}に{話|はな}しておく{価値|かち}がある。

{普段|ふだん}{使|つか}っている Chrome を{操作|そうさ}するとき、chrome-use はブラウザ{拡張|かくちょう}と native messaging を{使|つか}う。デバッグポートには{触|ふ}れないので、「リモートデバッグを{許可|きょか}するか」という{確認|かくにん}ダイアログもなく、`Runtime.enable` のようなプロトコル{層|そう}の{痕跡|こんせき}もない。しかし Electron アプリには Chrome ウェブストアの{拡張|かくちょう}を{入|い}れられない。だから、この{道|みち}では `--remote-debugging-port` を{使|つか}うしかない。つまり、ブラウザの{場面|ばめん}にあった「{痕跡|こんせき}ゼロ」のような{利点|りてん}は、Electron では{得|え}られない。{前提|ぜんてい}は、{自分|じぶん}でデバッグポートを{開|ひら}いて、そこへ{接続|せつぞく}することだ。

Slack や VS Code のような「{自分|じぶん}のアプリ」を{自動化|じどうか}するなら、これはまったく{問題|もんだい}ではない。{誰|だれ}かをだまそうとしているのではなく、すでにログインしている{自分|じぶん}のツールを{自動化|じどうか}したいだけだからだ。ただし、ブラウザでの「{検出|けんしゅつ}されない」という{期待|きたい}を{持|も}ったまま Electron を{操作|そうさ}しに{来|く}るなら、まず{期待値|きたいち}を{調整|ちょうせい}する{必要|ひつよう}がある。これは「{自分|じぶん}のアプリへ{接続|せつぞく}する」ことであって、「{他人|たにん}のサイトを{隠|かく}れて{操作|そうさ}する」ことではない。

## おもしろい細部：アプリの中にさらにアプリを入れられる

Electron アプリの{内部|ないぶ}には、しばしば `<webview>` がさらに{埋|う}め{込|こ}まれている。たとえば Slack で{開|ひら}いた{第三者|だいさんしゃ}アプリのパネルは、{本質的|ほんしつてき}にはもうひとつの{独立|どくりつ}したWebページだ。これらは CDP では{独立|どくりつ}した target になる。{接続後|せつぞくご}にまず `chrome-use tab` で{一覧|いちらん}を{出|だ}すと、メインウィンドウ、{設定|せってい}ウィンドウ、そしてそれらの webview が、それぞれ target になっているのが{見|み}える。{個別|こべつ}に{切|き}り{替|か}えて{操作|そうさ}できる。

だから、ひとつの Electron アプリは「ひとつのWebページ」ではない。「ネイティブの{殻|から}の{中|なか}に{重|かさ}なったWebページの{束|たば}」だ。これを{理解|りかい}すると、マルチウィンドウや{入|い}れ{子|こ}パネルのような、もともと{頭|あたま}を{悩|なや}ませる{場面|ばめん}は、すべて「{正|ただ}しい target に{切|き}り{替|か}える」だけになる。

## 境界

この{方法|ほうほう}は、Chromium {内核|ないかく}のアプリにだけ{成|な}り{立|た}つ。Swift/AppKit で{書|か}かれた{純粋|じゅんすい}なネイティブアプリには CDP ポートがなく、{接続|せつぞく}できない。その{場合|ばあい}は、システムのアクセシビリティに{戻|もど}るか、{別|べつ}のツールを{使|つか}う{必要|ひつよう}がある。iPhone 上のネイティブ app を{操作|そうさ}するとき、私は{別|べつ}の{仕組|しく}みを{使|つか}っている。{判断|はんだん}は{簡単|かんたん}だ。Slack、VS Code、Discord、Figma、Notion、Spotify のような「ひとつのコードでマルチプラットフォームに{対応|たいおう}する」デスクトップアプリは、{基本的|きほんてき}に Electron だ。

「デスクトップアプリは{実|じつ}はWebページだ」と{理解|りかい}してから、私はデスクトップツールを{見|み}ると、まずそれが Electron かどうかを{確認|かくにん}するようになった。Electron なら、それを{操作|そうさ}することは、もはや私がずっと{泥臭|どろくさ}いと{感|かん}じていた「デスクトップ自動化」ではない。すでによく{知|し}っている、Webページを{開|ひら}いて{扱|あつか}うためのあの{方法|ほうほう}になる。

関連ドキュメント（英語）：[chrome-use · Electron Apps](https://chrome-use.leeguoo.com/en/electron.html)、[インストール](https://chrome-use.leeguoo.com/en/install.html)。
