Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

/ios-qa: token-rotation wedge + SwiftUI-gesture limitations on iOS 26 (3 findings) #1975

Open

Description

/ios-qa: three findings integrating the debug bridge with a SwiftUI Canvas + DragGesture app on iOS 26

First, thanks for /ios-qa — I drove it end-to-end on a real device (screenshots, state snapshots, and input all working) on a SwiftUI game that renders through TimelineView(.animation) + Canvas and takes its input via a DragGesture. Three things surfaced that I think are worth a look. Code references are against the current templates on main (v1.57.10.0).

Environment: gstack v1.57.10.0 · Xcode 26.5 · iPhone 14, iOS 26.5 · SwiftUI Canvas + TimelineView app.


1. Boot-token rotation scrubs the sandbox file, wedging re-bootstrap on an Xcode 26 tunnel drop (bug)

StateServer.handleAuthRotate (templates/StateServer.swift.template) does, on the first successful rotate:

rotatedToken = newToken
bootTokenValid = false
// Best-effort scrub of on-disk boot token file.
try? FileManager.default.removeItem(atPath: bootTokenPath)

This assumes one bootstrap per app launch. But Xcode 26's CoreDevice drops the USB tunnel between devicectl invocations, so the Mac daemon re-runs bootstrapTunnel (its tunnel cache expires ~30s, or any reconnect). Re-bootstrap calls copyFileFromAppContainer on the boot-token path — which was just deleted — against the still-running app, and fails with boot_token_unavailable. Every reconnect is then wedged until the app is force-relaunched (only a relaunch re-runs start() and rewrites the file).

Repro: rotate once, keep the app running, let the tunnel drop / cache expire, trigger any command → boot_token_unavailable.

Suggested fix: on rotate, re-mint the on-disk token (write a fresh UUID, keep bootTokenValid = true) instead of scrubbing it. That preserves the security property that matters — every previously scraped credential (the os_log boot token, any earlier file copy) is dead the moment rotation lands — while leaving a live file for the daemon to re-read on reconnect. The rotated session token remains the daemon's in-memory secret.


2. In-process synthesized touches don't reach SwiftUI gesture recognizers on iOS 26 (limitation)

DebugBridgeTouch.sendTapAtPoint builds a real UITouch + IOHIDEvent and dispatches via UIApplication.sendEvent. On iOS 26.5 this returns success (hit view found, event delivered) but a SwiftUI DragGesture never fires — a Canvas whose input is a DragGesture sees nothing.

Important: I tried phase-separating the touch (Began → interpolated Moved → Ended across run-loop turns) and it still did not reach the DragGesture, so I don't think the synchronous Began→Ended dispatch is the root cause — it looks like iOS 26's gesture environment doesn't surface in-process synthetic touches to SwiftUI's gesture system at all. (UIKit controls / SwiftUI Button via _UIHitTestContext may still work — I was specifically driving a Canvas + DragGesture.)

Workaround I used: route tap/swipe into the app's own gesture-handler methods (the app exposes its input surface to the debug bridge under #if DEBUG), bypassing synthesis entirely. Deterministic and version-proof.

Open question: is there a known way to drive SwiftUI gestures via in-process synthesis on iOS 26? If not, it might be worth documenting the limitation and/or sanctioning an input-routing hook for gesture-driven apps.


3. /swipe only drives UIScrollView (limitation)

MutationBridgeImpl.handleSwipe (templates/Bridges.swift.template) walks up to the nearest enclosing UIScrollView and nudges setContentOffset; if none is found it returns false (no-op). The code's own comment notes it is "less faithful than synthesized touches but covers common scroll scenarios." For a gesture-driven non-scroll view (SwiftUI Canvas/DragGesture, custom pan handlers), /swipe does nothing.

Suggested direction: synthesize a real touch drag as a fallback when no UIScrollView is found — though per finding #2 that may not reach SwiftUI gestures on iOS 26 anyway, so an input-routing hook may be the more reliable path for those apps.


Happy to open separate issues, send a PR for #1 (the re-mint is a few lines), or share the input-routing approach if useful. Thanks again for the harness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /