本文へスキップ

AI エージェントがシミュレータのカメラ、キーチェーン、通信まで操作できるようにした

📋目次

はじめに

sim-use のようなツールのおかげで、Claude Code は iOS シミュレータの画面をタップしたりスワイプしたりできるようになりました。

ただし、画面には映らない領域が残っています。カメラが受け取る映像、キーチェーンに保存された値、アプリが実際に送受信している通信の中身です。これらを作り出したり書き換えたりする操作は、これまで人間が GUI を操作する以外に方法がありませんでした。

AppForceps と Mimicry の CLI に、この領域を操作できるコマンドを用意しました。カメラとキーチェーンは AppForceps、通信は Mimicry が担当します。

カメラの映像を差し替える

AppForceps の camera set は、画像ファイルや動画ファイルをシミュレータのカメラ入力として注入します。

appforceps camera set --device sim:<UDID> imagefile:/path/to/scene.png --yes --json
{"data":{"source":{"kind":"imageFile","label":"scene.png","path":"/path/to/scene.png","width":1440,"height":1080,"fps":10}},"ok":true}

差し替えは即座に反映されます。アプリがカメラを開いた瞬間、次のフレームからこの画像が渡ります。バーコードやQRコードを読み取るフロー、顔認識に失敗したときのエラーハンドリングなど、実物のカメラでは再現しづらい場面があります。任意の静止画や動画で試せます。

キーチェーンの中身を読み書きする

AppForceps の keychain list / keychain set は、シミュレータの Keychain に保存された項目を読み書きします。

appforceps keychain list --device sim:<UDID> --app <BUNDLE_ID> --json
{
  "data": {
    "items": [
      {
        "account": "probe-user",
        "service": "com.appforceps.probe.service",
        "class": "genp",
        "data": "Y3JlYXRlZA==",
        "dataLen": 7
      }
    ]
  },
  "ok": true
}

data は base64 でエンコードされた値です。書き換えは set で行います。

DATA=$(echo -n "expired-token" | base64)
appforceps keychain set --device sim:<UDID> --app <BUNDLE_ID> \
  --class genp --account probe-user --service com.appforceps.probe.service \
  --data "$DATA" --yes --json

GUI からも同じ項目を確認できます。

AppForceps の Keychain パネルに probe-user と probe-inet の 2 項目が一覧表示されている

トークンの有効期限切れやアカウント切り替え直後の不整合状態は、Keychain の値を直接書き換えないと作れません。アプリの UI を経由せずに再現できます。

サンドボックス内のファイルを直接操作する

Keychain 以外にも、AppForceps はアプリのサンドボックス内にあるファイルを直接読み書きできます。kv は plist や SharedPreferences のような構造化ファイルの1キーを、files はファイル単位で扱います。

appforceps kv delete --device sim:<UDID> --app <BUNDLE_ID> \
  Library/Preferences/<BUNDLE_ID>.plist recentSearches --yes --json

たとえば UserDefaults に保存された検索履歴のキーを消せば、初回起動時の「検索履歴なし」の画面をいつでも再現できます。ファイル自体を消したい場合は files rm を使います。UI から一つずつ削除する操作を再現しなくても、CLI 一発で同じ状態に戻せます。

保存済みのディープリンクと通知を一覧する

AppForceps の GUI には「保存済みアクション」機能があります。よく使うディープリンク URL や push payload を登録しておくと、ワンクリックで送れます。この一覧を CLI からも取得できるようにしました。

appforceps link list --app <BUNDLE_ID> --json
{"data":{"presets":[{"id":"...","name":"TODO詳細を開く","bundleId":"<BUNDLE_ID>","url":"todomemo://todo?id=42"}]}}
appforceps push list --app <BUNDLE_ID> --json

登録済みのプリセットは、そのまま link openpush send に渡して実行できます。

appforceps push send --device sim:<UDID> --app <BUNDLE_ID> \
  --payload '{"aps":{"alert":{"title":"TODO リマインダー","body":"「買い物リストを作る」の期限が近づいています"}}}' --json

シミュレータ側に通知バナーがそのまま届きます。

シミュレータの画面上部に「TODO リマインダー」という通知バナーが表示されている

link open で送ったディープリンクも、アプリ側で受信したことを確認できます。

アプリのデバッグ画面に、受信した Deep Link の URL と直近の Push のタイトルが表示されている

人間が GUI で登録したプリセットを、Claude Code がそのまま再利用して検証を回せます。

通信をキャプチャしてレスポンスを差し替える

Mimicry の CLI は、シミュレータをプロキシに向けて通信を捕捉し、レスポンスを差し替えるところまでを一つの流れとして扱います。

mimicry setup device sim:<UDID> --json

これでシミュレータの通信が Mimicry を経由するようになります。アプリを操作すると、その通信が logs に記録されます。

mimicry logs --limit 5 --json
{"data":{"results":[{"id":"c140372d-...","method":"GET","url":"http://ip-api.com/json","status":200}]}}

ログの ID を起点に、レスポンスをエラーへ差し替えます。

mimicry rule set --from-log c140372d-... --status 503 \
  --body '{"error":"service_unavailable"}' \
  --header 'Content-Type: application/json' --json

rule set が返った時点でルールは反映済みです。同じリクエストをもう一度送ると、503 とそのエラーボディがそのまま返ってきます。

HTTP/1.1 503 Service Unavailable
Content-Type: application/json

{"error":"service_unavailable"}

サーバー側のエラーハンドリングを、実際にサーバーを落とさずに検証できます。

まとめ

これで Claude Code は「アプリを操作する」「カメラ映像やキーチェーンの値、サンドボックス内のファイル、通信のレスポンスを書き換える」「保存済みのディープリンクや通知を再現する」「再操作して検証する」という一連の作業を人間の手を借りずに完結できるようになりました。

AppForceps と Mimicry それぞれの CLI の全体像は、下記の参考リンクにまとめています。よければ使ってみてください。

参考リンク

この記事をシェア