Appiumで画面を録画してみよう

この記事は [Selenium/Appium Advent Calendar 2018](https://qiita.com/advent-calendar/2018/selenium_and_appium) の13日目の記事です。

こんにちは！
人に言えない動画の話をしませんか！！！


Appiumに画面録画機能がつきました
==============

Android向けにはバージョン1.7.0(2017年9月19日リリース)、iOS向けにはバージョン1.8.0(2018年4月21日リリース)から、端末の画面を動画で記録する機能が使えるようになりました。
けっこうオッと思う機能な気がするんですが、日本語での言及がどこにも無くないですか！！ 人に言えない動画ですか！！！

各クライアントライブラリーからの使い方は公式リポジトリーのドキュメントにかんたんに記載されています。試しに使ってみましょう。
https://github.com/appium/appium/tree/master/docs/en/commands/device/recording-screen


実際にやってみよう
================================

アドベントカレンダー11日目 [AppiumでiOS/Androidアプリの自動テストを試した 〜Appiumをインストールして自作サンプルアプリをなんとか動かすまで〜](https://qiita.com/devnokiyo/items/3cea66eb83280985d6cc) で公開していただいたiOS向けサンプルアプリを題材にやってみましょう。ありがてえありがてえ。
ライブラリー等のバージョンは次の通りです。

|||
|:--|:--|
| OS | macOS Mojave 10.14.1 |
| Node.js | 8.11.3 |
| Java | 1.8.0_101 |
| JUnit | 4.12 |
| Appium | 1.10.0 |
| io.appium.java_client | 6.1.0 |

iOS向けのかんたんなサンプルコードは次のとおりです。

```Java
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.screenrecording.CanRecordScreen;

public class SampleTest
{
    AppiumDriver driver;

    @Before
    public void setUp() throws MalformedURLException
    {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("platformName", "iOS");
        capabilities.setCapability("platformVersion", "12.1");
        capabilities.setCapability("deviceName", "iPhone 8");
        capabilities.setCapability("automationName", "XCUITest");
        capabilities.setCapability("app", "/path/to/AppiumDemo.app");

        URL wdRemoteAddress = new URL("http://127.0.0.1:4723/wd/hub");

        driver = new IOSDriver<>(wdRemoteAddress, capabilities);
        ((CanRecordScreen) driver).startRecordingScreen();
    }

    @After
    public void tearDown() throws IOException
    {
        String base64Video = ((CanRecordScreen) driver).stopRecordingScreen();
        Files.write(Paths.get("./test.mov"), Base64.getDecoder().decode(base64Video));
        driver.quit();
    }

    @Test
    public void test1() throws InterruptedException
    {
        driver.findElement(By.id("txtId")).sendKeys("devnokiyo");
        driver.findElement(By.id("txtPassword")).sendKeys("abcd1234");
        driver.findElement(By.id("btnLogin")).click();

        Thread.sleep(2000);
    }
}
```

ポイントとなる2つのAPI `startRecordingScreen` `stopRecordingScreen` に絞って説明していきます。

## startRecordingScreen

まず、録画を開始する `startRecordingScreen` です。

```Java
        ((CanRecordScreen) driver).startRecordingScreen();
```

AppiumDriverクラスのインスタンスを [CanRecordScreen](https://appium.github.io/java-client/io/appium/java_client/screenrecording/CanRecordScreen.html) インターフェイスでキャストするか、またはこのインターフェイスが実装されているIOSDriverクラスやAndroidDriverクラスのインスタンスで、メソッド `startRecordingScreen` が利用できます。このサンプルコードでは何もオプションを指定していないので、既定値にしたがった形式で録画されます。
次のように、様々なオプションを設定することもできます。

```Java
        ((CanRecordScreen) driver).startRecordingScreen(
                new IOSStartScreenRecordingOptions()
                    .withTimeLimit(Duration.ofSeconds(180)) // 最大録画時間
                    .withVideoQuality(VideoQuality.MEDIUM) // 録画品質 low, medium, high, photo の4つから選択可能
                    .withVideoType(VideoType.MP4) // 録画形式 h264, mp4, fmp4 の3つから選択可能
                    .withUploadOptions(
                            new ScreenRecordingUploadOptions() // 録画終了時にどこかのサーバーにアップロードする場合のオプション
                                .withAuthCredentials("username", "password") // HTTP接続 またはFTP接続で認証が必要な場合に利用するユーザー名とパスワード
                                .withHttpMethod(RequestMethod.PUT) // HTTP接続でアップロードするときのメソッド
                                .withRemotePath("https://www.xvideos.com/") // アップロード先のURL ここを職場でコピペするとお前は社会的に死ぬ
                            )
                );
```

既定値の `VideoType.MP4` で記録すると、macOS標準のQuickTime Playerでは閲覧できませんので注意しましょう。おっさんは伝統の [VLC](https://www.videolan.org/vlc/) でも使えや。


## stopRecordingScreen

次に、録画を終了する `stopRecordingScreen` です。

```Java
        String base64Video = ((CanRecordScreen) driver).stopRecordingScreen();
        Files.write(Paths.get("./test.mov"), Base64.getDecoder().decode(base64Video));
```

CanRecordScreenインターフェイスが必要になるのは `startRecordingScreen` と同じです。
`stopRecordingScreen` は、 `ScreenRecordingUploadOptions` クラスによるアップロード指定が無い場合は、返り値にBASE64エンコードされた動画データを渡してきます。このサンプルコードではかんたんにデコード・ファイル出力しました。


## 出力結果のサンプル

では、試しに録画品質を「photo」、録画形式を「h264」で出力してみましょう。なんか最高品質っぽい感じがするんですよ。
(Qiitaの記事に貼り付けやすいようにGIFに変換しました)

![動画](https://qiita-image-store.s3.amazonaws.com/0/33963/259f4b06-db18-2731-c627-7ea343e709a9.gif)

オッ 撮れてるね！！ きれいだね！！！ ムフフ！！！！！

動画のフォーマットとしては25fpsと記録されていましたが、どうもそれよりもっとフレームレートが低い気がします。
とはいえ、動作概況の証跡として手軽に残すにはこれで十分なんじゃないでしょうか。Java以外のクライアントライブラリーにも実装されていますし、既存のコードにも気軽に組み込めますので、ぜひ一度試してはいかがでしょう！


今回はここまで
==================

次回は...誰かー！ 誰か来てくれーーー！！！
Selenium/Appium Advent Calendar 2018はまだまだ君の挑戦を待っているぜ！