codai docs
Aplicații

Controlează un iPhone de la distanță

Vezi ecranul unui iPhone în timp real și controlează-l din hub, din aplicația Android sau din orice agent codai, prin bridge-ul codai pentru iPhone — fără jailbreak, doar în același cont.

Bridge-ul codai pentru iPhone rulează pe PC-ul Windows cu care e asociat iPhone-ul și controlează telefonul prin USB sau Wi-Fi (pymobiledevice3, imaginea de dezvoltator, unelte fără WebDriverAgent). Cu accesul la distanță pornit, bridge-ul se conectează și singur la codai — fără aplicația desktop, fără port de intrare — așa că poți controla telefonul de oriunde:

  • Controlul trece prin releul de host-uri: bridge-ul este un host cu capabilitățile iphone și video, iar orice client apelează POST /v1/hosts/{deviceId}/exec cu operația iphone.
  • Ecranul live trece prin codai-relay: bridge-ul este daemonul propriului mediu „iPhone <nume>” și transmite ecranul ca video HEVC.
   hub / Android / agent            gateway + relay codai                PC cu bridge-ul           iPhone
   ─────────────────────           ─────────────────────               ───────────────           ──────
   POST /v1/hosts/:dev/exec  ───▶  releul de host-uri (SSE)     ───▶  același cod de unelte ─▶  atinge, scrie,
        { op: 'iphone', … }                                            ca MCP-ul local           deschide app…
   vizualizator video (WS)   ◀───  stream relay de tip `video`  ◀───  DisplayService HEVC   ◀─  ecran

Configurează bridge-ul

Instalează mai întâi bridge-ul (vezi apps/iphone-bridge/README.md; vine împreună cu MCP-ul desktop codai-iphone). Apoi, o singură dată:

Dă-i o cheie API

Creează o cheie în hub (Chei) și păstreaz-o într-un fișier lângă control.json al bridge-ului — niciodată în configurație:

Set-Content -NoNewline "$env:LOCALAPPDATA\codai\iphone-bridge\api-key.txt" 'codai_…'
'{"relay": {"enabled": true, "api_key_file": "%LOCALAPPDATA%/codai/iphone-bridge/api-key.txt"}}' |
  Set-Content "$env:LOCALAPPDATA\codai\iphone-bridge\config.json"

Înrolează telefonul

& "$env:LOCALAPPDATA\codai\iphone-bridge\venv\Scripts\codai-iphone-bridge.exe" relay enroll

relay enroll creează (sau refolosește) proiectul „codai iPhone” și un mediu BYO „iPhone <nume>”, de care leagă id-ul stabil de dispozitiv al acestui telefon. Comanda e idempotentă; opțiuni --udid, --name, --base-url.

Pornește-l cu acces la distanță

Repornește bridge-ul sau rulează-l cu --relay (echivalent cu relay.enabled: true). Se înregistrează cu os=ios, caps=iphone,video și id-ul mediului și se reconectează cu backoff (1 → 30 s) la erori de rețea. O cheie respinsă sau un alt bridge care preia același mediu oprește partea de la distanță până la repornire.

Cheile din config.json, sub relay: enabled, api_key_file (altfel CODAI_API_KEY), base_url (implicit https://ai.codai.ro), relay_url (implicit: ce a întors gateway-ul la înrolare), allow_sensitive (implicit false) și video (implicit true; false = doar control).

Folosește-l

UndeCum
Hubhub.codai.ro/devices/iphone — iPhone-uri la distanță listează telefoanele online; deschide unul pentru ecranul live și comenzi (atingere, derulare, Home, butoane, tastare).
Aplicația AndroidSetări → Servere remote → iPhone: aceeași listă, un ecran live pe care atingi și tragi, plus butoanele Home / Înapoi / Blocare.
AgențiUneltele iphone_* din fiecare agent codai (desktop, Android, VS Code, headless): iphone_hosts, iphone_screen, iphone_screenshot, iphone_find, iphone_click, iphone_tap, iphone_swipe, iphone_type, iphone_key, iphone_button, iphone_home, iphone_open_app, iphone_open_url, iphone_list_apps, iphone_wait_for. Fiecare primește un host opțional (id de dispozitiv); implicit este singurul host online cu capabilitatea iphone.
API / SDK-uriPOST /v1/hosts/{deviceId}/exec cu { "op": "iphone", "args": { "tool": "tap", "args": { "x": 200, "y": 640 } } }; client.hosts.iphone(deviceId, 'tap', { x: 200, y: 640 }) în TypeScript, client.hosts.iphone(device_id, "tap", {"x": 200, "y": 640}) în Python.

Răspunsul este { ok, result: { data, image? } }: data este ce a întors unealta bridge-ului, iar image o captură JPEG opțională ca data URL (≤ 1,5 MB, tot rezultatul ≤ 2 MB). Numele uneltelor și argumentele sunt cele ale MCP-ului local codai-iphone, fără prefixul iphone_.

Ecran live și rezervă

Un vizualizator deschide un stream video pe mediul telefonului. Bridge-ul pornește CoreDevice DisplayService (HEVC, de obicei 30–55 fps), împarte o singură sesiune între toți vizualizatorii și o oprește odată cu ultimul. Când stream-ul nu poate rula — altă aplicație folosește camera sau microfonul (eroarea 9022), telefonul nu îl suportă sau a eșuat la trei reporniri — bridge-ul trece automat pe capturi JPEG la circa 2 fps, iar aplicația Android afișează Capturi de ecran în loc de Live. Unui vizualizator lent i se aruncă cadre până la următorul cadru cheie, conexiunea nu se închide niciodată.

Hub-ul deschide WebSocket-ul relay-ului cu un tichet de unică folosință valabil 60 de secunde, așa că cheia ta API nu ajunge niciodată în browser.

Securitate

  • Doar același utilizator. Gateway-ul retransmite o operație iphone doar între dispozitivele aceluiași cont; nu există partajare între utilizatori.
  • Uneltele sensibile sunt refuzate de la distanță. Instalarea / dezinstalarea și wifi_setup rulează doar local, dacă nu setezi relay.allow_sensitive: true în bridge.
  • Totul este jurnalizat. Apelurile de la distanță rulează același cod ca cele locale și ajung în jurnalul bridge-ului marcate "via": "relay".
  • Cheia rămâne pe PC, în fișierul ales de tine; bridge-ul nu o afișează niciodată.

Depanare

SimptomSoluție
409 host_offlineBridge-ul nu este conectat cu acces la distanță: pornește-l cu --relay sau relay.enabled: true.
Niciun iPhone online în hubLa fel ca mai sus; apare la câteva secunde după ce bridge-ul se conectează.
Capturi de ecran în loc de LiveDisplayService nu e disponibil (cameră sau microfon ocupate, nesuportat); controlul funcționează în continuare.
Telefonul nu e găsit prin Wi-FiȚine-l treaz și în aceeași rețea sau conectează cablul o dată și apelează local wifi_setup.
Montarea imaginii de dezvoltator eșueazăÎnchide uneltele care țin ocupat mounter-ul imaginii (Impactor, 3uTools) înainte să pornești bridge-ul.

Pe această pagină