Skip to content

fix(android): deliver deep links opened while the app is in the foreground - #481

Closed
tatsuhama wants to merge 1 commit into
AppsFlyerSDK:masterfrom
tatsuhama:fix/android-foreground-deep-link
Closed

tatsuhama wants to merge 1 commit into
AppsFlyerSDK:masterfrom
tatsuhama:fix/android-foreground-deep-link

Conversation

@tatsuhama

Copy link
Copy Markdown

What

Deliver deep links on Android when a OneLink is opened while the app is already in the foreground.

Why

Since 7.0.x, registerDeepLinkListener's callback is not called when a OneLink (App Link) is opened while the app is in the foreground — for example, when a notification containing a OneLink is tapped while the app is open. The same case works on 6.18.1.

In this case Android only pauses the Activity around onNewIntent and never stops it. The SDK resolves warm-start deep links when the Activity resumes after being stopped, so the intent is never resolved.

How

In the onNewIntent listener, forward the VIEW intent's URL to AppsFlyerLib.performDeepLinking(url, false) (the SDK 7 replacement for performOnDeepLinking), but only when the Activity has not been stopped since it last resumed.

  • When the app comes back from the background (onStop → onStart → onNewIntent → onResume), the SDK already resolves the intent itself. Forwarding it there as well delivers the deep link twice, which I reproduced on a device with an unconditional call.
  • The lifecycle state at onNewIntent cannot tell the two cases apart (it is STARTED in both), so the plugin observes the attached Activity's lifecycle and remembers whether ON_STOP happened since the last ON_RESUME. The observer is removed when the Activity detaches.
  • shouldTriggerSession is false: sessions are still sent from the session-ready start() call, so no extra Launch is added.
  • An Activity that is not a LifecycleOwner keeps the current behavior.

Testing

Device: Pixel 8 Pro (Android 17). A Flutter app that registers registerDeepLinkListener → init → registerSessionReadyListener (start() inside), with the dev-flavor OneLink App Link manually approved. Links were opened with adb shell am start -a android.intent.action.VIEW -d <OneLink>. Numbers are onDeepLinking callbacks / Launch events per step.

Scenario 6.18.1 7.0.4 7.0.4 + this PR
App killed → open OneLink 1 / 1 1 / 1 1 / 1
App in background → open OneLink 1 / 1 1 / 1 1 / 1
App in foreground → open OneLink 1 / 0 0 / 0 1 / 0
Background → foreground (no link) 1 (NOT_FOUND) / 1 0 / 1 0 / 1
  • flutter test test — all tests passed
  • ./gradlew :appsflyer_sdk:testDebugUnitTest (from example/android) — all tests passed
  • Not tested on add-to-app / multiple-engine setups.

…round

When a OneLink is opened while the app is already in the foreground (for
example, from a notification), Android only pauses the Activity around
onNewIntent and never stops it. The SDK resolves warm-start deep links when
the Activity resumes after being stopped, so the registered DeepLinkListener
was never called in this case.

Plugin 6.18.0 fixed the same case by calling performOnDeepLinking from the
onNewIntent listener; that call was lost in the SDK 7 rewrite. Forward the
VIEW intent to AppsFlyerLib.performDeepLinking instead, but only when the
Activity has not been stopped since it last resumed: when the app comes back
from the background the SDK resolves the intent itself, and forwarding it as
well would deliver the deep link twice.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@pazlavi

pazlavi commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the detailed report and repro table. We're going to decline this change, because this is intended behavior and not a regression.

Why. In the AppsFlyer SDK, a OneLink is resolved when the app comes to the foreground. A link that is handled while the app is already in the foreground, for example from a notification tap or a link inside the app, is not resolved automatically. This has been the SDK's behavior for many years. For that case the app calls performDeepLinking(url) itself, as native Android apps do.

Plugin 6.x had some plugin-specific handling around onNewIntent. In v7 we intentionally removed it so that the plugin behaves the same as the native SDK, and the same as our other plugins. The migration guide lists performDeepLinking as the replacement for performOnDeepLinking.

What to do in your app. In your notification-tap or link handler, call:

AppsFlyerSdk.instance.performDeepLinking(url, shouldTriggerSession: false);

The result arrives in your registerDeepLinkListener callback as usual. Use shouldTriggerSession: true if you want the link to count as a re-engagement.

Why we're not forwarding in the plugin. The SDK already handles links when the app returns from the background, so the plugin would also forward some links the SDK resolves itself, and those could be delivered twice. We also think this change might deliver the same deep link twice: once when it is forwarded in the foreground, and again when the app moves to the background and then comes back to the foreground. Keeping a single, explicit entry point avoids that.

If you want to go through your use case or look at other options, please contact our support team and they'll help you adjust your integration.

@pazlavi pazlavi closed this Nov 3, 2026
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.

2 participants