[Bug] B11: Companion app — 'open in external browser' apps don't work #18

Closed
opened 2026-06-15 15:18:58 +00:00 by lfg2025 · 1 comment
Owner

Apps meant to open in a new/external browser don't launch from the companion app; need the phone-default-browser request-modal pattern mobile apps use.

Tracked in repo: tests/production-quality/TRACKER.md

Apps meant to open in a new/external browser don't launch from the companion app; need the phone-default-browser request-modal pattern mobile apps use. Tracked in repo: tests/production-quality/TRACKER.md
Author
Owner

Implemented across the stack (live pairing test pending).

The relay was one-way (Android companion → kiosk browser), so an "open external" app's window.open landed on the kiosk where the phone never saw it. Added a reverse hop:

  • Backend: new external_open_tx broadcast channel. The kiosk publishes {"t":"o","url":"https://…"} on its /ws/remote-relay socket; the server validates the URL (http/https only, ≤2048 chars — rejects javascript:/file:) and forwards it to the companion's /ws/remote-input socket.
  • Frontend: remote-relay.ts exposes requestExternalOpen(url); appLauncher.ts routes all four external-open sites through it — when a companion is active the URL goes to the phone, otherwise it opens locally as before.
  • Android: InputWebSocket.kt now parses the inbound {"t":"o","url"} and RemoteInputScreen.kt launches it via an ACTION_VIEW intent in the phone's default browser.

Rust cargo check + frontend vue-tsc pass. The Android module wasn't built here (no SDK in this env) — the Kotlin change is small and mirrors the existing openExternalUrl intent pattern. Live test: pair a phone, tap an "open external" app from the companion, confirm it opens on the phone.

**Implemented across the stack (live pairing test pending).** The relay was one-way (Android companion → kiosk browser), so an "open external" app's `window.open` landed on the kiosk where the phone never saw it. Added a reverse hop: - Backend: new `external_open_tx` broadcast channel. The kiosk publishes `{"t":"o","url":"https://…"}` on its `/ws/remote-relay` socket; the server validates the URL (http/https only, ≤2048 chars — rejects `javascript:`/`file:`) and forwards it to the companion's `/ws/remote-input` socket. - Frontend: `remote-relay.ts` exposes `requestExternalOpen(url)`; `appLauncher.ts` routes all four external-open sites through it — when a companion is active the URL goes to the phone, otherwise it opens locally as before. - Android: `InputWebSocket.kt` now parses the inbound `{"t":"o","url"}` and `RemoteInputScreen.kt` launches it via an `ACTION_VIEW` intent in the phone's default browser. Rust `cargo check` + frontend `vue-tsc` pass. The Android module wasn't built here (no SDK in this env) — the Kotlin change is small and mirrors the existing `openExternalUrl` intent pattern. Live test: pair a phone, tap an "open external" app from the companion, confirm it opens on the phone.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lfg2025/archy#18
No description provided.