Android実機の画面をPCに映して通信を覗こうとして詰まった記録

開発misc-dev

「PCの画面でAndroidアプリを見たい」と言い出したのが発端だった。

正確には、ある予約アプリの空き状況を、毎回スマホでアプリを開かなくても機械的に拾えるようにしたかった。最初は「Linuxでシミュレーターでも作れば見えるだろう」くらいのぼんやりした思いつきで、そもそも「エミュレーター」なのか「シミュレーター」なのかという用語すら怪しかった。

相談してみると、方式は3つあると返ってきた。Linuxデスクトップなら Waydroid、自動化を重視するなら公式エミュレータ(AVD)に adb、アプリ側の対策が厳しければ実機に scrcpy。ただし本命はそこではないと言われた。空き状況を機械的に取りたいだけなら、エミュレータを常時回すのは遠回りで、一度だけアプリの通信を覗いてAPIを特定し、あとは curl でポーリングすればいい、と。

その前に一度、寄り道もした。クラウド上で動く常駐AIエージェントに、そのままAndroidを動かしてもらえないかと考えたのだ。エージェントは専用の仮想マシンを持っているのだから、そこにアプリを入れれば済むのでは、と。調べてもらうと、たしかにブラウザもファイルシステムも持つ本物のLinux環境ではあった。ただ、Androidのエミュレータを動かすのに要る仮想化までは望み薄だと分かって、この案は畳んだ。頭として使うのはいいが、アプリを動かす機械にはできない、という線引きだった。

その代わり、使っていない手元のAndroid端末が一台あることを思い出す。それならエミュレータそのものが要らない。実機を1本ケーブルでつなげば済む。

画面を映すところまでは、拍子抜けするほどすぐ通った。詰まったのは、その先の「通信を覗く」段だった。

「ビルド番号を7回タップ」から始まった

端末をPCにつなぐには、まず開発者向けオプションを出す必要がある。ここで最初につまずいた。

「ビルド番号を7回タップしてください」という指示の意味が、まったく分からなかった。しかも自分は「9回」だと思い込んでいて、そこから食い違っていた。ビルド番号を叩くとなぜ設定画面が出てくるのか、直感に反する。

聞いてみると、ビルド番号はAndroidのOSのバージョンを表す文字列で、そこを7回連続でタップすると隠れていた開発者向けオプションが姿を現す、という仕掛けらしい。普通の人が誤って触らないよう、わざと奥に隠してあるだけだと教えてもらって、ようやく腑に落ちた。意味不明に見えたものが、「隠しコマンド」だと分かればただの手順になる。

開発者向けオプションを出し、その中の USBデバッグをオンにした。これで見えるはずだった。

つないでも、最初は見えなかった

USBデバッグをオンにして端末をつないだのに、PC側からは端末が一台も見えなかった。adb で端末一覧を出すコマンドの結果が空のまま返ってくる。

$ adb devices
List of devices attached
(空)

USBデバッグをオンにしただけでは足りず、ケーブルの挿し方と、端末側で出る許可のやりとりが要るのだと言われた。ケーブルを挿し直したら、端末に「このPCからのUSBデバッグを許可しますか」というダイアログが出た。それを許可したところで、ようやくPCが端末を認識した。

映す道具の scrcpy と adb は、PCのフォルダに単体の実行ファイルとして展開してもらっていた。レジストリもPATHも環境変数も触らず、使い終わったらフォルダごと消せば跡が残らない形にしてある。あとで片付けやすいのはありがたい。

画面は映った。ただし一部は真っ黒

scrcpy を起動すると、PCのウィンドウに端末の画面がそのまま映り、マウスでも操作できた。手元のスマホを触らずに、PCの画面の中でアプリを開いてタップできる。ここは素直に感心した。

ところが、対象のアプリでログイン後の画面に進むと、そこだけ真っ黒になった。

これはこちらの操作ミスではなく、アプリが画面キャプチャを禁止しているためだと分かった。予約や決済を扱うアプリは、スクリーンショット防止のためにこの制限をかけていることがある。トップ画面は映るのに特定の画面だけ黒くなるのは、まさにその症状だった。もっとも、画面を見るのはあくまで補助で、本命は通信の中身を読むことにある。画面が黒くても通信はキャプチャできるので、ここは気にしないことにした。

通信を覗く段で、ネットワークに引っかかる

本題はここからだった。アプリとサーバーの間で何がやりとりされているかを読めれば、空き状況のAPIが特定できる。

まず、吸い出したアプリを解析してもらったところ、通信先のサーバーのドメインが判明した。ここまでは順調だった。だが、そのまま覗こうとしても、通信は暗号化されていて中身が読めない作りになっていた。自分の端末での検証なので、証明書まわりを緩めたアプリと、PC側で通信を中継して覗くための道具(mitmproxy)を用意してもらい、いよいよ実際に流れを見にいく段に入った。

そこで、端末側の設定に詰まった。

やることは2つだけのはずだった。1つは、端末のWi-Fiのプロキシを手動に切り替えて、中継役のPCを指すように設定すること。もう1つは、通信を復号するためのCA証明書を端末にインストールすること。どちらも端末を数回タップすれば終わる、という段取りだった。

ところが、Wi-Fiのプロキシを設定しようとして「ネットワークを変更」という項目が見つからない。さらに厄介だったのがCA証明書で、端末の設定の検索窓に「CA証明書」と打ち込んでも、候補が一つも出てこなかった。インストールの入り口そのものが見当たらない。メーカーによってAndroidの設定画面の構成は違うので、手順書どおりの場所に同じ項目があるとは限らない。ここで足が止まった。

端末を触る係と、コマンドを用意する係

途中で、役割を分けることにした。

CA証明書のインストールには端末のロックPINが要る。これは本人が入力しないと進まない操作で、PC側から代わりに叩くことはできない。そこで、自分が端末を直接タップする係、PC側のコマンドは用意してもらってこちらは実行するだけ、という分担に落ち着いた。成否は中継役のPC側で通信を見れば分かるので、うまくいったかどうかもそちらで確認してもらう。

当初はPCに映した画面をスクショで送り、それを見ながら誘導してもらう形も試した。だが、スクショを何枚も送るとセッションが重くなってきた。そこで、画面越しに逐一やりとりするより、手順を文章でまとめて渡してもらい、自分の手で入れていく形に切り替えた。

端末の設定変更をPC側から流し込む案も一度は試したが、手元の端末はメーカーの制約で adb 経由の設定変更を拒否した。結局、端末の設定は自分の手で触るのが確実だった。「PCから全部やる」より「人間が端末を操作し、機械はPC側を固める」の分担のほうが、この局面では速い。

振り返り

画面を映すところまでは、思っていたより簡単に着いた。開発者向けオプションの隠し方さえ分かれば、あとはケーブルと許可ダイアログだけで実機はPCに乗る。

止まったのは、そのもう一段先だった。通信を覗くにはネットワーク側の下ごしらえが要り、そこはメーカーごとの設定画面の差に素直に足を取られる。手順書の一行が、自分の端末では同じ場所に存在しない。この日はCA証明書の入り口を見つけられないまま、通信の中身を読むところまでは到達しなかった。

「詰まった記録」として残しておく価値があるとすれば、ここだと思う。ミラーリングは前座で、本番はネットワーク設定にあった。次に触るときは、証明書のインストール経路をメーカー別に先に押さえてから端末に向かう。作業の記録自体は非公開のメモとして手元に残したので、続きはそこから拾い直せばいい。

#Android#scrcpy#adb#mitmproxy#開発日記