DevelopersSeptember 14, 2026by
EmpoorioChain Core
EmpoorioChain Core

Engineering Notes #11: Three Deep-Link Traps in Flutter, Measured on a Phone

Context

A eoonia://link-wallet?request_id=… deep link should open Eoonia on the linking screen. On 8 September 2026, on a physical phone, it sometimes did and sometimes did not. Three causes, all invisible in an emulator with a warm app.

Trap 1: pushNamed() does not stay while the current location is an unrecognised route

An external-scheme link arrives at GoRouter as the location /?request_id=…, which matches no GoRoute. From that state, GoRouter re-resolves and lands on its error route. The log said pushing wallet_link_request… and currentConfiguration.uri still showed the failed URI. It looks like the push does not work, when the push runs fine — and is then discarded.

Fix: a redirect that sends that location to a valid route before it becomes an error, scoped tightly (state.uri.path == '/' && queryParameters.isNotEmpty) so ordinary navigation is untouched. Then the push sticks.

uriLinkStream from the links plugin is a broadcast stream. If the native side emits the launching intent before the Dart subscription exists — which is exactly what happens on a cold start — the link is gone without trace. The failure looks random because it depends on timing.

Fix: also read getInitialLink(), a Future that does not depend on timing, and handle both sources.

Fix: deduplicate by the full URI.

The shape of the fix

All three live in a shared routing mixin (DeepLinkRouting) used by Eoonia and the apps that call it, tested with the app launched cold, warm and from background — because a wallet request that vanishes on cold start is not a wallet integration.

The rule

Deep links are a platform boundary; test them on the device, in every launch state. The same session produced the note about installing on a locked phone (the OS refuses; unlock first) — the kind of thing no CI will ever tell you.

From the Ailoos ↔ Eoonia linking work, 2026-09-08.

Share this article