Repository navigation
feat: device voiceover to drive VoiceOver and read what it speaks - #552
vijaysharm wants to merge 3 commits into
Conversation
mobilecli device voiceover get|set on/off|speech|move next/previous/in/out and the matching device.voiceover.* JSON-RPC methods, on iOS 27+ simulators and real devices, through devicekit's new device.voiceover.*. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 1 billable file and costs up to $0.25. Or wait 46 minutes for your next included review. View limit details
Walkthrough
Merge Risk:
|
RemoteDevice didn't implement the VoiceOver methods, so a fleet iOS 27 device was refused before any request was sent. Forward them like clipboard and orientation, and assert every iOS device type implements the interface. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A remote caller's read deadline is rpc.RPCTimeout (30s); with the agent call also allowed 30s, a timed-out set reached it as a generic read timeout. 25s still covers VoiceOver's own ~15s start failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Depends on mobile-next/devicekit-ios#109, which adds the agent side. Draft until that ships in a devicekit-ios release and
agentVersionIOSis bumped. This PR leaves the version alone, since agent bumps land as their own chore PRs.Summary
mobilecli has no way to check an app the way a VoiceOver user hears it. Labels show up in
dump ui, but not what VoiceOver actually speaks or the order it visits elements in. iOS 27'sXCUIDevice.voiceOverServicegives both, on simulators and real devices, and mobile-next/devicekit-ios#109 exposes it from the agent.This adds
mobilecli device voiceover get | set on|off | speech | move next|previous|in|out, plus the matchingdevice.voiceover.*JSON-RPC methods (documented indocs/openrpc.json). Android and pre-27 iOS answer with "does not support voiceover" or the agent's "requires iOS 27" error.Risk surface
io tapfocuses an element instead of activating it. The README, the--helptext and the RPC description all say so, because a forgottenset onmakes later taps look broken.setgets a 25s agent timeout instead of the default 10s. Disabling takes ~5s even when VoiceOver is already off, and a slow enable fails after ~15s with Apple's own error, which is more useful than our timeout. 25s stays under the fleet client's 30s read deadline.io tap @refdoes it: with VoiceOver on, the tap moves VoiceOver focus to the element without activating it, and the nextspeech/movestarts there. Each such tap takes ~6s.VoiceOver gestures through
io gestureVoiceOver also responds to gestures synthesized through
io gesture. On an iPhone 13 (iOS 27.0.1) these did what VoiceOver does for a finger:Tap-timing gestures can't be expressed yet: double tap to activate, split tap, Magic Tap, triple tap.
device.io.gesturepresses every finger at t=0, so for now nothing can be activated while VoiceOver is on. Follow-ups #553 and mobile-next/devicekit-ios#110 add a per-finger start time, which made all four work in a local test.Test plan
go test ./... -racego fmt ./...leaves no diffgolangci-lintv2.13.1 adds no new findings apart from one moregoconston the cobraUse: "get"stringBehavior verification
Needs the mobile-next/devicekit-ios#109 runner installed on an iOS 27 simulator (
xcrun simctl install <udid> devicekit-iosUITests-Runner.app).setreports the new state;speechandmovereturn the focused element's label (e.g."Fitness Double tap to open.");move inreturns the "Navigation Style ... Groups" error;speechwhile off returns "not enabled";set maybeandmove upare rejected before the device is toucheddump ui, thenio tap @<ref>with VoiceOver on. Expected:speechreturns that element's label, and the app does not navigatemobilecli server start. Expected: the same results overPOST /rpc; a missingdeviceIdorenabled→ "'X' is required"dump uithenio tap @<ref of the 7 key>→speechreturns"7"and the display does not change, because the tap focused the key without pressing itDemo
https://github.com/user-attachments/assets/8c1521c0-f321-46e6-b115-00726a94de66
https://github.com/user-attachments/assets/17446bbf-9f96-49fb-92f3-86fcc726a36c
🤖 Generated with Claude Code
Summary by CodeRabbit