Skip to content

feat: drive development-signed apps on physical iOS devices - #99

Open
onevcat wants to merge 3 commits into
mainfrom
fix/physical-ios-device-merge-readiness
Open

feat: drive development-signed apps on physical iOS devices#99
onevcat wants to merge 3 commits into
mainfrom
fix/physical-ios-device-merge-readiness

Conversation

@onevcat

@onevcat onevcat commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up replacement for #93 that preserves the original feature commit (92801fd) and @subdiox's authorship.

  • Add the experimental sim-use ios-device devices/ui/tap surface over the accessibility audit daemon.
  • Scope full hierarchy and actions to development-signed foreground apps with get-task-allow=true; Release-configuration builds remain supported when installed with a Development profile.
  • Replace device-only tap --text with the existing --label, --label-contains, and --element-type vocabulary.
  • Fail loudly for empty hierarchies and missing or ambiguous tap targets instead of printing 0 elements, choosing the first match, or showing usage for a runtime miss.
  • Wait for physical-device attachment notifications to quiesce so multiple USB devices are discovered.
  • Correlate DTX replies by both identifier and conversationIndex, preventing unsolicited events from satisfying unrelated pending requests.
  • Document the experimental support boundary in CLI help, README, CHANGELOG, and the bundled skill.

Supported scope

  • Paired, trusted, unlocked physical iPhone/iPad with Developer Mode enabled.
  • Foreground target app signed with a Development profile and final get-task-allow=true entitlement.
  • No runner installation, sim-use-side signing, or Developer Disk Image.
  • Text hierarchy and accessibility Activate only; no geometry, coordinates, gestures, screenshot, recording, or JSON on this surface yet.
  • Distribution/Ad Hoc, TestFlight, App Store, and system apps are explicitly unsupported.

Verification

  • make build — passed with 0 warnings.
  • make test — 1311 tests passed with 0 warnings.
  • Two-device enumeration — both attached devices returned in 20/20 runs.
  • iPhone 14 Pro, iOS 18.4.1:
    • Development-signed Release archive: 114 nodes; label-selected Activate navigated to Tap Test.
    • Five immediate cold-launch hierarchy reads: 5/5 stable.
    • ui --fast: passed.
  • iPhone 15 Pro Max, iOS 26.6:
    • Development-signed Release archive: 124 nodes; label-selected Activate navigated to Tap Test.
    • Five immediate cold-launch hierarchy reads: 5/5 stable.
    • ui --connections 2: passed.
  • The same archive exported with Apple Distribution / Ad Hoc signing (get-task-allow=false) failed on both OS versions with exit 1 and the entitlement diagnostic; neither path printed 0 elements or action success.
  • Missing target, ambiguous target, invalid tuning, and multi-device selection error contracts are covered by focused tests.

subdiox and others added 3 commits August 10, 2026 18:55
Adds `sim-use ios-device` (devices / ui / tap), a third backend alongside
the simulator and Android ones. A connected iPhone or iPad is reached
through `com.apple.accessibility.axAuditDaemon.remoteserver` over usbmux
lockdown, so no XCUITest runner is installed, nothing is code signed and
no Developer Disk Image is mounted — the device only has to be unlocked.

The channel exposes no element geometry, so this surface deliberately
omits coordinate taps, swipes and gestures and interacts through
accessibility actions instead; the outline is ordered by the
accessibility reading order rather than by screen position.

Notable details, all measured against iOS 27:

- The daemon wants the DTX stream in plaintext once lockdown has started
  the service. `FBAMDServiceConnection` send/receive push bytes through
  the connection's SSL context, so the transport talks to the raw socket
  instead; encrypted frames make the device hang up on the first message.
- `FBDeviceSet` receives AMDevice attachment through CFRunLoop sources on
  the main queue, so discovery pumps the main run loop. Without that a
  CLI only ever sees the restorable half of the device.
- AMDevice does not publish the lockdown UDID before a session, so a
  device is addressable by ECID as well.
- Sessions must release the daemon's inspector state on the way out.
  Skipping it leaves the device answering every element query with
  nothing, which is easy to misread as a locked screen.

Requests are pipelined over one connection, which is worth about 1.4x;
past that the daemon serialises, so `--fast` trades roughly a quarter of
the elements for 40% off the wall clock.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: yuta.ooka <yuta.ooka@lycorp.co.jp>
PR #93 widens the SKILL.md description to cover physical iPhone/iPad
driving, so the substring the init test pins no longer matches.

Claude-Session: https://claude.ai/code/session_01Tfc7gDbW9yPgmGW9g3QZb4
Signed-off-by: onevcat <onevcat@gmail.com>
Scope the accessibility-audit backend to development-signed target apps and fail clearly when the device exposes no usable hierarchy. Align tap selectors with the regular label vocabulary and reject missing or ambiguous targets without usage-error noise.

Wait for multi-device discovery to quiesce, route DTX replies by conversation index as well as identifier, preserve operation errors across session cleanup, and cover the behavior with focused tests and updated documentation.

Signed-off-by: onevcat <onevcat@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants