LoginSignup
6
3

More than 3 years have passed since last update.

AppiumでAndroidアプリのスクリーンショットをとってみた

Last updated at Posted at 2019-12-06

Appiumとは

Appium

Appiumはネイティブもしくはハイブリッドなモバイルアプリのためのオープンソーステスト自動化フレームワークです。

私は毎週毎週Androidアプリの最新版のスクリーンショットを手動で取るのが嫌になってAppium導入しました:sweat_smile:

UIテストの自動化もできますが、今回はひとまずスクリーンショット取れるところまで。

環境構築

まずはAppiumを動かせる環境を構築します。
Node.jsをインストールしてからnpmでappiumとwd(Webdriver/Selenium 2クライアント)をインストールするだけです。

以下、公式ページから引用

brew install node      # get node.js
npm install -g appium  # get appium
npm install wd         # get appium client
appium &               # start appium
node your-appium-test.js

これでNode.jsで書いたスクリプトを動かせるのですが、スクリプトを全部自分で書くのはとても面倒です。
UIコンポーネントのパスとか自分の頭で考えたくない。。
ですので、appium-desktopをインストールして自動でスクリプトに落としてもらいましょう。

GitHub - appium/appium-desktop: Appium Server and Inspector in Desktop GUIs for Mac, Windows, and Linux

上記からダウンロードしてインストールします。

appium-desktop

appium-desktopを起動すると以下のような画面が表示されます。

image.png

「Start Server v1.15.1」をクリックしてサーバを起動します。

image.png

右上の虫眼鏡ボタンをクリックします。
すると、以下の画面が表示されます。
「JSON Representation」にエミュレータや端末の情報をJSON形式で設定します。

image.png

編集ボタンをクリックして、JSONを記載します。
JSONの記載方法は以下のサイトに詳しく解説があります。

Desired Capabilities - Appium

最低限必要な項目を設定します。
今回はAndroidの設定を行います。

例)
例えばこんな感じです。値は適宜変更してください。

{
    "platformName": "Android",
    "platformVersion": "9",
    "deviceName": "emulator-5554",
    "app": "/Users/miyatay/Documents/flutter_app/build/app/outputs/apk/debug/app-debug.apk"
}
key value
platformName Android
platformVersion 9
deviceName emulator-5554
app [apkの絶対パス]

platformNameはAndroidの場合は"Android"固定
platformVersionはAndroidのOSのバージョンを設定します

image.png

deviceNameはadb devicesコマンドで表示されたデバイス名を設定します

$ adb devices
List of devices attached
emulator-5554   device

以下のキャプチャは上記の設定をした状態です。
image.png

「Start Session」ボタンをクリックしてセッションを開始します。

設定が正しいければ以下の画面が表示されます。
このアプリはAndroidStudioでFlutterプロジェクトを作成すると自動で生成されるカウントアップアプリです。
image.png

もし、画面が真っ白な場合はリロードボタンをクリックしてみてください。
ボタンをクリックしてみます。
画面上部の目のマークのボタンをクリックしてください。
image.png

画面左側にカーソルを合わせると、選択できるコンポーネントが黄色く表示されます。
image.png

TapやSend Keysなどを選択すると動作がキャプチャされます。
画面上部にスクリプトが自動生成されるのでこちらをコピーすると同じ動作を何度でもさせることが可能になります。
Show/Hide Boilerplate Codeを選択することで初期処理をコードに含めるか否か選ぶことができます。
Showすると、ドライバーの初期化や接続の設定情報などを吐き出してくれるのでとても便利です。
image.png

Boilerplate CodeをShowにしてコードをテキストエディタにコピーします。
今回はJS-WD(Promise)を選択しました。

こんな感じになりました。

// Requires the admc/wd client library
// (npm install wd)
// Then paste this into a .js file and run with Node 7.6+

const wd = require('wd');
const driver = wd.promiseChainRemote("http://localhost:4723/wd/hub");
const caps = {"platformName":"Android","platformVersion":"9","deviceName":"emulator-5554","app":"/Users/miyatay/Documents/flutter_app/build/app/outputs/apk/debug/app-debug.apk"};

