Supported on: iOS SDK 1.0.61+ · Android SDK 1.0.33+ · Flutter SDK 1.0.3+
The deep links module handles deferred deep links — routing users to the correct screen on first launch after installing from a link. This enables attribution tracking, referral programs, and contextual first-launch experiences.
Deferred Deep Links
A deferred deep link works across the install boundary:
- User clicks a link on the web (e.g.,
https://yourapp.com/workout/123?ref=instagram)
- User is redirected to the App Store or Play Store and installs your app
- On first launch, the SDK resolves the original link and returns the destination
final deepLink = await AppDNA.checkDeferredDeepLink();
if (deepLink != null) {
// deepLink.screen = "/workout/123"
// deepLink.params = {"ref": "instagram"}
navigate(deepLink.screen, deepLink.params);
}
checkDeferredDeepLink is a static method on AppDNA. It should be called once on first launch, typically after configure() completes. The SDK returns null if no deferred link is found or if the app was not installed from a link. On Android, resolution uses the Google Install Referrer API plus AppDNA’s stored visitor context.
Deferred Deep Link Check
checkDeferredDeepLink is a top-level static method on AppDNA, not part of the deep links module:
final deepLink = await AppDNA.checkDeferredDeepLink();
if (deepLink != null) {
navigate(deepLink.screen, deepLink.params);
}
Module Access
final deepLinks = AppDNA.deepLinks;
Module Methods
| Method | Signature | Description |
|---|
setDelegate | void setDelegate(AppDNADeepLinkDelegate? delegate) | Set a delegate for deep link callbacks |
handleURL | Future<void> handleURL(String url) | Pass an incoming deep link URL to the SDK for processing |
DeferredDeepLink
| Property | Type | Description |
|---|
screen | String | Target screen path (e.g., "/workout/123") |
params | Map<String, String> | Additional parameters (e.g., referrer, campaign) |
visitorId | String | The visitor identifier from the originating link |
AppDNADeepLinkDelegate
Register a delegate for deep link events:
abstract class AppDNADeepLinkDelegate {
/// Veto. Return false to suppress deep-link processing.
bool shouldOpen(String url, Map<String, dynamic> params);
void onDeepLinkReceived(String url, Map<String, dynamic> params);
}
shouldOpen is a veto called BEFORE the SDK processes a deep link. Return false to defer routing (for example until after login completes) and handle the URL yourself once the user is authenticated. Return true to let the SDK proceed with default handling.
Example Implementation
import 'package:appdna_sdk/appdna_sdk.dart';
class LinkHandler extends AppDNADeepLinkDelegate {
@override
bool shouldOpen(String url, Map<String, dynamic> params) {
// Return false to defer routing (e.g., until login completes).
return true;
}
@override
void onDeepLinkReceived(String url, Map<String, dynamic> params) {
// Route based on the incoming URL
final uri = Uri.parse(url);
route(uri.path, params);
}
void route(String screen, Map<String, dynamic> params) {
if (screen.startsWith("/workout/")) {
final id = screen.substring("/workout/".length);
showWorkout(id);
} else if (screen == "/referral") {
showReferralWelcome(params["ref"] as String?);
} else {
showHome();
}
}
void showWorkout(String id) { /* ... */ }
void showReferralWelcome(String? referrer) { /* ... */ }
void showHome() { /* ... */ }
}
AppDNA.deepLinks.setDelegate(LinkHandler());
Deep links require platform-specific configuration in your iOS and Android host projects.
iOS — Universal Links
To support Universal Links on iOS, configure your app:
- Enable Associated Domains in your target’s Signing & Capabilities.
- Add your domain:
applinks:yourapp.com
- Host an
apple-app-site-association file on your domain.
In your iOS host (AppDelegate.swift or SceneDelegate.swift), forward incoming URLs to the SDK:
// SceneDelegate
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let url = userActivity.webpageURL {
AppDNA.deepLinks.handleURL(url)
}
}
Android — App Links
- Add intent filters to your
AndroidManifest.xml:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="yourapp.com" />
</intent-filter>
- Host a Digital Asset Links file at
https://yourapp.com/.well-known/assetlinks.json.
- In your
MainActivity.kt, forward the incoming intent’s data URL to the SDK:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.dataString?.let { AppDNA.deepLinks.handleURL(it) }
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
intent.dataString?.let { AppDNA.deepLinks.handleURL(it) }
}
Forwarding from Dart
If your app already parses deep links in Dart (e.g. via the uni_links package), forward them to the SDK so triggers, attribution, and the delegate fire consistently:
await AppDNA.deepLinks.handleURL(incomingUri.toString());
Auto-Tracked Events
| Event | Trigger |
|---|
deep_link_handled | A deep link URL is processed |
deferred_deep_link_resolved | A deferred deep link is resolved on first launch |
Full Example
import 'package:appdna_sdk/appdna_sdk.dart';
class AppCoordinator extends AppDNADeepLinkDelegate {
AppCoordinator() {
AppDNA.deepLinks.setDelegate(this);
}
Future<void> handleFirstLaunch(String currentUserId) async {
// Check for deferred deep link on first launch
final deepLink = await AppDNA.checkDeferredDeepLink();
if (deepLink != null) {
// User installed from a link -- route to the target screen
route(deepLink.screen, deepLink.params);
// Track the visitor as a user trait
await AppDNA.identify(currentUserId, traits: {
"visitor_id": deepLink.visitorId,
});
} else {
// Normal install -- show default onboarding
showOnboarding();
}
}
// AppDNADeepLinkDelegate
@override
bool shouldOpen(String url, Map<String, dynamic> params) => true;
@override
void onDeepLinkReceived(String url, Map<String, dynamic> params) {
final uri = Uri.parse(url);
route(uri.path, params);
}
void route(String screen, Map<String, dynamic> params) {
// Route to the correct screen based on the path
}
void showOnboarding() { /* ... */ }
}
Deep link routes are configured in the Console under Engagement > Deep Links. The SDK resolves deferred links by checking the Google Install Referrer (Android) plus AppDNA’s stored visitor context on first launch.