検索

ガイド

Python で adb を使い Android エミュレータを操作する

Macro Automation Studio 向けの Python adb チュートリアル: BlueStacks でタップ、スワイプ、文字入力、キー操作、スクリーンショットを、adb の管理はアプリに任せて行います。

  • Windows
  • Mac
  • エミュレータ
  • クラウド端末
  • スマホ
  • Python SDK
中級 更新日 約10分で読めます
このページの内容
  1. 始める前に
  2. 各部品の組み合わさり方
  3. プロジェクトを作る
  4. 画面サイズと座標
  5. Python で adb のスクリーンショットを撮る
  6. タップ
  7. スワイプ
  8. 文字入力
  9. キーを押す
  10. アプリを開いて確認する
  11. 完全なスクリプト
  12. この Python チュートリアルで adb が担う部分
  13. うまくいかないとき
  14. Could not discover RPC port
  15. タップが違う場所に落ちる
  16. input_text が何も入力しない
  17. デバイスが見つからない、または offline

多くの 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_PORTMAS_RPC_HOSTMAS_DEVICE_IDMAS_SESSION_TOKEN) で渡します。すべての mas.* 呼び出しは、アプリへの JSON-RPC 2.0 リクエストになります。アプリが adb コマンド、テンプレート検索、OCR を実行し、結果を返します。デバイスは最初の行が動く前に結び付けられているので、connect() の呼び出しも、管理するシリアルもありません。基本概念 を参照してください。

プロジェクトを作る

  1. マクロ を開き、新しいプロジェクトを作成 をクリックします。
  2. コードベース を選び、対象デバイス をモバイルにし、プロジェクト名を付けて プロジェクトを作成 をクリックします。
  3. プロジェクトを開きます。Code Editor に src/app.py が表示されます。
  4. デバイスセレクターでエミュレータを選び、スニペットを試したいときはいつでも 実行 (F5) をクリックします。停止Shift+F5 です。

画面サイズと座標

SDK に渡すすべての座標は、デバイス画面の左上からの、デバイス自身の解像度でのピクセルオフセットです。モニター上のエミュレータウィンドウの大きさは関係ありません。

python
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()widthheight を持つ ScreenSize を返します。get_device_info() はそれに加えてデバイスの nametypeconnected フラグを返します。スクリプトが解像度の変更に耐える必要があるときは、最後の例のように位置をサイズの割合で計算します。テンプレート画像と OCR 領域は耐えられません。画像認識ガイド を参照してください。

Python で adb のスクリーンショットを撮る

python
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 を保持し、widthheight はそのピクセルサイズ、timestamp は ISO 8601 の文字列です。上のファイルは、作業ディレクトリであるプロジェクトフォルダーに保存されます。同じオブジェクトを screenshot=shot で複数の find_object 呼び出しに渡すと、すべてが再取得せずに 1 つのフレームを検索します。

タップ

python
mas.click(270, 800)                 # tap, then wait 1000 ms
mas.click(270, 800, delay_ms=300)   # shorter pause for tight loops

click(x, y, delay_ms=1000) は 1 度タップし、アプリが反応できるよう delay_ms の後に待ちます。タップに押し続ける時間はありません。長押しには duration_ms を付けた key_press を使います。

スワイプ

python
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 deliberate

swipe(from_coords, to_coords, duration_ms=1000) は 2 つの (x, y) タプルを受け取ります。短い時間はフリック、長い時間はドラッグになります。ピンチ操作は別の呼び出しです: zoom_in()zoom_out() は既定で画面中央に percent=50 で行います。

文字入力

python
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 there

input_text(text, delay_ms=0, clear=False) はフォーカスされた欄に入力するので、先に欄をタップしてください。clear=True はカーソルを末尾に移動し、入力前に既存の文字を削除します。

キーを押す

python
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 press

key_press(key_code, modifiers=None, duration_ms=100, repeat=1) は Android のキーイベントを送ります。duration_ms が 500 以上なら長押しになります。それを超える正確なミリ秒数は反映されません。repeat は 1 から 100 で、Python のループよりずっと速く動きます。KeyCode には D パッド、音量、メディア、数字のキーもあります。

アプリを開いて確認する

python
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_stateNOT_INSTALLEDNOT_RUNNINGRUNNING_IN_BACKGROUND_SUSPENDEDRUNNING_IN_BACKGROUNDRUNNING_IN_FOREGROUND のいずれかを返します。close_app はパッケージを強制停止します。

完全なスクリプト

このスクリプトは Android の設定を開き、語句を検索し、結果をスクロールし、スクリーンショットを保存し、その語句が画面にあることを OCR で確認します。検索ボックスは Asset Lab で切り出すテンプレートです。ID を自分のものに置き換えてください。スワイプは画面サイズの割合を使うので、どの解像度でも動きます。

python
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> を実行し、そのセッションを実行の間保ちます。
  • 入力。 clickadb shell input tap に、swipeadb shell input touchscreen swipe に、input_textadb shell input text に、key_pressadb shell input keyevent になります。ピンチ操作はエミュレータのタッチ入力デバイスに直接書き込まれます。
  • 画面。 take_screenshot とすべての find_object は、Windows で PNG を壊さないバイナリセーフな形式の adb exec-out screencap -p で取得します。get_screen_sizewm size を読み、get_current_app はウィンドウマネージャーを読みます。
  • アプリ。 open_appmonkey でランチャーインテントを発行し、am start にフォールバックします。close_appam 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で質問する