Links for Flutter SDK
Enable and track Android App Links and iOS Universal Links in your app using the Flutter SDK
Android App Links and iOS Universal Links allow the links you send through Marketing to open directly in your mobile application without any redirects that would hinder your users' experience.
For details on how App Links and Universal Links work and how they can improve your users' experience, refer to the Universal Links section in the Campaigns documentation.
This page describes the steps required to support and track incoming App Links and Universal Links in your app using the Flutter SDK.
Implement and track App Links and Universal Links
The official Flutter documentation describes how to set up your application and how to process incoming links. , we just need to add tracking to Exponea.
When the application is opened by an App Link or Universal link while there is no session active, the newly started session will contain tracking parameters from the link.
Android
No changes are required to make App Links work.
To track the links to Marketing, you must add 2 methods to the MainActivity that will respond to incoming intents:
package com.exponea.example
import android.content.Intent
import android.os.Bundle
import com.exponea.ExponeaPlugin
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Add this call:
ExponeaPlugin.Companion.handleCampaignIntent(intent, applicationContext)
super.onCreate(savedInstanceState)
}
override fun onNewIntent(intent: Intent) {
// Add this call:
ExponeaPlugin.Companion.handleCampaignIntent(intent, applicationContext)
super.onNewIntent(intent)
}
}iOS
Universal Links are handled automatically by the SDK for both the legacy AppDelegate lifecycle and the UIScene lifecycle (Flutter 3.38+).
With ExponeaFlutterAppDelegate
If your AppDelegate extends ExponeaFlutterAppDelegate, no changes are required — Universal Links are tracked automatically in both lifecycle modes.
Without ExponeaFlutterAppDelegate
Legacy lifecycle — if your AppDelegate doesn't extend ExponeaFlutterAppDelegate, forward the event manually (the plugin doesn't implement application(_:continue:restorationHandler:) to avoid double-firing alongside ExponeaFlutterAppDelegate).
If your AppDelegate still extends FlutterAppDelegate, track then call super so Flutter can still handle deeplinking (don't return true without calling super — that claims the activity and can skip Flutter's link handling):
override func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
SwiftExponeaPlugin.continueUserActivity(userActivity)
return super.application(application, continue: userActivity, restorationHandler: restorationHandler)
}If you implement UIApplicationDelegate directly (no FlutterAppDelegate), call SwiftExponeaPlugin.continueUserActivity(userActivity) and return whatever your own routing logic requires.
UIScene lifecycle (Flutter 3.38+):
If you use the standard migration (FlutterSceneDelegate declared in Info.plist), no manual implementation is required — the SDK registers itself via addSceneDelegate and tracks Universal Links automatically for both cold launch and warm launch.
If you use the FlutterSceneLifeCycleProvider protocol and correctly forward scene callbacks to your FlutterPluginSceneLifeCycleDelegate, no manual forwarding is required — addSceneDelegate routes events to the SDK automatically.
If you use a fully custom SceneDelegate that doesn't subclass FlutterSceneDelegate and doesn't forward Flutter scene lifecycle events to a FlutterPluginSceneLifeCycleDelegate, you must forward both the cold launch and warm launch events manually:
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
if let userActivity = connectionOptions.userActivities
.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }) {
SwiftExponeaPlugin.continueUserActivity(userActivity)
}
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
SwiftExponeaPlugin.continueUserActivity(userActivity)
}Updated 4 days ago

