Deep Linking vs Deferred Deep Linking:
A deep link is a special URL that routes to a specific spot, whether that’s on a website or in an app. A “mobile deep link” then, is a link that contains all the information needed to take a user directly into an app or a particular location within an app instead of just launching the app’s home page.
If the app is installed on the user's device - the deep link routes them to the correct location in the app. But what if the app isn't installed? This is where Deferred Deep Linking is used.When the app isn't installed, clicking on the link routes the user to the store to download the app. Deferred Deep linking defer or delay the deep linking process until after the app has been downloaded, and ensures that after they install, the user gets to the right location in the app.
Since users may or may not have the mobile app installed, there are 2 types of deep linking:
- Deferred Deep Linking (Legacy APIs) - Serving personalized content to new or former users, directly after the installation. -
- Direct Deep Linking (Legacy APIs) - Directly serving personalized content to existing users, which already have the mobile app installed.
- Unified deep linking - Unified deep linking sends new and existing users to a specific in-app activity as soon as the app is opened.
For more info about Deferred Deep Linking please check out the OneLink™ Deferred deep linking Guide.
For more info about Direct Deep linking please check out the OneLink™ Direct Deep Linking Guide.
For more info about Unified Deep Linking please check out the OneLink™ Direct Deep Linking Guide.
Check out the deferred deeplinkg guide from the AppFlyer knowledge base here.
- Create and register a delegate to receive the callbacks. Setup guide here
- Implement
onConversionDataSuccess
andonConversionDataFail
methods fromAppsFlyerLibDelegate
protocol
Code Sample to handle the conversion data:
// Handle Organic/Non-organic installation
func onConversionDataSuccess(_ data: [AnyHashable: Any]) {
print("onConversionDataSuccess data:")
for (key, value) in data {
print(key, ":", value)
}
if let status = data["af_status"] as? String {
if (status == "Non-organic") {
if let sourceID = data["media_source"],
let campaign = data["campaign"] {
print("This is a Non-Organic install. Media source: \(sourceID) Campaign: \(campaign)")
}
} else {
print("This is an organic install.")
}
if let is_first_launch = data["is_first_launch"] as? Bool,
is_first_launch {
print("First Launch")
if let fruit_name = data["deep_link_value"]
{
// The key 'deep_link_value' exists only in OneLink originated installs
print("deferred deep-linking to \(fruit_name)")
walkToSceneWithParams(params: data)
}
else {
print("Install from a non-owned media")
}
} else {
print("Not First Launch")
}
}
}
func onConversionDataFail(_ error: Error) {
print("\(error)")
}
When a deeplink is clicked on the device the AppsFlyer SDK will return the resolved link in the onAppOpenAttribution method.
- Create and register a delegate to receive the callbacks. Setup guide here
- Implement
onAppOpenAttribution
andonAppOpenAttributionFailure
methods fromAppsFlyerLibDelegate
protocol
Code Sample to handle OnAppOpenAttribution:
//Handle Deep Link Data
func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]) {
print("onAppOpenAttribution data:")
for (key, value) in attributionData {
print(key, ":",value)
}
var deepLinkValue: String? = nil
if let value = attributionData["deep_link_value"] as? String {
deepLinkValue = value
} else if let linkParam = attributionData["link"] as? String {
guard let url = URLComponents(string: linkParam) else {
print("Could not extract query params from link")
return
}
if let value = url.queryItems?.first(where: { $0.name == "deep_link_value" })?.value {
deepLinkValue = value
}
}
print("The deep link value is: \(deepLinkValue ?? "Not Found")")
}
func onAppOpenAttributionFailure(_ error: Error) {
print("onAppOpenAttributionFailure: \(error)")
}
The flow works as follows:
- User clicks the OneLink short URL.
- The iOS Universal Links or the deferred deep link, trigger the SDK.
- The SDK triggers the didResolveDeepLink method, and passes the deep link result object to the user.
- The
didResolveDeepLink
method uses the deep link result object that includes thedeep_link_value
and other parameters to create the personalized experience for the users, which is the main goal of OneLink.
Check out the Unified Deep Linking docs for iOS.
Implementation:
- Create and register a delegate to receive the callbacks. Setup guide here
- Implement
didResolveDeepLink
methods fromDeepLinkDelegate
protocol
Example:
func didResolveDeepLink(_ result: DeepLinkResult) {
print("didResolveDeepLink")
switch result.status {
case .notFound:
print("Deep link not found")
return
case .failure:
print("Error: \(result.error)")
return
case .found:
print("Deep link found")
}
guard let deepLinkObj:DeepLink = result.deepLink else {
print("Could not extract deep link object")
return
}
if deepLinkObj.isDeferred {
print("This is a deferred deep link")
} else {
print("This is a direct deep link")
}
let deepLinkValue = deepLinkObj.deeplinkValue
print("The deep link value is: \(deepLinkValue ?? "Not Found")")
}
This section is about setting up your app with deep links.
Add the following code to your AppDelegate
class:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// setup delegate for legacy deep links
AppsFlyerAdobeExtension.delegate = self
// setup delegate for UDL
AppsFlyerAdobeExtension.deepLinkDelegate = self
...
}
// For Swift version < 4.2 replace function signature with the commented out code
// func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool { // this line for Swift < 4.2
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Make sure you are using `AppsFlyerAttribution` and not `AppsFlyerLib`
AppsFlyerAttribution.shared.continueUserActivity(userActivity: userActivity)
return true
}
// Open URI-scheme for iOS 9 and above
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Make sure you are using `AppsFlyerAttribution` and not `AppsFlyerLib`
AppsFlyerAttribution.shared.handleOpenUrl(open: url)
return true
}
// Create Legacy Delegate
extension AppDelegate : AppsFlyerLibDelegate {
func onAppOpenAttribution(_ attributionData: [AnyHashable : Any]) {
print("onAppOpenAttribution")
}
func onAppOpenAttributionFailure(_ error: Error) {
print("onAppOpenAttributionFailure")
}
func onConversionDataFail(_ error: Error) {
print("onConversionDataFail")
}
func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) {
print("onConversionDataSuccess")
}
}
// Create UDL Delegate
extension AppDelegate : DeepLinkDelegate {
func didResolveDeepLink(_ result: DeepLinkResult) {
print("didResolveDeepLink")
}
}
If you use SceneDelegate
make sure to add the following code as well in your SceneDelegate
class:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
if let userActivity = connectionOptions.userActivities.first {
self.scene(scene, continue: userActivity)
} else {
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
}
...
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity){
// Make sure you are using `AppsFlyerAttribution` and not `AppsFlyerLib`
AppsFlyerAttribution.shared.continueUserActivity(userActivity: userActivity)
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>){
if let url = URLContexts.first?.url {
// Make sure you are using `AppsFlyerAttribution` and not `AppsFlyerLib`
AppsFlyerAttribution.shared.handleOpenUrl(open: url)}
}
Universal links
For more on Universal Links check out the guide here.
Essentially, the Universal Links method links between an iOS mobile app and an associate website/domain, such as AppsFlyer’s OneLink domain (xxx.onelink.me). To do so, it is required to:
- Configure OneLink sub-domain and link to mobile app (by hosting the ‘apple-app-site-association’ file - AppsFlyer takes care of this part in the onelink setup on your dashboard)
- Configure the mobile app to register approved domains: see here