Skip to Content

Androidアクション

Androidアクションは、Androidのエミュレータまたは実機の上のアプリを操作します。アプリの起動、タップ、文字の入力、戻るボタン、要素の待機、テキストの読み取り、スクリーンショットの保存ができます。LinuxとmacOSで動きます。

外部アクションとしてmozership/probe-android で公開しています。ワークフローが初めて使うときにProbeがダウンロードし、固定したコミットのaction.ymlが示すSHA-256と一致する実行ファイルだけを実行します。

仕組み

アクションはadbだけで動きます。ビルドするものはなく、端末に入れるのもテスト対象のアプリだけです。要素に対する各操作は、uiautomator dumpで画面を読み、要素が現れるまで読み直してから、inputで操作します。タップは要素の中央へのinput tap、入力はinput textです。日本語などinput textで入力できない文字は、ADBKeyBoardで入力します。

必要なもの用意の仕方
adbAndroid SDK Platform-Tools。PATHか$ANDROID_HOME/platform-toolsに置く
起動済みのエミュレータまたは実機emulator -avd <name>、またはUSBデバッグを有効にした実機。adb devicesでdeviceと表示されること
テスト対象のアプリ端末にインストールしておく:adb install path/to/app.apk

アクションはエミュレータの起動もアプリのインストールも行いません。起動の失敗がテストの失敗と取り違えられないよう、shellステップなどの別のステップで行ってください。

エミュレータのアニメーションは、adb shell settings put global animator_duration_scale 0と、window_およびtransition_で始まる同様の設定でオフにしてください。uiautomatorは動いている途中の画面を読めないので、アクションはアニメーションが終わるまで待つことになります。

基本的な構文

ワークフローでは40文字のコミットSHAでアクションを固定します。各リリース のノートの先頭に、コピーして使うアクションとコミットがあります。

name: Settings actions: android: github.com/mozership/probe-android@bd855d4c4c0a62c662f7e059e4ff5b0586c63732 # v0.2.0 jobs: - name: settings steps: - name: Open Network & internet uses: android with: app: com.android.settings actions: - name: launch - name: tap selector: text="Network & internet" - name: text id: airplane selector: text="Airplane mode" test: res.code == 0 && res.results.airplane == "Airplane mode"

画面は端末に残るので、後のステップは前のステップが終えた画面から操作を続けます。

パラメータ

パラメータ型必須デフォルト説明
app文字列はい-操作するアプリのパッケージ名
actionsリストはい-順に行う操作。アクションを参照
device文字列いいえ唯一の端末端末のシリアル(emulator-5554など)またはモデル名。adbに複数の端末が表示されるときは指定が必要
timeout期間の文字列または秒数いいえ30s最初から最後までの操作の制限時間

アクション

actionsの各要素は、nameで操作を指定します。

操作フィールド内容
launchランチャーのアイコンと同じようにアプリを新しく起動します。動いていれば先に終了させます
activateアプリを元の状態のまま前面に出します。動いていなければ起動します
terminateアプリを終了します
back戻るボタンを押します
tapselector要素の中央をタップします
typeselector、value要素をタップし、valueを入力します。文字の入力を参照
waitselector要素が画面に現れるまで待ちます
textselector、id要素のテキストを読み、テキストがなければコンテンツの説明を読んで、res.resultsに入れます
treeid画面を1行に1要素の形でres.resultsに入れます。セレクタで指定できる内容がわかります
screenshotid画面をPNGで保存し、そのパスをres.filepathsに入れます

idは結果のキーで、省略すると操作の名前がキーになります。要素に対する操作は、timeoutの残り時間だけ要素が現れるまで画面を読み直し、現れなければステップは失敗します。操作が受け付けないキー(iOSアクションのargsなど)を持つ要素は、ステップの実行前にエラーになります。

treeは、画面の要素を深さに応じて字下げし、1行に1つずつ並べます。

TextView id=android:id/title text="Network & internet" [200,540][700,600] EditText id=com.android.settings:id/ssid text="Wi-Fi" [20,230][256,278] focused

セレクタ

セレクタは、空白で区切ったkey=valueの組で要素を指定します。空白を含む値は二重引用符で囲みます。

キー一致する対象
idリソースID。com.example:id/loginのように全体でも、loginのように名前だけでも指定できます
text表示されているテキスト
descコンテンツの説明。アイコンなどでスクリーンリーダーが読み上げる文字列です
classクラス。android.widget.Buttonのように全体でも、Buttonのように名前だけでも指定できます
index一致した要素のうち、treeの並び順で何番目か(0始まり)。省略すると最初の要素

=を含まないセレクタはリソースIDとして扱うので、loginはid=loginと同じです。

文字の入力

typeは、表示可能なASCII文字をinput textで入力します。input textはどの端末でも使えます。ただし日本語などそれ以外の文字や、input textが空白と解釈する%sは入力できません。そうした文字は、adbから送った文字列を入力するIMEであるADBKeyBoard で入力します。

- name: type selector: id=ssid value: 日本語

ADBKeyBoardは、リリース のkeyboardservice-debug.apkをadb installして、端末に入れておく必要があります。アクションはADBKeyBoardをインストールしません。入っていない端末では、ADBKeyBoardが必要なステップを最初の操作の前に失敗させます。インストール以外の設定は要りません。そうした文字を入力するステップは、最初の操作の前にADBKeyBoardをIMEに切り替え(有効でなければ有効にし)、ステップが終わると、失敗した場合も含めて元のIMEに戻します。ADBKeyBoardは準備が整う前に送られた文字列を捨てるので、アクションはフォーカスのある要素に文字列が入るまで画面を読み直し、入っていなければ送り直します。

uiautomatorで画面を読むと、ソフトキーボードが閉じます。フォーカスは要素に残るのでtypeはそのまま入力できますが、キーボードが閉じたときに画面を変えるアプリは、そこから先を操作できません。たとえば設定アプリの検索は、キーボードが閉じると検索画面ごと閉じます。

レスポンスオブジェクト

フィールド説明
res.codeすべての操作が成功したときは0
res.resultstextとtreeが読んだ内容(キーごと)
res.filepathsscreenshotが保存したファイル(キーごと)
res.device操作した端末のシリアル

最後まで終えられなかった操作は、ステップをアクションエラーで失敗させます。このとき実行は終了ステータス3で終わり、テストするresはありません。

actions[1] tap: no element matches text="No Such Row" within 5.0s

CI

GitHub ActionsのUbuntuのランナーでは、KVMを使ってエミュレータを動かせます。android-emulator-runner がエミュレータを起動してアニメーションをオフにし、起動しているあいだにスクリプトを実行します。

name: E2E on: [pull_request] jobs: e2e: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Install Probe uses: mozership/probe-action@v1.3.0 with: install-only: true - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - uses: reactivecircus/android-emulator-runner@v2 with: api-level: 35 target: google_apis arch: x86_64 script: probe e2e.yml
更新日時