OpenSTF を Mac に入れたら 簡単にAndroid端末をリモート操作できた話

2020.09.15更新：Android 10 に対応したバージョンについて [追記・更新](#補足android-10-対応版devicefarmer版への移行について) しました

## この記事でわかること
- MacOS に OpenSTF をインストールして、Android 端末をリモートで動かすまでの手順
- Xcode やら Android Studio などの開発環境が入ってない Mac でも大丈夫
- 端末を起動する度にアプリが消えちゃう問題、転送が遅い問題への対応・対策
- Android 10 対応版のインストール・移行について

## そもそもの目的
- Android アプリの動作検証に複数の Android 端末を使うけど、OSバージョンとか画面解像度を変えてチェックする度に USB を抜き差しするのが面倒
- 会社とかだと、使いたい端末を誰が持ってるのか分からないとか、貸したら２週間返ってこないとか普通にあって困る
- OpenSTF を使って、複数の Android 端末をリモートでチェックできたら素晴らしいのでは

## OpenSTF って何？
Android 端末をブラウザからリモート操作できる（オリジナルは CyberAgent社による）オープンソースソフトウェア。STF = Smartphone Test Farm。

参考：~~[OpenSTF 公式サイト](https://openstf.io)~~（更新終了）
参考：~~[openstf/stf (GitHub)](https://github.com/openstf/stf)~~ ⇒ [DeviceFarmer/stf (GitHub)](https://github.com/DeviceFarmer/stf)（DeviceFarmer に移行）
参考：[@DeviceFarmer/stf (npm)](https://www.npmjs.com/package/@devicefarmer/stf)

## ざっくり、入れるものは以下
- HomeBrew
- nodebrew
- OpenSTF

node については、簡単にやるなら HomeBrew で node 入れたら良いんじゃないの？と思う（し、実際やった）んだけど、HomeBrew で入る node のバージョン（確認時点で 12.7.0）だと stf がインストールできなかったので、nodebrew を入れるのが良さげ。

*他にも（例えば）node のバージョンを n で管理するという選択肢もあるけど、/usr/local/bin/node を上書きするのが気になるし、nodebrew が主流のようなので。*

## 検証環境
- MacBook Pro (13-inch, Mid 2010)
- macOS (Sierra) 10.12.6

## インストールの流れ
### Homebrew をインストール
```bash:terminal
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
- 参考：[Homebrew 公式サイト](https://brew.sh/index_ja.html)
- 必要に応じて Command Line Tools (CLT) for Xcode もインストール
    - Homebrew インストールの流れで同時にインストールされれば、それで良し
    - インストールされなければ、`xcode-select --install` でインストール
- インストール後、コマンドラインで `brew doctor` と打って、`Your system is ready to brew.` と表示されればOK

### ADB をインストール（Android Studio が入っていれば不要）

```bash:terminal
$ brew cask install android-platform-tools
```
- インストール後、コマンドラインで `adb version` と打って、バージョンが表示されればOK

### STF の実行に必要なものを諸々インストール
```bash:terminal
$ brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config
```
- GitHub にある README.md の通り 
- 参考：[openstf (GitHub) > README.md](https://github.com/openstf/stf/blob/master/README.md) > Requirements

### nodebrew をインストール
```bash:terminal
$ brew install nodebrew
$ nodebrew setup

# nodebrew 用にパスを通します
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
```
- インストール＆パス設定後、コマンドラインで `nodebrew` と打って、ヘルプとバージョン情報が表示されればOK

### Node.js をインストール
```bash:terminal
$ nodebrew install-binary v9.11.2
$ nodebrew use v9.11.2
```
- Node.js のバージョンが 10以上だと OpenSTF のインストールに失敗するらしい
- ので、ver.9 の最終ビルドをインストール
 - nodebrew でインストールできるバージョンは `nodebrew ls-remote` で確認できる
- インストール後、コマンドラインで `node --version` と打って、バージョンが表示されればOK

### OpenSTF をインストール
```bash:terminal
$ npm install -g @devicefarmer/stf
```
- npm のバージョンが低いとインストールできない場合もあるらしい
    - その場合は画面の指示に従って `npm install -g npm` でアップデート
- インストール後、コマンドラインで `stf --version` と打って、バージョンが表示されればOK

## OpenSTF を起動・実行する

### データベースを起動
```bash:terminal
$ rethinkdb
```
- 実行した場所の下にデータ保存用ディレクトリが作られるので、実行する場所に注意
    - 例えば ~/ で実行すると、~/rethinkdb_data/ というディレクトリができる
- バックグラウンドで実行させたい場合は `rethinkdb &` で

### まずは、ローカルで OpenSTF を実行してみる
```bash:terminal
$ stf local
```
- OpenSTF をインストールした Mac のブラウザから `http://localhost:7100/` に繋げば、その Mac に接続されている Android 端末に接続できる
 - Android 端末側で、設定から開発者オプションに入り `USBデバッグをON` にしておく必要がある
- 動作が確認できたら、ターミナル上で Ctrl-C で終了させる

### 他の PC からアクセスできるように OpenSTF を実行
```bash:terminal
# 以下のIPアドレスは例で、実際はインストールしたMacのIPアドレスを指定
$ stf local --public-ip 192.168.1.10
```
- `--public-ip` 以降は、**STF を実行している Mac の IPアドレス** を指定
- 上記の場合、他の PC から `http://192.168.1.10:7100/` で接続できる

## OpenSTF 使用中にインストールしたアプリが消えてしまう問題
OpenSTF に繋がっている Android 端末にアプリをインストールしても、**使用終了するとアプリが消えてしまう**。セキュリティ的には良いんだけど、少人数で使う場合、使う度に何度も同じアプリをインストールしなければならなくて、少し面倒。なので、

### インストールしたアプリを消さない設定で OpenSTF を実行
```bash:terminal
# 以下のIPアドレスは例で、実際はインストールしたMacのIPアドレスを指定
$ stf local --no-cleanup --public-ip 192.168.1.10
```
- `--public-ip` 以降は、**STF を実行している Mac の IPアドレス** を指定

## OpenSTF の動作が遅いので、少しでも速くしたい…！
OpenSTF の動作速度を決める最大の要因は、画像の転送速度＝画像のストリーミング速度。動かしているサーバ（今回の場合はMac）のスペックは変えられないとして、その他、設定等で改善できる可能性について。

### Wi-Fi ではなく、有線LAN にするべし
そういうことです。ノートでも有線がオススメ。

### スクリーンキャプチャの画質を落として転送量を減らす
```bash:terminal
# 以下のように環境変数を設定してから、STF を起動する
$ export SCREEN_JPEG_QUALITY=50
```
- 上記の `50` は画質で、デフォルトは `80`(？)
- 少しブロックノイズが気になるが、転送データ量が減るので動作速度が改善する


以上です。

## 補足：Android 10 対応版（DeviceFarmer版）への移行について
openstf 版の最終バージョンは `3.4.1` で、このバージョンは **Android 10 に対応していない** 。

2020年7月(？)、OpenSTF プロジェクトの開発は **openstf から DeviceFarmer に移行** しており、Android 10 に対応したバージョン `3.4.3` 以降は DeviceFarmer 版をインストールする必要がある。

なお、**openstf 版と DeviceFarmer 版は混在できない** ので、旧 stf を削除して新たにインストールする。

```bash:terminal
# 旧 openstf 版を削除
$ npm uninstall -g stf

# DeviceFarmer 版をインストール
$ npm install -g @devicefarmer/stf
```
- インストール後に `stf --version` と打って、`3.4.3` 以降のバージョンが表示されればOK
- 使用方法や挙動に違いはない

##### 以下はメモ：
>・ 一度 STFが起動できなくなったことがあり、ログを見ていると起動時の設定データ取得で失敗しているようだったので、rethinkdb を停止 ⇒ rethinkdb 実行ディレクトリに出来たデータ rethinkdb_data/ を削除（実際はリネームしてbackup）してから rethinkdb を再起動したところ、STFが正常に起動した
>・↑を行うと、なぜかスマホのアイコンやサムネイル画像が表示されなくなったので、パス指定しているであろうファイル `device-icons.js` を探して、パス指定を以下に書き換えたところ正常に戻った。
>`pathutil.root('node_modules/@devicefarmer/stf-device-db/dist')`
 


## 参考
- [OSSなリモートスマホサービス（STF）が素敵すぎる](https://qiita.com/tabbyz/items/5f6cec37e1d525a8e4d5)
- [macへのnodebrewを使ったnode.jsの５分間インストール](https://qiita.com/undrthemt/items/4ade6df1fe94107a45a6)
- [Android端末の開発者モードをONにする方法](https://qiita.com/knakamigawa/items/5b8bd2793920b517bf25)