はじめに
これをやろうと思うに至った、事の発端としては、弊社の開発メンバーの平日早朝5時からの勤務や、土日出勤率が上がってきており、それが問題視されるようになりました。
その理由を聞いたら、主に、「総合試験(出勤しなければアクセスできないネットワーク上にある)においてのリアルな時間でのスマフォアプリの動作確認」という事だったのです。。。
そこで、このスマフォアプリの動作を、社内のPCで、ある時間指定で自動で動作させて、画面のスクリーンショットを取る所までを何とか出勤せずに自動で行う事ができないかと思い、調べまくって実装してみました。
出来た事
・パソコンから自動で、スマフォ(実機・Android端末)のアプリを起動し、操作することができた。
・スクリーンショットを取って、ファイルサーバに格納
・これを土日や朝一などの日時を指定して定期的に実行
[制約]
・パソコンを起動したままにしておくこと
・スマフォをスリープ状態に入らない設定にして、起動したままにしておくこと
・パソコンのOSは、Windows10
・スマフォは、Android OSの端末
・USBのデータ通信用ケーブルが必要(※充電用とは異なります。ご注意を)
(※今回は、目的上、スマフォを社内の総合環境に接続しましたが、もちろん、インターネット(WiFiなど)への接続でも、同じような構成で自動操作が可能です。)
PC上で使ったツールやプログラミング言語は以下です。これらをPCにインストールする必要があります。
・Python
・Appium(GUI)
・その他、Appiumの動作に必要なもの
・タスクスケジューラ(※Windows10に初めからインストールされているもの)
##環境準備
Windows10のPCにAppium GUI版をインストールします。
私がGUI版をお勧めする理由は、その方がプログラミングが圧倒的に楽になるためです。
運用するときには、CUI版を使ってもいいかもですね。
環境準備には、以下のサイトを参考にしました。
https://qiita.com/emurin/items/fe640327f847c474f1e8
①Javaのインストール
・環境変数の「JAVA_HOME」に設定(例:「C:\Program Files\Java\jdk-15.**」を設定)
・環境変数の「path」に設定(例:「%JAVA_HOME%\bin」を設定)
・念のため、コマンドプロンプトで、「java -versioin」などでコマンドが実行できることを確認
②Pythonのインストール
・インストーラーをダウンロード
・インストーラー起動時、「Add Python 3.x to PATH」みたいなとこにチェックを付けておくことで、環境変数の「path」に自動的に追加してくれます。
・コマンドプロンプトで、「pip install Appium-Python-Client」を実行(※これは後で使うライブラリをインストールしている。)
③Android Studio のインストール
・起動させて初期設定すると、インストールが走り、「C:\Users*\AppData\Local」に「Android」というディレクトリを作成してインストールしてくれます。
・環境変数の「ANDROID_HOME」に設定(例:「C:\Users*\AppData\Local\Android\Sdk」)
・環境変数の「path」に設定(例:「%ANDROID_HOME%\platform-tools」を設定)
・ここで、念のため、「adb devices」などと打って、応答返ってくることを確認
④Appium GUI Windows版 のインストール
以下のように起動すればOK
##スマフォと接続してみる
USBのデータ通信用ケーブルで、PCとスマフォを接続します。
設定から、「システム」メニューを開き、「開発者向けオプション」を開きます。
この「開発者向けオプション」が表示されていない場合には、↓「端末情報」の「ビルド番号」という箇所を5,6回タップすると、「開発者向けオプション」が一時的に表示されるようになるはずです。
「開発者向けオプション」を開き、「ON」にチェックをし、
「スリープモードにしない」と「USBデバッグ」のチェックをONにします。
コマンドプロンプトで、「adb devices」と打ち込み、以下のように表示されればOKです。これで準備完了。
##Appium GUIクライアントから接続
ここからが、本番です。
まずは、AppiumのGUIクライアントを起動して、スマフォの画面にアクセスしてみます。
まずは、PCで、AppiumのGUIクライアントを起動し、「Start Server v*****」をクリックします。
すると、Appiumのサーバが起動した状態となります。
起動にはそこそこ時間が掛かりますが、↓のような画面になるはずです。
そこで、画面左下に、どこに接続したいのかを記載するのですが、今回はAndroid端末1台だけなので、とりあえず、↓のような感じで十分です。
↓コピペ用に使ってください
{
"platformName": "Android"
}
繰り返し使う事になるので、保存しておくことをお勧めします。
そして、右下の「Start Session」ボタンを押します。
このようにスマフォの画面が表示されるというわけです。凄いですよね!
##Appiumを使って、Pythonでプログラミング
スマフォアプリを自動操作するためには、1つ1つの要素のIDまたは場所(xpath)などが必要になります。これは、当然開発者でなければ知ることは難しいものなのですが、Appium GUIクライアントの場合、自分が開発者でなくても、IDや場所(xpath)を知ることができるのです。
PCとスマフォが接続され、Appium GUIクライアントで、↓の目のようなアイコン「Start Recording」をクリックします。
すると、↓のような録音しているかのようになります。
この状態で、画面左のスマフォ画面の「電卓」アプリのアイコンを選択すると、その要素が右下のウィンドウに表示されるので、「tap」ボタンを押します。
すると、PC画面上のスマフォで「電卓」アプリが起動しますが、
そして、同時に、プログラムコードが出力されていることがお分かり頂けるでしょうか。。
画面右上で「Python」と書かれているプルダウンですが、こちら、「Java」や「Ruby」などにも変更可能なのです。
同じように、今度は、「1」のボタンを選択して、右の要素ウィンドウの「tap」をクリックすると↓のようになります。
後は、これの繰り返しです。
「+」ボタン押して、「tap」ボタン
「2」ボタン押して、「tap」ボタン
「=」ボタン押して、「tap」ボタン
このような感じで、ボタン操作をプログラムコードとして、生成してくれるのです。
そして、↓右上の「Python」を選んでいるプルダウン隣、「四角に矢印」が付いたアイコンボタンをクリックすると、インポート文を含む、全体のプログラムコードが生成されます。
↓生成されたコードがこちら。
# This sample code uses the Appium python client
# pip install Appium-Python-Client
# Then you can paste this into a file and simply run with Python
from appium import webdriver
caps = {}
caps["platformName"] = "android"
caps["ensureWebviewsHavePages"] = True
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
el1 = driver.find_element_by_accessibility_id("電卓")
el1.click()
el2 = driver.find_element_by_id("com.google.android.calculator:id/digit_1")
el2.click()
el3 = driver.find_element_by_accessibility_id("足す")
el3.click()
el4 = driver.find_element_by_id("com.google.android.calculator:id/digit_2")
el4.click()
el5 = driver.find_element_by_accessibility_id("イコール")
el5.click()
driver.quit()
これをコピー&ペーストでテキストファイルにして、適当なファイル名で「.py」拡張子を付けて保存します。仮に「test01.py」というファイル名で保存した場合、コマンドプロンプトからは、以下のコマンドで実行できます。
> python [パス]/test01.py
##プログラムコードに書き入れる
先ほど作った「test01.py(仮)」に対して、スクリーンショットの取得や待機、またはアサーションなどの処理コードを必要に応じて書き足します。
###スクリーンショット
スクリーンショットは以下でできます。必要な箇所に差し込んでください。
driver.save_screenshot('[パス]/screenshoto1.png')
###待機
画面遷移やデータのロード時間などで、一時的に処理を止めたい場合などは、Sleepさせることもできます。以下は、2秒間待機させる場合の例です。必要な箇所に差し込んでください。
sleep(2)
###ある要素が見つかるまで待機
sleep処理の場合、強制的にその時間を待つことになるので、非効率です。
なので、ある要素が見つかるまで待機という方法も書けます。
いくつか書き方はありますが、例としては↓です。xpathでの指定を例としてます。
def find_element_by_xpath_ex(xpath):
"""
要素が見つかるまで0.5秒のスリープを挟みながら繰り返し検査し、要素が見つかり次第、その要素を返す。
繰り返した後、10秒以上分スリープさせても見つからない場合には、Noneを返す。
"""
tmp = 0
el = None
while True:
try:
el = driver.find_element_by_xpath(xpath)
if el is not None:
break
except NoSuchElementException:
if tmp > 10:
break
sleep(0.5)
tmp += 0.5
return el
###アプリ終了が上手く動かないので、アプリをバックグラウンドへ
定期的に繰り返し実行するためには、初期の状態(今回の場合、「電話区」アイコンをタップできる状態)に戻さなければなりません。
そのためには、アプリを終了したいところなのですが、「driver.quit()」や「driver.close_app()」など、何をしても戻りませんでした(´;ω;`)
というわけで仕方なく、↓のアプリをバックグラウンドへ移動させることで、初期状態にしました。
driver.background_app(-1)
##定期的な実行
定期的な実行には、↑のpythonコマンド「> python [パス]/test01.py」を書き込んだbatファイルを作っておき、それをWindows標準インストールされているタスクスケジューラで時間などを登録しておくことで定期的な実行が可能となります。
エラーになった際の再実行については、タスクスケジューラで上手く行かなかったので、結局、batファイル内でプログラミングしました。
これは、前の記事↓で記載してます。
https://qiita.com/jun_higuche/items/523e11502b5e0847571d
##その他のアプリ操作
今回、「電卓」アプリで説明しちゃったので、要素(ボタン)を選択してタップのみでしたが、他にも、「スワイプ」や「要素を指定しないタップ」ができます。
「スワイプ」はこちらから可能です。開始位置と終了位置の2点を指定することで実施してくれます。
「要素を指定しないタップ(画面上のX軸Y軸での場所指定でタップ)」はこちらから可能です。当然、実機依存になるので、あまり使わない方がいいと思います。
また、他にも、Actionsというタブがあって、そこからも色々な操作ができるようになっています。
Appiumのクライアントでの操作が全てではない可能性もありますので、↓のAPIドキュメントで調べて手動で書いていく方法も同時に考えてみましょうね。
http://appium.io/docs/en/about-appium/api/
こちら、各プログラミング言語での書き方も書いてくれているので、とても分かりやすいです。
##出来そうにない操作
ピンチイン/ピンチアウト(2本の指を使って拡大縮小させる動作)は見当たらず、、できないのかもしれません。
その他にも、細かいモノをタップしてそれをドラッグ移動させるような操作も不向きに思えます。オブジェクトにはIDが割り当てられていて、それを指定し、パラメータなどで数値を与えることができるものであることが理想な作りなのだと思われます。
##最後に
とりあえず、Android端末での自動操作をしたかったので、Windows10のPCと接続して、自動操作をできるようにしました。
現在、2週間ほど回していて、問題なく、スクリーンショット画像が取れています!ほんと素晴らしく安定稼働!
というのは、割といろんなパターン(起動時にエラーが出たときや、エラー後に想定外の画面から始まった場合など)を考え、「こういう画面の場合には、こういう操作をさせる。」みたいなのをだいぶ作り込んでいるのです。
今後は、iPhoneでも同じように自動での動作テストをしたいという要望があがっているので、iMac+iPhoneでやってみようと思います。たぶん、ほとんど同じだと思いますが、、
こちらも、もし上手く出来た際には、またQiitaで記事を書くつもりです。
それでは、また。
誰かの参考になれば幸いですm(__)m