mcpField
I
iphone-use

iphone-use

github.com/leeguooooo生産性39342 回インストール今日更新
リポジトリ

iphone-use について

iphone-use は、独自の XCTest ランナーで実機 iPhone を操作するスキルです。Mac の画面やカーソルには触れず、アプリ操作、保存済みフローの実行、操作の検証を支援します。

主な機能

  1. 01XCTest による実機 iPhone の操作
  2. 02保存済みフローと Jev の端末タスク実行
  3. 03UI 操作の一括実行と結果検証
  4. 04画面要素とホーム画面レイアウトの確認
  5. 05端末の占有状態と再接続の管理

活用シーン

  1. 01iPhone アプリで複数手順のタスクを自動化
  2. 02アプリの状態確認と表示中のコントロール操作
  3. 03繰り返し使うフローの再利用や作成

MCP 対応

`phone_*` ツールを備えた MCP サーバーが付属し、端末の読み取りや操作、フロー実行、セッション管理を行います。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/leeguooooo/iphone-use --skill iphone-use

インストール後、Claude Code で/iphone-useを入力して読み込まれたか確認します。

詳細

iphone-use — 実機の iPhone を操作

iphone-use デーモンは、独自の XCTest デバイスランナーを通じて実機の iPhone を操作します。このランナーは v0.14.0 で WebDriverAgent に置き換わりました。iPhone Mirroring は使用しません。HTTP インターフェースは WebDriverAgent と互換性があります(/wda/... ルート)。Mac の画面やカーソルには一切触れません。以下の HTTP API または同梱の MCP サーバー(phone_* ツール)を使用してください。どちらも同じ手順で操作できます。詳細についてはリファレンスをご覧ください。curl -s -H "$AUTH" "$HOST/agent/reference" で、実行中のデーモンに対応する内容を取得できます(以下の各セクション名は見出しに対応しています。また、docs/agent-reference.md もご覧ください)。

HOST="${IPHONE_USE_URL:-http://127.0.0.1:44321}"
AUTH="Authorization: Bearer $IPHONE_USE_TOKEN"   # daemon password or IPHONE_USE_AGENT_TOKEN
MUTATION="X-Phone-Control: 1"                      # required on every state-changing POST
OWNER="X-Phone-Owner: <your-session-name>"          # MCP sends this for you
curl -s -H "$AUTH" "$HOST/agent/status"             # probe first; on failure stop and report

ループ

  1. 確認します。 ユーザーが電話を指定した場合、または複数の電話がインストールされている場合は、まず phone_instances を使用し、その後、すべての MCP 読み取り/操作でその instance を渡します。 instance を省略すると、設定済みデーモンのみが報告され、すべての電話は報告されません。 GET /agent/status / phone_status。画面の読み取りと UI 入力には drivable:true が必要です。それ以外の場合は hint を報告し、これらの操作を中止します。 ペアリング済みのメタデータ読み取り(phone_home_layout、phone_apps)とキャッシュ済みの機能検出には、 Runner の実行は必要ありません。再接続したりホーム画面を開いたりせずに使用し、 プライベート保留による拒否があれば従います。再接続(phone_reconnect / POST /agent/mode {"mode":"agent"})は、 ユーザーの現在のタスクで電話が必要な場合に限り、一度だけ行います。ヘルスチェックのためには行いません。 Runner を起動するたびに、オペレーターがパスコードを入力しなければならない場合があります。 owner が別のセッションであれば、操作しないでください。→ 参考:電話の状態と復旧

  2. まず保存済みのフローを探します。 アプリに入ると、launch_app の応答、 または新しく入ったアプリでの最初の /agent/elements 読み取りに、そのアプリの保存済みフローを一覧表示する registry ブロックが含まれます。タスクに合うフローがあれば、 phone_flow_run で実行します。数十回の呼び出しが1回で済み、スクリーンショットも不要です。 phone_flow_list / iphone-use-mcp flow list --app <bundle> ですべてを表示できます。 実行前に risk と compat を確認してください。→ 参考:フロー

    "$HOME/Applications/iPhoneUse.app/Contents/MacOS/iphone-use-mcp" flow run system/spotlight-search --input query=Health
    
  3. フローがない場合は、明確な目標を Jev に渡します。 phone_jev_run / iphone-use-mcp jev run --goal "…" [--app <bundle>] は、高速なオンデバイスエージェントを実行します(TypeSafe の Jev が各ステップを選択し、1ステップ約1~2秒で、モデルのターンはありません)。ステップ履歴とともに done / blocked を返します。送信、支払い、削除を行う目標は、先にユーザーの確認を取ってください。最後の画面は自分で確認します。

  4. それ以外の場合は、タップではなくまとめて操作します。 呼び出しのたびに1ターンを丸ごと消費し、 電話の処理には約0.5秒かかります。launch_app でアプリを開き、GET /agent/elements を一度読み取ります。その後、すでに把握している操作をすべて1つのバッチとして送信します(POST /agent/actions / phone_run_steps、最大24ステップ。画面が変わるたびに wait_for を指定)。observe:true(MCP のデフォルト)を指定すると、バッチ終了時の画面が応答に含まれるため、読み取りを追加せずに次のバッチを判断できます。バッチの間に1分以上考える場合は、phone_hold を使うと Runner が解放されません。単独のタップ(要素+スナップショット、一意のラベル、ロケーター)は、まだ読み取っていない画面を調べるためのものです。3回連続すると、デーモンがその旨を知らせます(batch_hint)。

  5. 各ステップを後続条件と照合して確認します。 MCP の操作ツールはデフォルトで画面を確認し(HTTP:?return=delta)、同じ呼び出しで確定した変更を返します。確定後の画面もキャプチャされ、phone_screenshot を呼び出せばすぐに取得できます。テキストだけでは不十分な場合に限り、画面を確認してください。ok:true は操作が送信されたことを意味するだけで、何かが達成されたという意味ではありません。 → 参考:結果の読み取り

  6. フローとして保存するか尋ねます。 応答に flow_suggestion が含まれている場合、またはフローで対応できない複数ステップのタスクを完了した場合は、フローとして保存するかユーザーに尋ねてください。同意があった場合に限り、ドラフトを取得し(phone_flow_draft(save_as=…) / flow draft --out … / GET /agent/flow/draft)、todo リストを修正して検証し、ファイルを一度実行します。公開すると公開 PR が作成されるため、phone_flow_publish(confirm=true) の前にもう一度確認してください。→ 参考:フローの保存

