本文へスキップ

CLI

概要

AppForceps には appforceps CLI ツールが同梱されており、ターミナルや AI エージェントから iOS Simulator / Android Emulator のアプリデータを検査・変更できます。コンテナ内のファイル、plist や SharedPreferences・Jetpack DataStore・SQLite の 1 key、プライバシー権限、ディープリンク、プッシュ通知、カメラソースまでを GUI を一切操作せずに扱えます。

インストール

Homebrew でインストール(推奨)

Homebrew でインストールした場合、CLI は自動的に PATH に追加されます。

brew install --cask kusumotoa/tap/appforceps

DMG から手動インストールした場合

CLI バイナリはアプリに同梱されています。以下のコマンドでシンボリックリンクを作成してパスを通します。

sudo ln -sf /Applications/AppForceps.app/Contents/MacOS/appforceps /usr/local/bin/appforceps

動作確認

appforceps --version

コマンド一覧

コマンド説明
appforceps assertcontainer 内の 1 key を期待値と比較する。テストや CI 向けで、実行が成功しても不一致は exitCode 1 で表す
appforceps snapshot createcontainer を named snapshot としてキャプチャして保存する
appforceps snapshot diff2 つの named snapshot を比較する
appforceps compare2 つのデバイス間で container を比較する
appforceps files ...container 内ファイルの list / read / write / rm / mkdir / info / summary
appforceps kv ...構造化 key-value(plist / Android SharedPreferences / Jetpack DataStore / SQLite)の list / get / set / delete
appforceps perm ...iOS(TCC)/ Android のアプリ権限の list / grant / revoke / reset。grant/revoke/reset は対象アプリを終了させる副作用がある
appforceps folders ...登録済みローカル参照フォルダの list / add / remove / rename--device / --app を取らない、ファイルシステムのみの操作)
appforceps link openディープリンクを開く
appforceps pushプッシュ通知を送る(simctl push / FCM をデバイス種別から自動選択)
appforceps devices ...デバイス一覧の表示、アプリの再起動(--device を省略すると booted 1 台を自動選択)
appforceps camera ...カメラソースの状態表示・一覧・差し替え(set は iOS / Android 両対応。iOS は AppForceps GUI 実行中のみ動作し即座に反映、Android は設定ファイルを書き換えるだけなのでエミュレータの再起動後に反映。--device は省略可)
appforceps docs ...バイナリに埋め込まれた実用ドキュメントの一覧・表示
appforceps init --client claudeClaude Code 向けの Agent Skill を書き出す
appforceps capabilitiesプラットフォーム × 機能の対応表を表示(読み取り専用、デバイスに触れない)
appforceps keychain ...iOS Simulator の Keychain の list / set / delete / undo(AppForceps GUI 実行中のみ動作。iOS Simulator 専用)
appforceps sqlite ...container 内 SQLite ファイルの tables / describe / select / query / update-cell / insert-row / delete-row(Core Data・Remote Config も同じ経路で扱える)
appforceps crash listiOS Simulator のクラッシュレポート(.ips)を新しい順に一覧表示(読み取り専用、iOS Simulator 専用)
appforceps cookies ...iOS Simulator の WKWebView Cookie の list / add / update / delete(デバイス単位で全アプリ共有のため --app は取らない)
appforceps replace ...container 全体、または container 内の 1 ファイルをローカルファイルで上書き(container / file。デバイス間・アプリ間の一括コピーに使う)
appforceps coredata refresh実行中アプリに CoreData / SwiftData をディスクから再読み込みさせる(AppForceps GUI 実行中のみ動作。iOS Simulator 専用)
appforceps realm ...Realm データベースの sources / schema / objects / export / update(読み取りも含め全操作が AppForceps GUI 実行中のみ動作。iOS Simulator 専用)
appforceps search1 つの container 内でファイル名・plist キー&値・SQLite テーブル名&セル値を検索(GUI の横断検索と異なり単一 container のみが対象)

