Appiumをやめてsimctlに移行した話

こんにちは。QA（Quality assurance：品質管理）チームの佐藤です。

:::note warn
この記事は、[Supershipグループ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/supership)の1日目の記事になります。
:::

## TL;DR
- Appiumを使用して困ったこと
  - 実機iOSでの自動テストに支障  
- そもそも最近はそれほど複雑な操作を必要としていない
  - 自動テストのスクリプトを`simctl`で動作するように変更した

## はじめに
QAチームでは、以前から実機をPCから操作して動作確認を行うタスクがあり、そのタスクにAppiumを利用してきました。当初は、SDKのサンプルアプリの動作確認が中心でしたが、最近は、表示される広告のチェックが中心となり、長時間テストを稼働させてログやスクリーンショットを取得することが重要視されるようになりました。そのため、ボタンが動作するかどうか、画面が切り替わるかといった事項は、それほど重要視されていません。

Appiumは、1.x系から2.x系へと進化し、仕様が大きく変わりました。また、実機端末のOSも毎年バージョンアップするため、これらのアップデートのたびに、必ずと言って良いほど、テストが動かなくなるという状況が発生しています。特に困ったのは、iOSの実機端末をリモート操作する際の不具合が毎回発生することでした。これは、Appleがセキュリティ強化のため、ユーザーがアクセスできる領域を制限していることが大きな要因と考えられます。

## シンプルにいきたい
Appiumを動作させるための環境構築は結構複雑で、いくつものツールをインストールしなければなりません。また、動作させる際も、Webriverにアクセスするためのサーバーを複数経由させる必要があります。うまく動作しない場合、原因の切り分けも結構手間です。

冒頭でも言及してますが、最近要求される機能としては、アプリの起動・スクリーンショットの取得・ログの取得くらいなもの（当初と違い、公開しているサンプルアプルではなく、起動するとボタンを押さずに自動で広告にアクセスし、終了すると再度広告にアクセスするという非公開のチェック専門のアプリで広告のクオリティを確認をしている）なので、Androidなどでは`ADB`コマンドを直接実行することで事足ります。

## devicectl/simctl
Appiumからの移行当初、iOSの実機でのテストをそのまま移植する予定でした。ですので、Appleが提供している`devicectl`という実機を操作するコマンドを使って実機を操作する方向で進めていましたが、アプリなどの起動までは可能でしたが、スクリーンショットの取得や端末操作などの機能はそもそも含まれていないことがわかり、上記機能が使える`simctl`（`devicectl`のシミュレータ版のようなもの）を使って移植することにしました。

## 実際に使用したコマンド抜粋
特定の条件などがあってうまく動作しない場合もあると思いますが、実際に使用したコマンド抜粋して提示します。
（Xcodeインストール時にsimctlも同時にセットアップされています。`xcrun simctl`として、`usage`が出力されれば環境準備はOKです。）

参考までに、以下が手元の機材のバージョンです。
- MacOS 15.1.1
- Xcode 16.1

### システムに登録されているiPhoneシミュレータを確認
Xcodeからアプリをビルドして動かすため、複数あるシミュレータのうち、ビルドしているシミュレータをUUIDで特定してコマンドを送る必要があります。
```zsh
% xcrun simctl list devices
== Devices ==
-- iOS 17.5 --
    iPhone SE (3rd generation) (xxxxx-xxxxx-xxxxxxx-xxxxxx) (Shutdown) 
    iPhone15（17.5） (xxxxx-xxxxx-xxxxxxx-xxxxxxB) (Shutdown) 
-- iOS 18.1 --
    iPhone SE (3rd generation) (xxxxx-xxxxx-xxxxxxx-xxxxxx) (Shutdown) 
    iPhone 16 Pro (xxxxx-xxxxx-xxxxxxx-xxxxxx) (Shutdown) 
    iPhone 16 Pro Max (xxxxx-xxxxx-xxxxxxx-xxxxxx) (Shutdown) 
```
`xxxxx-xxxxx-xxxxxxx-xxxxxx`の部分をメモっておきます。
### シミュレータを起動する
シミュレータの起動は、`simctl`ではなく、システムの`open`コマンドを使い以下のようにします。
```zsh
% open -a "Simulator.app" --args -CurrentDeviceUDID xxxxx-xxxxx-xxxxxxx-xxxxxx
```
シミュレータが起動しましたでしょうか？

### シミュレータからログを取る
下記のコマンドで、シミュレータからログを取得できます。
```zsh
% xcrun simctl spawn booted log stream
```
実際には、`grep`コマンドでフィルタした上、ファイルに出力していろいろな処理をしています。
また、リアルタイムでログを追うために、`grep`に`--line-buffered`オプションなども付加して使っています。

### シミュレータの中のアプリを起動する
下記のように、シミュレータの`UUID`とビルドしたアプリの`ID`を指定して、シミュレータの中のアプリを起動します。
```zsh
% xcrun simctl launch xxxxx-xxxxx-xxxxxxx-xxxxxx com.xxxxxx.xxxx 
```
アプリを終了する場合は、`launch`のところが、`terminate`となります。
### スクリーンショットを取得する
ログなどでアプリの動作を把握して、欲しいタイミングで以下のようにスクリーンショットを取得します。
```zsh
% xcrun simctl io booted screenshot --type png test.png
```

### その他備考
`xcrun simctl install`や`xcrun simctl uninstall`などでビルドしたアプリのインストール/アンインストールをできるのですが、うまく動作しないため、Xcodeからビルドした際、シミュレータ内に残ったものをそのまま使用しています（ビルド時の証明書とかそういう系の設定の問題と思われる）。

`xcrun simctl`を`xcrun devicectl`とすることで、実機のコントロールができます。含まれるサブコマンドに多少の誤差があるので、そのままコードの流用は難しいですが。

私がお出かけ用にPDFへと編集したコマンドのヘルプを共有しますので、ちょっとバージョンが古くなっていますが、ざっと目を通していだだければ、上記以外にも多くの機能があることを関していただけると思います。

- [simctl リファレンス](https://acrobat.adobe.com/id/urn:aaid:sc:AP:8a47449e-96c7-4442-af3e-26545e4828f3)
- [devicectl リファレンス](https://acrobat.adobe.com/id/urn:aaid:sc:AP:34ce4fbb-60b7-4677-8059-cc30666e033d)

## おわりに
この作業をしたのは、新しいiOSがbetaの時期でした。新機能のニュースなどで`iPhoneミラーリング`がアナウンスされていたので、`devicectl`に機能が追加されるなどするのかな‥と思ったのですが、まだ確認していません。そのうち確認したいです。

また、今回のケースではアプリの起動、スクリーンショット取得、ログの取得の条件を満たせばよかったため、ボタンのクリックやスワイプなどの操作を含む動作確認などが要求される場合、やっぱりAppiumやSeleniumが必要‥となる可能性もありますし、AppumのiOS実機の検証周りのアップデートが今後されるでしょうから、それまで待つというのも選択肢としてアリなのではないかと思います。

:::note
**最後に宣伝です。**

Supershipではプロダクト開発やサービス開発に関わる人を絶賛募集しております。
ご興味がある方は以下リンクよりご確認ください。
[Supership 採用サイト](https://supership.jp/recruit/)
是非ともよろしくお願いします。
:::