ブラウザで iOS/Android シミュレーター QA 環境を作るまで — MSE を捨てた理由
(github.com/jo-duchan)モバイルアプリを作るチームなら、一度は経験したことがあるはずです。テスト端末は常に足りず、OS バージョンを幅広くカバーするのも簡単ではありません。かといってシミュレーターを使おうとすると Xcode や Android Studio が必要で、企画者・デザイナー・サーバー開発者のようにモバイル開発環境がないチームメンバーは、そもそも入り口でつまずいてしまいます。"サンドボックスにデプロイされたものを一度見たいんですが、アプリはどうやって入れるんですか?" といった依頼が来るたびに、モバイル開発者が手を止めてサポートしなければなりません。
Appetize・BrowserStack も検討はしました。ただ、(1) チーム規模が大きくなるほど急速に上がる料金と、(2) アプリのバイナリが外部クラウドにアップロードされる構造が気になり、余っていた Mac で自前で作ることにしました。
そうしてできたのが tapflow です — チームの誰でもブラウザから iOS シミュレーター・Android エミュレーターでモバイル QA ができる、オープンソースのセルフホスティングツールです。利用者側は何もインストールする必要がなく、ブラウザを開くだけで使えます。さらにセルフホスティングなので、アプリデータもチームの Mac の外に出ません。
作る中で最も難しかったのは機能ではなく、レイテンシーでした。画面がほんの半拍でも遅れると、みんな一度スクロールしてみて閉じてしまうからです。しかもシミュレーター画面は agent → relay → ブラウザ render パイプを通るため、各区間で遅延が積み上がります。この経路の遅延を減らしながら整理した内容は次の通りです:
- MSE を捨てました。
<video>メディアバッファが構造的に約 235ms を載せてしまうため、WebCodecs(セキュアコンテキスト)/WASM tinyh264(平文 HTTP) の 2-tier に置き換えました。SPS に reorder=0 を宣言し、decode→present を 267ms→2.5ms に短縮。(localhost 単一クロック測定) - デコーダー 4 種類(tinyh264/FFmpeg/openh264)をベンチマークしたものの、結局 tinyh264 を維持 — FFmpeg は静止画でしか勝てず、スクロールでは毎回負けるうえ、バンドルは 11 倍でした。ボトルネックはデコーダーではなく、負荷と転送でした。
- Android の SW エンコードを Mac の HW エンコードで改善しました。 エミュレーターには HW H.264 エンコーダーがないため、scrcpy は SW エンコーダーに制約されます(22–29fps)。raw フレームを gRPC でホストに出し、Mac VideoToolbox でエンコード → 59fps(ダウンスケール)。(デフォルトは 30fps キャプチャ、実機は scrcpy を維持)
- WDA なしで iOS タッチ(CoreSimulator HID API を直接注入)、Mac Agent はリレーへのアウトバウンド接続のみ(インバウンドのファイアウォールルール不要)。
制限事項: iOS エージェントは macOS 専用、タッチは Private API のため macOS アップデートで壊れる可能性あり、まだ v0.x、実機未対応。
npm install -g tapflow
tapflow start # → http://localhost:4000
MIT ライセンス
GitHub: https://github.com/jo-duchan/tapflow
ドキュメント: https://www.tapflow.dev
シミュレーターへのアクセス問題を経験したことがある方、あるいは低レイテンシーストリーミングや Private API へのアプローチについての意見を歓迎します。
まだコメントはありません。