The iOS fix for #198 establishes a contract that Android does not yet meet:
A link that arrives before anything is subscribed is handed to the first
craft.deepLinks.onLink/craft.onDeepLinksubscriber, including the link that launched the app, markedinitial: true. A page that callsgetInitialURL()first, or in the same tick, gets the launch link from there and not a second time fromonLink.
Where Android stands
- Cold start dispatches nothing.
MainActivity.onCreatecallshandleIncomingDeepLink(intent, dispatch = false). The launch link reaches onlygetInitialURL(), so a page that subscribes and never asks never learns how it was opened. That is exactly #198's failure on iOS. - Warm links race the page.
CraftBridge.sendEventqueues events untilbridgeReadyand flushes them from theinjectBridgecallback. The flush happens immediately after the script that definesonLinkruns, so no page code can have subscribed yet, and a link queued during a reload is dispatched to nobody. This is the same timing iOS had. onLinkreturns nothing where iOS now returns an unsubscribe function.
What parity looks like
Port the page half of the iOS change. It is plain JavaScript in the injected script:
- an
undeliveredlist filled by acraftDeepLinklistener while nothing is subscribed; _subscribeDeepLinks, which replays that list to the first subscriber on the next turn and returns an unsubscribe;_claimInitialDeepLink, called bygetInitialURL, which withdraws the entry markedinitial.
On the native side, dispatch the launch link on cold start with initial: true instead of suppressing it.
The E2E harness can cover it the way iOS is covered. adb shell am start -a android.intent.action.VIEW -d <link> cold-starts the app with no confirmation prompt, and the driver page's probeDeepLinks already reports what it received. It needs a host-side read on Android, which logcat already provides.
Found while fixing #198.