タスクが完了したら、電話を解放します:phone_release_owner / POST /agent/owner {"release":true}。応答に agent_focus が含まれていた場合、セッション中は電話が「おやすみモード」になっています。そのことをユーザーに伝えてください。解放すると、おやすみモードは解除されます。

基本操作

内容HTTP /agent/input typeMCPFlow / バッチステップ kind
アプリのバンドル ID を検索するGET /agent/apps?query=微信phone_apps—
アプリを開くlaunch_app bundle(組み込みアプリの場合は name、または app:任意のアプリの正確な名前。候補が複数ある場合は拒否されます)phone_run_steps ステップlaunch_app(bundle または app)
ホームページ、Dock、フォルダを読み取るGET /agent/home-layout?page=0(すべて表示する場合は page を省略)phone_home_layout(page?)—
画面を読み取るGET /agent/elementsphone_elementswait_for(application、present、absent)
要素をタップするtap + element + snapshotphone_tap_elementtap_locator(永続的)
一意のラベルをタップするtap + labelphone_tap_labeltap_label
ロケーターでタップするtap_locator + locatorphone_run_steps ステップtap_locator
座標をタップするtap + x,yphone_taptap
テキストを入力するtext(フォーカス中のフィールドに入力。最大 20000 文字。text_partially_typed の場合は clear:false を指定して remaining_text のみ送信)phone_typetype(input は実行時の値を指定)
キーkey return…phone_keykey
ホーム/Spotlightshortcutphone_shortcutshortcut
スクロールscroll dy(80 ≈ 画面の 15%、400 ≈ 75%)phone_scroll(x、y、dx、dy が必須)scroll(MCP バッチでは x、y、dx、dy が必須)
システムアラートalert button / actionphone_run_steps ステップalert
アプリからログインを求められた場合POST /agent/login(iphone-use auth login --bwu)phone_login—
スイッチ/スライダーperform toggle / adjustphone_run_steps の perform ステップ(要素 + スナップショット)—

エッジでホバーする必要があるドラッグでは、drag ステップで x1/y1/x2/y2 の代わりに points: [{x, y, dwell_ms}, …] を使用できます。現在の画面から 2~16 個のポイントを指定します。 各滞留中も同じ指を押し続けます。duration_ms はセグメントごとの移動時間で、保持・移動・滞留の合計は 10 秒以下です。 Flow の下書きにはパス全体が保持されます。次の操作に進む前に、終了画面を確認してください。

スワイプ、ドラッグ、ピッカー、set_value、スクロールの各バリエーションを含むすべての操作は、リファレンスに記載されています:操作カタログ。

HTTP /agent/input では、省略されたスクロールアンカーと dx にデフォルト値が設定されます。 MCP の phone_scroll と phone_run_steps のスクロールステップでは、4 つのフィールドすべてが必須です。 現在の画面で、スクロール対象領域内の適切な位置に正規化された x/y を指定してください。 その画面で確認した中央アンカーの場合、MCP バッチの形式は次のとおりです。

