前回の記事では、PythonとADBを組み合わせるメリットと、自動化を始めるための環境構築方法について解説しました。環境の準備が整った今、いよいよ本記事では具体的なADBコマンドをPythonスクリプトで自動化する方法に焦点を当てていきます。
ここでは、開発やテストで頻繁に利用されるADBコマンドを厳選し、adb-shell
ライブラリを使った実践的なコード例を豊富に提供します。
- アプリのインストール・アンインストール
- ファイルのプッシュ・プル
- スクリーンショットの取得やシェルコマンドの実行
など実際の現場で役立つ自動化レシピを通じて、PythonによるAndroid操作の可能性を実感してください。
基本的な接続と操作の準備
adb-shell
ライブラリを使ってAndroidデバイスに接続し、基本的な操作を行うための準備を行います。前提として、adb server
がPCで起動している必要があります。
Python
from adb_shell.adb_device import AdbDevice
from adb_shell.auth.sign_pure_python import AdbKey # 認証が必要な場合
import time
import subprocess # adbコマンドを直接実行するために使用
# adb serverが起動していることを確認・起動
# コマンドプロンプト/ターミナルで `adb start-server` を手動で実行しておくことを推奨します。
# またはPythonから subprocess を使って起動することも可能です。
# subprocess.run("adb start-server", shell=True)
# デバイスへの接続設定
# 通常は localhost:5037 で adb server に接続します。
# デバイスがPCに接続され、USBデバッグが有効になっている必要があります。
# 認証が必要な場合(通常は初回接続時):
# key_path = '/path/to/your/.android/adbkey' # 環境に合わせてパスを修正
# with open(key_path, 'rb') as f:
# signer = AdbKey(f.read())
# device = AdbDevice(host='127.0.0.1', port=5037)
# device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
# 認証が不要、または事前に認証済みの場合(一般的なケース):
try:
device = AdbDevice(host='127.0.0.1', port=5037)
device.connect(rsa_keys=None, auth_timeout_s=0.1)
if device.available:
print("デバイスに正常に接続しました。")
else:
print("デバイスに接続できませんでした。USBデバッグの有効化、adb serverの起動を確認してください。")
except Exception as e:
print(f"接続エラーが発生しました: {e}")
- 注意点
adb-shell
はデバイスとの直接的な通信を扱うため、Pythonスクリプトを実行するPC上でadb start-server
が実行されている必要があります。また、デバイスがPCに適切に接続され、USBデバッグが有効になっていることを確認してください。
Pythonで実践!よく使うADBコマンド自動化レシピ
それでは、具体的なADBコマンドの自動化レシピを見ていきましょう。
デバイス接続の確認とリスト表示
adb-shell
は単一デバイスへの接続を前提としていますが、subprocess
モジュールを使えば、接続されているデバイスのリストを取得できます。
Python
def get_connected_devices():
"""接続されているADBデバイスのシリアル番号と状態をリストで取得します。"""
command = "adb devices"
process = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8')
if process.returncode == 0:
output_lines = process.stdout.strip().split('\n')
devices = []
if len(output_lines) > 1: # ヘッダー行を除外
for line in output_lines[1:]:
if line.strip():
parts = line.split('\t')
if len(parts) == 2:
devices.append({"serial": parts[0], "status": parts[1]})
return devices
else:
print(f"adb devicesコマンドの実行に失敗しました: {process.stderr}")
return []
# 接続されているデバイスをリストアップ
connected_devices = get_connected_devices()
if connected_devices:
print("接続されているデバイス:")
for dev in connected_devices:
print(f" シリアル: {dev['serial']}, 状態: {dev['status']}")
else:
print("接続されているデバイスはありません。")
# シリアル番号を指定して接続したい場合(複数のデバイスがある場合)
# device = AdbDevice(host='127.0.0.1', port=5037, serial='YOUR_DEVICE_SERIAL')
# device.connect(...)
アプリケーションのインストール・アンインストール
APKファイルのインストールや、既存アプリのアンインストールを行います。adb-shell
には直接インストールする高レベルなAPIがないため、subprocess
モジュールを使ってadb install
コマンドを直接呼び出すのが一般的です。
Python
def install_app(apk_path):
"""指定されたAPKファイルをデバイスにインストールします。"""
command = f"adb install \"{apk_path}\"" # パスにスペースが含まれる可能性があるためクォート
print(f"アプリ {apk_path} をインストール中...")
process = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8')
if process.returncode == 0:
print(f"アプリ '{apk_path}' のインストールに成功しました。")
print(process.stdout)
else:
print(f"アプリ '{apk_path}' のインストールに失敗しました: {process.stderr}")
def uninstall_app(package_name):
"""指定されたパッケージ名のアプリをデバイスからアンインストールします。"""
command = f"adb uninstall {package_name}"
print(f"アプリ {package_name} をアンインストール中...")
process = subprocess.run(command, shell=True, capture_output=True, text=True, encoding='utf-8')
if process.returncode == 0:
print(f"アプリ '{package_name}' のアンインストールに成功しました。")
print(process.stdout)
else:
print(f"アプリ '{package_name}' のアンインストールに失敗しました: {process.stderr}")
# 使用例:
# install_app("C:/Users/YourUser/Downloads/your_app.apk")
# uninstall_app("com.example.your_package_name")
ファイルのプッシュ・プル
PCとデバイス間でファイルをやり取りします。これはadb-shell
ライブラリの得意分野です。
Python
# PCからデバイスへファイルをプッシュ (adb push)
local_file_path = 'local_data.txt' # PC上のファイルパス
remote_file_path = '/sdcard/Download/remote_data.txt' # デバイス上のパス
try:
# テスト用のファイルをPCに作成
with open(local_file_path, 'w', encoding='utf-8') as f:
f.write("これはPythonからプッシュされるテストファイルです。\n")
f.write("Hello Android Automation!")
device.push(local_file_path, remote_file_path)
print(f"ファイル '{local_file_path}' をデバイスの '{remote_file_path}' にプッシュしました。")
except Exception as e:
print(f"ファイルプッシュに失敗しました: {e}")
# デバイスからPCへファイルをプル (adb pull)
pulled_local_path = 'pulled_data.txt' # PCに保存するパス
pulled_remote_path = '/sdcard/Download/remote_data.txt' # デバイス上のパス
try:
device.pull(pulled_remote_path, pulled_local_path)
print(f"デバイスの '{pulled_remote_path}' からファイル '{pulled_local_path}' をプルしました。")
with open(pulled_local_path, 'r', encoding='utf-8') as f:
print("プルしたファイルの内容:")
print(f.read())
except Exception as e:
print(f"ファイルプルに失敗しました: {e}")
スクリーンショットの取得
デバイスのスクリーンショットを撮り、PCに保存します。これはシェルコマンドの実行とファイルのプルを組み合わせます。
Python
def take_screenshot(device, local_save_path="screenshot.png"):
"""デバイスのスクリーンショットを取得し、PCに保存します。"""
remote_screenshot_path = '/sdcard/temp_screenshot.png'
try:
# デバイス上でスクリーンショットを撮影し、一時的に保存
print(f"デバイスでスクリーンショットを撮影中...")
device.shell(f'screencap -p {remote_screenshot_path}')
time.sleep(1) # スクリーンショットが保存されるまで少し待つ
print(f"スクリーンショットを '{remote_screenshot_path}' に保存しました。")
# PCにプル
device.pull(remote_screenshot_path, local_save_path)
print(f"スクリーンショットをPCにプルしました: '{local_save_path}'")
# デバイス上の一時ファイルを削除
device.shell(f'rm {remote_screenshot_path}')
print(f"デバイス上の一時ファイル '{remote_screenshot_path}' を削除しました。")
except Exception as e:
print(f"スクリーンショットの取得またはプルに失敗しました: {e}")
# 使用例:
# take_screenshot(device, "my_app_screenshot.png")
シェルコマンドの実行
任意のシェルコマンドをデバイス上で実行します。これはadb-shell
の主要な機能です。
Python
# デバイスのプロパティを取得
result = device.shell('getprop ro.build.version.release')
print(f"Androidバージョン: {result.strip()}")
# インストールされているパッケージの一覧を取得
result = device.shell('pm list packages -f') # -f オプションでAPKファイルのパスも表示
print("\nインストールされているパッケージ (パス付き):")
for line in result.splitlines():
if line.strip():
print(f"- {line.strip()}")
# テキスト入力のシミュレーション(例:検索ボックスにテキストを入力)
# 注意:特定のアプリの入力フィールドにフォーカスがある必要があります
# device.shell("input text 'Hello Automation'")
# print("デバイスに 'Hello Automation' と入力しました。")
# キーイベントの送信(例:HOMEボタンを押す)
# keyeventのコードはAndroid開発者サイトを参照
# device.shell("input keyevent 3") # KEYCODE_HOME
# print("HOMEボタンを押しました。")
# 画面タップのシミュレーション(X, Y座標)
# device.shell("input tap 500 1000") # 例: 画面中央付近をタップ
# print("座標 (500, 1000) をタップしました。")
パッケージ情報の取得
特定のアプリの情報を取得したり、インストールされているパッケージをより詳細にリストアップしたりします。
Python
# 特定のパッケージの情報を取得
package_name_to_check = "com.android.chrome"
result = device.shell(f'dumpsys package {package_name_to_check} | grep "versionName"')
print(f"\n{package_name_to_check} のバージョン情報:")
if result.strip():
print(result.strip())
else:
print("情報が見つかりませんでした。パッケージ名を確認してください。")
# アプリの起動 (例: Google Chrome)
# 実行にはパッケージ名とActivity名を指定します。
# Activity名は `dumpsys package <package_name> | grep -A 1 "Main activities"` などで確認できます。
# chrome_package = "com.android.chrome"
# chrome_activity = "com.google.android.apps.chrome.Main"
# device.shell(f'am start -n {chrome_package}/{chrome_activity}')
# print(f"アプリ {chrome_package} を起動しました。")
# デバイスとの接続を切断
if device.available:
device.close()
print("デバイスとの接続を切断しました。")
まとめ
本記事では、Pythonとadb-shell
ライブラリを用いて、Androidデバイスの基本的なADB操作を自動化する具体的なレシピを実践的に解説しました。
- Pythonの
subprocess
モジュールとadb-shell
を組み合わせることで、デバイス情報の取得、アプリのインストール・アンインストール、ファイルのプッシュ・プルといった一連の作業を効率的に自動化できます。 - 特に、
device.shell()
メソッドを使えば、任意のシェルコマンドを実行し、デバイスを細かく制御することが可能です。これにより、スクリーンショットの取得やテキスト入力、キーイベントの送信など、多岐にわたる操作が実現できます。
これらの自動化レシピを組み合わせることで、日常の開発・テスト業務におけるAndroidデバイス操作の多くの部分をスクリプト化し、時間と労力を大幅に節約できます。次の記事では、ADB単体では難しいUI操作の自動化や、スクリプト開発中に遭遇しがちなトラブルシューティングについて、さらに掘り下げて解説します。より高度な自動化を目指す方は、ぜひ次の記事も参考にしてください。
コメント