すべてのコマンドは --json(1 行の JSON envelope で結果を返す。exit code 0〜7 と対応)を共通で持っています。破壊的な操作(files write / files rm / kv set / kv delete / perm grant / perm revoke / perm reset 等)はさらに --yes で実行を承認するか、--dry-run で変更計画だけを事前に確認できます。

kv: UserDefaults / SharedPreferences を確認・書き換える

典型的な流れは、対象の plist(または SharedPreferences / DataStore / SQLite)内の 1 key を kv get で確認し、--dry-run で変更内容を事前確認してから --yes で書き換える、という手順です。コマンドが返った時点で値は反映済みです。

# 現在の値を確認する
appforceps kv get --device sim:<udid> --app com.example.MyApp \
  Library/Preferences/com.example.MyApp.plist isPremium

# 書き換え前に変更内容を確認する(何も変更しない)
appforceps kv set --device sim:<udid> --app com.example.MyApp \
  Library/Preferences/com.example.MyApp.plist isPremium true --dry-run
# → update key isPremium: false -> true

# 承認して実際に書き換える
appforceps kv set --device sim:<udid> --app com.example.MyApp \
  Library/Preferences/com.example.MyApp.plist isPremium true --yes

権限を「未確認」の状態に戻してアプリを再起動すると、初回起動時の許可ダイアログや権限拒否時のエラーハンドリングを再現できます。権限変更はアプリを終了させることがあり、レスポンスの data.targetAppTerminated で実際に終了したかどうかを確認できます。

# 権限を未確認状態に戻す(iOS Simulator 専用。Android は revoke で代替)
appforceps perm reset --device sim:<udid> --app com.example.MyApp photos --yes --json
# → {"data":{"action":"reset","targetAppTerminated":false,...},"ok":true}

# アプリを再起動してオンボーディングを再現する
appforceps devices restart-app --device sim:<udid> --app com.example.MyApp --yes

assert / compare / snapshot: CI 向けの検証

assert は container 内の 1 key を期待値と比較するコマンドで、「実行は成功したが答えは No」という状態を ok: true のまま exitCode: 1 で表します(data.matched で判定)。exit code をそのまま CI のゲートに使えるため、他のコマンドより一段 CI 向けです。一方 compare(2 つのデバイス間の container を比較)と snapshot create / snapshot diff(同一デバイスの前後を named snapshot として比較)は、差分が見つかっても exit code は 0 のままです(exit 1 は比較そのものが実行できなかった場合)。差分の有無で CI を失敗させたい場合は、出力 JSON の summary を自前でチェックしてください。

# 1 key だけを CI で検証する(不一致なら exit code 1)
appforceps assert --device sim:<udid> --app com.example.MyApp \
  Library/Preferences/com.example.MyApp.plist isPremium --equals true --json

# 操作の前後で container 全体を named snapshot として比較する
appforceps snapshot create --device sim:<udid> --app com.example.MyApp --label before
# ...アプリを操作する...
appforceps snapshot create --device sim:<udid> --app com.example.MyApp --label after
appforceps snapshot diff --label-a before --label-b after --json

docs / init: 埋め込みドキュメントと AI ツール連携

バイナリに埋め込まれた実用ドキュメント(getting-started / output-contract / kv / permissions / camera / recipes など)を、デバイスにもアプリにも触れずに読めます。appforceps init --client claude を実行すると、Claude Code 向けの Agent Skill が ~/.claude/skills/appforceps/SKILL.md に書き出されます。この skill 自体はコマンド例を一切持たず、実行時に appforceps docs show へ誘導するだけの設計です。CLI のバージョンと skill の内容が乖離して陳腐化するのを防ぐためで、常に手元のバイナリと一致したドキュメントを参照できます。

appforceps docs list
appforceps docs show cli/getting-started

appforceps init --client claude
# → wrote ~/.claude/skills/appforceps/SKILL.md