{"steps":[{"kind":"scroll","x":0.5,"y":0.5,"dx":0.0,"dy":80.0}]}
curl -s -H "$AUTH" -H "$MUTATION" -H "$OWNER" -X POST "$HOST/agent/input" \
  -d '{"type":"launch_app","bundle":"com.apple.Health"}'        # response may carry `registry`
curl -s -m 40 -H "$AUTH" "$HOST/agent/elements"                  # give it ≥40s
curl -s -H "$AUTH" -H "$MUTATION" -H "$OWNER" -X POST "$HOST/agent/input?return=delta" \
  -d '{"type":"tap","element":3,"snapshot":"<from that read>"}'
curl -s -H "$AUTH" -H "$MUTATION" -H "$OWNER" -X POST "$HOST/agent/actions" -d '{"steps":[
  {"kind":"action","action":{"type":"tap_locator","locator":{"label":"资料","kind":"Button"}}},
  {"kind":"wait_for","expect":{"present":[{"label":"导出所有健康数据"}]},"timeout_ms":8000}]}'
しないこと → 代わりにすること
しないこと代わりにすること
スクリーンショットから推測した座標をタップするphone_elements を読み取り、要素とスナップショット、またはラベルでタップする
各ステップの後にスクリーンショットを撮るobserve:true / ?return=delta で変更を確認する
次のステップが見えているのに、呼び出しごとに1回タップするwait_for を使って、phone_run_steps / /agent/actions でまとめて実行する
秒数を固定して sleep するpresent / absent / application を指定して wait_for する
システムアラートのボタンをタップするalert アクション(button または action)を使う
スイッチやスライダーをタップするperform の toggle / adjust を使う
outcome_unknown または retry_safe:false の後に再送するまず画面を読み取る。すでにスマートフォン側で操作が実行されている場合があります
no_progress となったアクションを繰り返す画面を読み直してから、別のコントロールを使うか wait_for する
状態確認のために再接続するphone_status を使い、タスクでスマートフォンが必要な場合にのみ再接続する
フォーカスを確認せずに入力するフォアグラウンドアプリとフォーカスされているフィールドを確認してから入力する
見つからなかったラベルを繰り返すエラーが提示する「もしかして」のラベルを使うか、読み直す

タスクのメトリクス:iphone-use metrics / GET /agent/metrics が数えるのは、モデルのターン数ではなく HTTP 呼び出し数です。1つのタスクを正確に数えるには、phone_run_start / phone_run_end で囲みます(HTTP:POST /agent/run)。GET /agent/elements?scope=app(または interactive、focused、changed&since=…)は、同じ読み取り結果のより小さなビューを返します。?image=auto は、ツリーが使えない場合にのみスクリーンショットを追加します。MCP の画面テキストには、最大200行、行テキストは最大32 KiBが含まれます。省略された行があると表示された場合は、query / limit を指定して phone_elements の範囲を絞り込みます。対象が省略されていても、その対象が存在しないとは証明されず、切り詰められたリストも完全であるとは証明されません。表示された #N はスナップショットとともに使用してください。これは元の全ツリーでのインデックスです。画面外または描画されていない行のうち、5ラベルの要約に含まれないものを調べるには、include_hidden: true を指定して phone_elements を呼び出します(テキスト量の上限に収めるため、query / limit と組み合わせてください)。これらの行には hidden と表示されます。操作する前に、スクロールして表示し、もう一度読み取ってください。 → 参照:タスクのメトリクス、実行、アドバイス

ホーム画面の整理:フォルダーを開いたりページをスワイプしたりする前に、phone_home_layout を使用してください。保存されたページ、Dock、フォルダーの内容、ウィジェットスタックを、アイコンを移動せずに読み取ります。ページ/行/列のインデックスは0始まりです。ページには非表示のページやFocusフィルターが適用されたページも含まれるため、ページのインデックスは表示中のページコントロールの番号とは異なります。位置はアイコンの順序とグリッドの指標から導出されます。サイズが不明な場合、位置は null となり、positions_complete:false になります。これらはピクセル座標ではなく、レイアウトを復元してよいことを意味するものでもありません。ドロップ後に読み直し、ジェスチャーにはライブ要素を使用してください。

フローは、保存されたこれらのステップにすぎません

{
  "version": 1,
  "name": "New note",
  "app": "com.apple.mobilenotes",
  "risk": "navigation",
  "locale": "zh-CN",
  "inputs": { "body": { "type": "string", "description": "note text" } },
  "steps": [
    { "kind": "launch_app", "bundle": "com.apple.mobilenotes" },
    { "kind": "wait_for", "expect": { "application": "备忘录" }, "timeout_ms": 15000 },
    { "kind": "tap_locator", "locator": { "label": "新建备忘录", "kind": "Button" } },
    { "kind": "type", "input": "body" }
  ]
}

