Skip to content

fix(deeplink): handle incoming links in the SDK and report organic installs - #14

Merged
onamfc merged 2 commits into
mainfrom
fix/handle-incoming-links
Oct 20, 2026
Merged

onamfc merged 2 commits into
mainfrom
fix/handle-incoming-links

Conversation

@onamfc

@onamfc onamfc commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

  • initialize() listens for incoming links. It subscribes to app_links' uriLinkStream, which carries the link that launched the app (cold start) and links opened while it runs, and passes each to the deep link handler. onDeepLink callbacks receive the server-resolved link data with no app-side app_links code.
  • The launch link reaches late callbacks. A link that arrives before any onDeepLink callback is registered is held and delivered to the callbacks registered by the next microtask, so the documented pattern (register after await LinkForty.initialize(...)) receives it.
  • Repeat URLs are delivered once. The same URL passed to handleDeepLink() again within 10 seconds is ignored, so an app that also forwards links from its own app_links listener gets each link once. That listener can be removed.
  • onDeferredDeepLink(null) for organic installs, as the README describes.
  • LinkFortyConfig.attributionWindowHours is used when reporting the install; the initialize() argument overrides it when given.
  • Last-click attribution: the install link is recorded only on the launch that reports the install, and not over a direct deep link opened on that same launch. Without this, the direct link resolving during initialize() could be overwritten by the install link.
  • Example app registers its callbacks after initialize(); README updated (including turning off Flutter's built-in deep linking when it's in use).
  • Version 0.3.0 in pubspec.yaml and SdkInfo.version.

Behavior changes for existing apps

  • onDeferredDeepLink now also fires for organic installs, with null.
  • An app that calls handleDeepLink() from its own app_links listener keeps working and gets each link once.

Test plan

  • flutter test: 138 passing (9 new)
  • flutter analyze: no issues
  • dart pub publish --dry-run: no warnings beyond uncommitted files
  • Mutation checks: disabling the listener, the organic delivery, or the attribution guard each fails the new tests
  • On an Android device with verified App Links: cold start from a link, warm open, and a fresh install from a link

…stalls

initialize() now subscribes to app_links' link stream, which carries the
link that launched the app as well as links opened while it runs, and
passes each to the deep link handler. A link that arrives before any
onDeepLink callback is registered is held and delivered to the callbacks
registered by the next microtask, so registering after initialize()
returns receives the launch link.

The same URL passed to handleDeepLink() again within 10 seconds is
ignored, so an app that also forwards links from its own app_links
listener gets each link once.

onDeferredDeepLink is called with null for an organic install.
LinkFortyConfig.attributionWindowHours is used when reporting the
install; the initialize() argument overrides it when given.

The install link is recorded for last-click attribution only on the
launch that reports the install, and not over a direct deep link opened
on that same launch.

The example app registers its callbacks after initialize().
@onamfc
onamfc merged commit 5a0706c into main Oct 20, 2026
4 checks passed
@onamfc
onamfc deleted the fix/handle-incoming-links branch October 20, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant