ガイド
Python で adb を使い Android エミュレータを操作する
Macro Automation Studio 向けの Python adb チュートリアル: BlueStacks でタップ、スワイプ、文字入力、キー操作、スクリーンショットを、adb の管理はアプリに任せて行います。
- Windows
- Mac
- エミュレータ
- クラウド端末
- スマホ
- Python SDK
このページの内容
多くの Python adb チュートリアルは、adb shell input tap を包む subprocess のラッパーで終わります。Macro Automation Studio (MAS) 向けのこの Python adb チュートリアルは別の道を取ります: adb はアプリが持ち、スクリプトは mas パッケージを通してアプリと話します。このガイドでは、新しいプロジェクトから、アプリを開き、語句を検索し、スクロールしてスクリーンショットを保存するスクリプトまでを進みます。adb コマンドを書かずに BlueStacks、LDPlayer、MuMu Player、MEmu を操作したい Python 開発者向けです。
始める前に
- MAS がインストール済みで、トライアルかプランでサインインしていること。MAS のインストール を参照してください。
- エミュレータが ADB を有効にして動いており、デバイスグループ にデバイスとして追加されていること。デバイス を参照してください。
- 基本的な Python を知っていること。他に自分でインストールするものはありません。MAS は
mas入りの独自の Python 3.13 環境を同梱しています。
各部品の組み合わさり方
MAS はプロジェクトフォルダーを作業ディレクトリとして、スクリプトを python -u -m src.app として起動します。接続情報は環境変数 (MAS_RPC_PORT、MAS_RPC_HOST、MAS_DEVICE_ID、MAS_SESSION_TOKEN) で渡します。すべての mas.* 呼び出しは、アプリへの JSON-RPC 2.0 リクエストになります。アプリが adb コマンド、テンプレート検索、OCR を実行し、結果を返します。デバイスは最初の行が動く前に結び付けられているので、connect() の呼び出しも、管理するシリアルもありません。基本概念 を参照してください。
プロジェクトを作る
- マクロ を開き、新しいプロジェクトを作成 をクリックします。
- コードベース を選び、対象デバイス をモバイルにし、プロジェクト名を付けて プロジェクトを作成 をクリックします。
- プロジェクトを開きます。Code Editor に
src/app.pyが表示されます。 - デバイスセレクターでエミュレータを選び、スニペットを試したいときはいつでも 実行 (F5) をクリックします。停止 は Shift+F5 です。
画面サイズと座標
SDK に渡すすべての座標は、デバイス画面の左上からの、デバイス自身の解像度でのピクセルオフセットです。モニター上のエミュレータウィンドウの大きさは関係ありません。
import mas
size = mas.get_screen_size()
print(f"Screen: {size.width}x{size.height}")
center = (size.width // 2, size.height // 2)
mas.click(*center)get_screen_size() は width と height を持つ ScreenSize を返します。get_device_info() はそれに加えてデバイスの name、type、connected フラグを返します。スクリプトが解像度の変更に耐える必要があるときは、最後の例のように位置をサイズの割合で計算します。テンプレート画像と OCR 領域は耐えられません。画像認識ガイド を参照してください。
Python で adb のスクリーンショットを撮る
import base64
import mas
shot = mas.take_screenshot()
print(shot.width, shot.height, shot.timestamp)
with open("screen.png", "wb") as f:
f.write(base64.b64decode(shot.base64))take_screenshot() は Screenshot を返します: base64 は PNG を保持し、width と height はそのピクセルサイズ、timestamp は ISO 8601 の文字列です。上のファイルは、作業ディレクトリであるプロジェクトフォルダーに保存されます。同じオブジェクトを screenshot=shot で複数の find_object 呼び出しに渡すと、すべてが再取得せずに 1 つのフレームを検索します。
タップ
mas.click(270, 800) # tap, then wait 1000 ms
mas.click(270, 800, delay_ms=300) # shorter pause for tight loopsclick(x, y, delay_ms=1000) は 1 度タップし、アプリが反応できるよう delay_ms の後に待ちます。タップに押し続ける時間はありません。長押しには duration_ms を付けた key_press を使います。
スワイプ
mas.swipe((270, 750), (270, 300), duration_ms=400) # scroll a list down: drag from lower to upper
mas.swipe((100, 500), (400, 500), duration_ms=1000) # drag and drop: slow and deliberateswipe(from_coords, to_coords, duration_ms=1000) は 2 つの (x, y) タプルを受け取ります。短い時間はフリック、長い時間はドラッグになります。ピンチ操作は別の呼び出しです: zoom_in() と zoom_out() は既定で画面中央に percent=50 で行います。
文字入力
mas.click(270, 120, delay_ms=500) # focus the field first
mas.input_text("hello world")
mas.input_text("new value", clear=True) # replace what is thereinput_text(text, delay_ms=0, clear=False) はフォーカスされた欄に入力するので、先に欄をタップしてください。clear=True はカーソルを末尾に移動し、入力前に既存の文字を削除します。
キーを押す
from mas import KeyCode
mas.key_press(KeyCode.BACK)
mas.key_press(KeyCode.HOME)
mas.key_press(KeyCode.ENTER)
mas.key_press(KeyCode.DELETE, repeat=10) # ten presses in one command
mas.key_press(KeyCode.POWER, duration_ms=3000) # long presskey_press(key_code, modifiers=None, duration_ms=100, repeat=1) は Android のキーイベントを送ります。duration_ms が 500 以上なら長押しになります。それを超える正確なミリ秒数は反映されません。repeat は 1 から 100 で、Python のループよりずっと速く動きます。KeyCode には D パッド、音量、メディア、数字のキーもあります。
アプリを開いて確認する
mas.open_app("com.android.settings", timeout_ms=5000)
print(mas.get_current_app()) # package name in front
print(mas.is_app_focused("com.android.settings")) # True or False
if mas.get_app_state("com.android.chrome") == mas.NOT_RUNNING:
mas.open_app("com.android.chrome")
mas.close_app("com.android.settings")open_app(package_name, timeout_ms=2000) はパッケージ名で起動し、timeout_ms 待ちます。パッケージ名を知るには、手でアプリを開いて mas.get_current_app() を出力します。get_app_state は NOT_INSTALLED、NOT_RUNNING、RUNNING_IN_BACKGROUND_SUSPENDED、RUNNING_IN_BACKGROUND、RUNNING_IN_FOREGROUND のいずれかを返します。close_app はパッケージを強制停止します。
完全なスクリプト
このスクリプトは Android の設定を開き、語句を検索し、結果をスクロールし、スクリーンショットを保存し、その語句が画面にあることを OCR で確認します。検索ボックスは Asset Lab で切り出すテンプレートです。ID を自分のものに置き換えてください。スワイプは画面サイズの割合を使うので、どの解像度でも動きます。
import base64
import sys
import time
import mas
from mas import KeyCode
PACKAGE = "com.android.settings"
TERM = "Display"
images = mas.images({"search_box": 301})
def main():
size = mas.get_screen_size()
mas.log(f"Screen {size.width}x{size.height}")
mas.open_app(PACKAGE, timeout_ms=5000)
if not mas.is_app_focused(PACKAGE):
mas.log(f"{PACKAGE} did not come to the front", level="error")
sys.exit(2)
box = mas.find_object_retry(images.search_box, total_tries=3, time_sleep=2.0)
if box is None:
mas.log("Search box not found; crop it in Asset Lab", level="error")
sys.exit(2)
mas.click(box.x, box.y, delay_ms=800)
mas.input_text(TERM, clear=True)
mas.key_press(KeyCode.ENTER)
time.sleep(2)
x = size.width // 2
mas.swipe((x, int(size.height * 0.75)), (x, int(size.height * 0.35)), duration_ms=600)
time.sleep(1)
shot = mas.take_screenshot()
with open("search_results.png", "wb") as f:
f.write(base64.b64decode(shot.base64))
mas.log(f"Saved search_results.png ({shot.width}x{shot.height})")
text = mas.read_text(screenshot=shot, psm=11)
mas.log(f"Term on screen: {TERM.lower() in text.text.lower()}")
mas.key_press(KeyCode.HOME)
if __name__ == "__main__":
main()psm=11 を付けた read_text はフレーム全体のまばらな文字を読むので、結果一覧に向いています。1 つのカウンターを読むための領域とモードは OCR ガイド で説明しています。書くより説明したい場合は、MAS Agent がこの種のスクリプトを代わりに書きます。
この Python チュートリアルで adb が担う部分
adb を呼ぶことはありませんが、その下で仕事をしているのは adb です。
- バイナリ。 インストーラーが adb を同梱します。Windows では
C:\ProgramData\MacroAutomationStudio\3rdpartyにあり、内蔵のコピーが予備です。Mac ではアプリバンドル内にあり、Homebrew の adb が予備です。PATH には何も入りません。詳細は インストール ページにあります。 - 接続。 エミュレータはローカルの TCP ポートで adb を公開します。開始 か 実行 をクリックすると、MAS はデバイスカードのポートに対して
adb connect 127.0.0.1:<port>を実行し、そのセッションを実行の間保ちます。 - 入力。
clickはadb shell input tapに、swipeはadb shell input touchscreen swipeに、input_textはadb shell input textに、key_pressはadb shell input keyeventになります。ピンチ操作はエミュレータのタッチ入力デバイスに直接書き込まれます。 - 画面。
take_screenshotとすべてのfind_objectは、Windows で PNG を壊さないバイナリセーフな形式のadb exec-out screencap -pで取得します。get_screen_sizeはwm sizeを読み、get_current_appはウィンドウマネージャーを読みます。 - アプリ。
open_appはmonkeyでランチャーインテントを発行し、am startにフォールバックします。close_appはam force-stopを実行します。 - サーバー。 MAS は独自の adb サーバーを動かします。PATH 上の 2 つ目の adb ビルドが独自のサーバーを起動すると、両者が互いを置き換え、デバイスは Connecting に落ちます。ADB トラブルシューティング ページに、ポートごとの対処があります。
アプリがこれらすべてを行うので、BlueStacks で書いたスクリプトは、LDPlayer でも、クラウドデバイスでも、ローカルポート経由のお手持ちのスマホでも、そのまま動きます。
うまくいかないとき
Could not discover RPC port
スクリプトが MAS からではなくターミナルから起動されたため、環境変数がありません。Code Editor の 実行 か、デバイスカードから実行してください。
タップが違う場所に落ちる
デバイスのピクセルではなくウィンドウのピクセルを使っているか、エミュレータの解像度が変わりました。mas.get_screen_size() を出力し、渡している座標と比べてください。Asset Lab の座標はすでにデバイスのピクセルです。
input_text が何も入力しない
どの欄にもフォーカスがありませんでした。click で欄をタップし、入力前に delay_ms=500 を与えます。一部のアプリは欄を覆うキーボードを開きます。入力後に key_press(KeyCode.BACK) で閉じます。
デバイスが見つからない、または offline
エミュレータで ADB がオフ、デバイスカードのポートが間違っている、または別の adb サーバーが乗っ取りました。ADB トラブルシューティング に従ってください。
操作するアプリがゲームの場合は、他の自動化されたアカウントと同じ注意を払ってください。100%リスクのない自動化ツールは存在しないため、自動化は責任を持って、ご自身の判断で行ってください。
次のステップ
関連ページ
ありがとうございます。誤りがあればDiscordでお知らせください。
質問がありますか? Discordで質問する