フィールドの全リスト、互換性の値、公開とレポートの手順については、参照:フロー をご覧ください。

厳守事項

  1. retry_safe:false または outcome_unknown の場合は再送しないでください。 すでにスマートフォンで操作が実行されている可能性があります。まず画面を読み取り、テキストの再入力、送信、支払い、削除を確認せずに行わないでください。失敗したフローにも同じルールが適用されます。
  2. risk: side_effect および破壊的なタップには、対象と入力を明示したユーザーの許可(confirm=true / --confirm)が必要です。 支払い画面や2FA画面を無人で操作しないでください。
  3. テキストは、フォーカスがあるフィールドに入力されます。 誰かがチャット中の場合、入力した言葉はその人のメッセージに入ります。まず前面のアプリとフォーカスのあるフィールドを確認してください。チャットアプリでは Return で送信され、入力テキスト内の \n も Return になります。ユーザーが改行を希望していない限り、1行だけ送信してください。→ 参考:チャットアプリ:複数行のメッセージ
  4. システムアラートには alert アクションが必要です。 アラートのボタンをタップすると ACK されますが、多くの場合、何も起こりません。スイッチには perform toggle が必要です。どちらの場合も、新しい value を確認してください。
  5. スマートフォン1台につきセッションは1つです。 X-Phone-Owner を送信してください。409 phone_owned が返された場合は待機し、他のセッションが放棄されたとユーザーが明示しない限り、引き継がないでください。完了したら、リースを解放してください。
  6. ログインには phone_login / iphone-use auth login --bwu のみを使用してください。 デーモン内でユーザー自身の保管庫エントリーを入力します。パスワードやコードを自分で尋ねたり、入力したり、繰り返したりしないでください。新規登録、パスワード変更、支払いも行わないでください。Face ID、PIN、コード、またはログイン phone_login でログインを完了できない場合は、停止し、phone_hold(secs, private=true) を取得して、その間に画面が読み取られないようにします。ホストの質問ツールを使ってユーザーに尋ね(ツールがない場合、または現在利用できない場合はプレーンテキストで尋ねます)、返答を待ってからホールドを解除し、画面を読み直してください。→ 参考:本人がサインインする必要がある場合
  7. 保存や公開を決めるのはユーザーです。 フローを保存する前に確認し、公開またはイシューを登録する前にも再度確認してください。いずれもユーザーの GitHub アカウントを使用します。

タスクで必要なファイルは AirDrop 経由で Mac に転送され、~/Downloads に保存されます(参考:スマートフォンから Mac にファイルを転送する)。

画面が変わった場合(app_changed、バナー、スマートフォンの操作など)は、停止して画面を読み直してから、以前の手順を続けてください。スキルの説明とライブ API の内容が異なる場合は、スキルが古くなっている可能性があります。参考:アップグレード。iphone-use 自体に不具合や分かりにくい点がある場合は、イシューの登録を提案してください(参考:イシューの登録)。

複数指での長押しと復旧可能な観察

同時に長押しするには、phone_run_steps で {"kind":"multi_longpress","points":[{"x":0.3,"y":0.5},{"x":0.5,"y":0.5},{"x":0.7,"y":0.5}],"duration_ms":1500} を使用してください。 2~5個の異なる正規化座標で指の本数を指定します。長押し時間は1~10000 ms(既定値は1000)です。HTTP アクションの本文では type:"multi_longpress" を使用し、保存済みフローでは kind を使用します。通常の longpress に fingers:3 を指定してはいけません。アプリ固有のジェスチャー認識は実機で確認する必要があります。

Jev は、HTTP 504 runner_source_timeout が発生した場合に限り、サーバー指定の1~60秒の retry_after_secs 後に、観察を1回だけ再試行します。直前のアクションを再実行することはありません。アクション後の観察から復旧できない場合は、status:"blocked"、history、last_successful_action を調べてから、次の操作に進む前に読み直してください。

複数のインストール済みスマートフォン

読み取り専用のローカルインスタンス一覧には phone_instances を使用してください。他の各 phone_* 呼び出しでは instance(例:i13、default)を渡し、そのデーモンを指定します。読み取りとアクションで同じ値を使い続けてください。instance を省略すると、MCP サーバーの起動時設定が使用されます。対象が変更されることはなく、利用できないインスタンスが別のスマートフォンにフォールバックすることもありません。インスタンスを切り替えるためにトークンを読み取ったり、HTTP リクエストを手書きしたりしないでください。検出によって再接続が行われることはありません。通常の所有権、プライバシー、ロック、スマートフォン終了/人への引き継ぎのルールは引き続き適用されます。実行時の選択では、インストール済みのローカル LaunchAgent がサポートされます。シミュレーターのみのレコードは別に扱われます。

コメント