async function main () {
  await driver.init(caps);
  let el1 = await driver.elementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.Button");
  await el1.click();
  await driver.quit();
}

main().catch(console.log);

実行するとこうなりました。

$ node sample.js
{ Error: [elementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.Button")] Error response status: 7, , NoSuchElement - An element could not be located on the page using the given search parameters. Selenium error: An element could not be located on the page using the given search parameters.
    at exports.newError (/Users/miyatay/node_modules/wd/lib/utils.js:152:13)
    at /Users/miyatay/node_modules/wd/lib/callbacks.js:94:19
    at /Users/miyatay/node_modules/wd/lib/webdriver.js:196:5
    at Request._callback (/Users/miyatay/node_modules/wd/lib/http-utils.js:89:7)
    at Request.self.callback (/Users/miyatay/node_modules/request/request.js:185:22)
    at Request.emit (events.js:197:13)
    at Request.<anonymous> (/Users/miyatay/node_modules/request/request.js:1161:10)
    at Request.emit (events.js:197:13)
    at IncomingMessage.<anonymous> (/Users/miyatay/node_modules/request/request.js:1083:12)
    at Object.onceWrapper (events.js:285:13)
  message:
   '[elementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.Button")] Error response status: 7, , NoSuchElement - An element could not be located on the page using the given search parameters. Selenium error: An element could not be located on the page using the given search parameters.',
  status: 7,
  cause:
   { status: 7,
     value:
      { message:
         'An element could not be located on the page using the given search parameters.' },
     sessionId: '43f216e2-8b0b-481e-baae-63ae74b73c29' },
  inspect: [Function],
  'jsonwire-error':
   { status: 7,
     summary: 'NoSuchElement',
     detail:
      'An element could not be located on the page using the given search parameters.' } }

ボタンのelementが見つけられなくてエラーになっているようです。
elementが見つかるまでの待機時間を設定してみます。
Implicit Wait - Appium

UIAutomatorを使うとNoSuchElementが出にくくなるとの記事も見た気がしますが今回はこのまま突き進みます。。

sample.js
// Requires the admc/wd client library
// (npm install wd)
// Then paste this into a .js file and run with Node 7.6+

const wd = require('wd');
const driver = wd.promiseChainRemote("http://localhost:4723/wd/hub");
const caps = { "platformName": "Android", "platformVersion": "9", "deviceName": "emulator-5554", "app": "/Users/miyatay/Documents/flutter_app/build/app/outputs/apk/debug/app-debug.apk" };

async function main() {
    await driver.init(caps);
    await driver.setImplicitWaitTimeout(5000); // 暗黙的な待機時間を設定
    let el1 = await driver.elementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.Button");
    await el1.click();
    await driver.quit();
}

main().catch(console.log);

コピペで5秒に設定しました。
再度、node sample.jsでスクリプトを起動します。
一瞬アプリが起動して終了すると思います。
これでスクリプトを動かせるようになりました。

今回はスクリーンショットを取得したいので、以下のページを参考にスクリーンショットを取得してみます。
Screenshot - Appium

sample.js
// Requires the admc/wd client library
// (npm install wd)
// Then paste this into a .js file and run with Node 7.6+

const wd = require('wd');
const fs = require('fs')
const driver = wd.promiseChainRemote("http://localhost:4723/wd/hub");
const caps = { "platformName": "Android", "platformVersion": "9", "deviceName": "emulator-5554", "app": "/Users/miyatay/Documents/flutter_app/build/app/outputs/apk/debug/app-debug.apk" };

async function main() {
    await driver.init(caps);
    await driver.setImplicitWaitTimeout(5000);
    let el1 = await driver.elementByXPath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.Button");

    // スクリーンショット取得
    let base64 = await driver.takeScreenshot();
    const buffer = Buffer.from(base64, 'base64');
    fs.writeFileSync("screen.jpg", buffer)

    await el1.click();
    await driver.quit();
}

main().catch(console.log);

これで実行すると、screen.jpgが保存されます。
あとは全画面でスクリーンショットを取るスクリプトを書くだけ:rolling_eyes:
モックサーバとの連携も必要ですね。。

以上、Appiumでスクリーンショットを取る方法でした。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3