Please follow the steps in the section that corresponds to the type of app you have:
- UIKit apps using AppDelegate lifecycle
- UIKit apps using SceneDelegate lifecycle
- SwiftUI apps using AppDelegate lifecycle
- SwiftUI apps using SceneDelegate lifecycle
In addition, implement deep link handling logic:
UIKit apps using AppDelegate lifecycle
Update your AppDelegate to implement direct and deferred deep linking.
import Adjustimport UIKit
@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate, AdjustDelegate{ func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Configure Adjust SDK // Replace {YourAppToken} with your Adjust app token let appToken = "{YourAppToken}" var adjustConfig: ADJConfig?
#if DEBUG adjustConfig = ADJConfig( appToken: appToken, environment: ADJEnvironmentSandbox) adjustConfig?.logLevel = ADJLogLevelVerbose #else adjustConfig = ADJConfig( appToken: appToken, environment: ADJEnvironmentProduction, allowSuppressLogLevel: true) adjustConfig?.logLevel = ADJLogLevelSuppress #endif
// Wait up to 120 seconds after app open for user to respond to ATT // before sending install session to Adjust's servers. // Ensure this interval is long enough for user to respond. adjustConfig?.attConsentWaitingInterval = 120
// Create delegate for deferred deep linking adjustConfig?.delegate = self
// Initialize Adjust SDK Adjust.initSdk(adjustConfig)
return true }
// Receive universal link when app is installed, // and app is in "not running" or background state, // and user clicks link or another app opens link using // UIApplication.open(_:options:completionHandler:). func application( _ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void ) -> Bool { if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingLink = userActivity.webpageURL { // Handle incoming universal link DeeplinkHandler.handleDeeplink(incomingLink) } return true }
// Receive app scheme deep link when app is installed, and either: // - App is in "not running" or background state, and user clicks link or // another app opens link using UIApplication.open(_:options:completionHandler:), or // - App is in foreground state and opens its own link using // UIApplication.open(_:options:completionHandler:). func application( _ application: UIApplication, open incomingLink: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:] ) -> Bool { // Handle incoming app scheme deep link DeeplinkHandler.handleDeeplink(incomingLink) return true }
// Receive deferred deep link via AdjustDelegate method func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool { if let incomingLink = deeplink { if UserDefaults.standard.bool(forKey: "HasCompletedOnboarding") { // If onboarding is complete, handle deferred deep link immediately DeeplinkHandler.handleDeeplink(incomingLink) } else { // Store deferred deep link to invoke after onboarding screens and login UserDefaults.standard.set(incomingLink.absoluteString, forKey: "lastDeferredLink") } } // Return true to let Adjust SDK attempt to open deep link immediately // upon receipt (for example: app has no ATT, onboarding screens, or login). // Otherwise, return false to prevent SDK from opening the deep link immediately. return false }
#import <Adjust/Adjust.h>#import "AppDelegate.h"#import "DeeplinkHandler.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Configure Adjust SDK // Replace {YourAppToken} with your Adjust app token NSString *appToken = @"{YourAppToken}"; ADJConfig *adjustConfig;
#ifdef DEBUG adjustConfig = [ADJConfig configWithAppToken:appToken environment:ADJEnvironmentSandbox]; [adjustConfig setLogLevel:ADJLogLevelVerbose];#else adjustConfig = [ADJConfig configWithAppToken:appToken environment:ADJEnvironmentProduction allowSuppressLogLevel:YES]; [adjustConfig setLogLevel:ADJLogLevelSuppress];#endif
// Wait up to 120 seconds after app open for user to respond to ATT // before sending install session to Adjust's servers. // Ensure this interval is long enough for user to respond. adjustConfig.attConsentWaitingInterval = 120;
// Create delegate for deferred deep linking adjustConfig.delegate = self;
// Initialize Adjust SDK [Adjust initSdk:adjustConfig];
return YES;}
// Receive universal link when app is installed,// and app is in "not running" or background state,// and user clicks link or another app opens link using// [UIApplication openURL:options:completionHandler:].- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler: (void (^)(NSArray<id<UIUserActivityRestoring>> *_Nullable)) restorationHandler { if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { NSURL *incomingLink = userActivity.webpageURL; if (incomingLink) { // Handle incoming universal link [DeeplinkHandler handleDeeplink:incomingLink]; } } return YES;}
// Receive app scheme deep link when app is installed, and either:// - App is in "not running" or background state, and user clicks link or// another app opens link using [UIApplication// openURL:options:completionHandler:], or// - App is in foreground state and opens its own link using// [UIApplication openURL:options:completionHandler:].- (BOOL)application:(UIApplication *)app openURL:(NSURL *)incomingLink options: (NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options { // Handle incoming app scheme deep link [DeeplinkHandler handleDeeplink:incomingLink]; return YES;}
// Receive deferred deep link via AdjustDelegate method- (BOOL)adjustDeferredDeeplinkReceived:(nullable NSURL *)deeplink { if (deeplink) { if ([[NSUserDefaults standardUserDefaults] boolForKey:@"HasCompletedOnboarding"]) { // If onboarding is complete, handle deferred deep link immediately [DeeplinkHandler handleDeeplink:deeplink]; } else { // Store deferred deep link to invoke after onboarding screens and login [[NSUserDefaults standardUserDefaults] setObject:deeplink.absoluteString forKey:@"lastDeferredLink"]; } } // Return YES to let Adjust SDK attempt to open deep link immediately // upon receipt (for example: app has no ATT, onboarding screens, or login). // Otherwise, return NO to prevent SDK from opening the deep link immediately. return NO;}
Most apps have some kind of onboarding process (for example: ATT prompt, onboarding screens, login prompt). When setting up deferred deep linking, you have to ensure that onboarding and launching deferred deep links don’t interfere with each other. One approach is to wait until after onboarding to launch deferred deep links. Here’s how it works in the code examples:
- A user who doesn’t have the app installed clicks an Adjust deep link, which redirects them to the app store.
- The user installs and opens the app.
- The app begins its onboarding process.
- After the ATT prompt response or timeout, the Adjust SDK sends session and attribution requests to Adjust’s servers.
- Adjust’s servers respond with attribution data, including the deep link the user clicked on (“deferred deep link”).
- The Adjust SDK triggers a deferred deep link callback in the app (shown in the AppDelegate implementation above). The callback checks whether onboarding is complete:
- If onboarding is complete, it handles the deep link immediately.
- If onboarding isn’t complete, it stores the deep link.
- Once onboarding completes, the app checks for and handles any stored deferred deep link (shown in the ViewController example class below).
- The app navigates the user to the deep link screen.
import Adjustimport UIKit
class ViewController: UIViewController { var hasCompletedOnboarding: Bool { get { UserDefaults.standard.bool(forKey: "HasCompletedOnboarding") } set { UserDefaults.standard.set(newValue, forKey: "HasCompletedOnboarding") } }
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated)
// Check if onboarding has been completed if !hasCompletedOnboarding { // Show onboarding screens and login prompt
// Show ATT prompt after delay to ensure app is active DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { Adjust.requestTrackingAuthorizationWithCompletionHandler { _ in } }
// After onboarding, set hasCompletedOnboarding to true hasCompletedOnboarding = true
// Check for deferred deep link that arrived during onboarding if let deferredLinkString = UserDefaults.standard.string( forKey: "lastDeferredLink" ), let deferredLink = URL(string: deferredLinkString) { // Remove stored deferred deep link to avoid handling again later UserDefaults.standard.removeObject(forKey: "lastDeferredLink") // Handle deferred deep link DeeplinkHandler.handleDeeplink(deferredLink) } } else { // Show main content } }}
#import <Adjust/Adjust.h>#import "DeeplinkHandler.h"#import "ViewController.h"
@implementation ViewController
- (BOOL)hasCompletedOnboarding { return [[NSUserDefaults standardUserDefaults] boolForKey:@"HasCompletedOnboarding"];}
- (void)setHasCompletedOnboarding:(BOOL)hasCompletedOnboarding { [[NSUserDefaults standardUserDefaults] setBool:hasCompletedOnboarding forKey:@"HasCompletedOnboarding"];}
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated];
// Check if onboarding has been completed if (!self.hasCompletedOnboarding) { // Show onboarding screens and login prompt // Show ATT prompt after delay to ensure app is active dispatch_after( dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [Adjust requestTrackingAuthorizationWithCompletionHandler:nil]; });
// After onboarding, set hasCompletedOnboarding to true self.hasCompletedOnboarding = YES;
// Check for deferred deep link that arrived during onboarding NSString *deferredLinkString = [[NSUserDefaults standardUserDefaults] stringForKey:@"lastDeferredLink"]; NSURL *deferredLink = [NSURL URLWithString:deferredLinkString]; if (deferredLink) { // Remove stored deferred deep link to avoid handling again later [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"lastDeferredLink"]; // Handle deferred deep link [DeeplinkHandler handleDeeplink:deferredLink]; } } else { // Show main content }}
@end
Lastly, implement your deep link handling logic:
UIKit apps using SceneDelegate lifecycle
Follow the steps in the UIKit apps using AppDelegate lifecycle section, except instead of implementing the application(_:continue:restorationHandler:)
and application(_:open:options:)
methods in your AppDelegate for direct deep linking, implement the following methods in your SceneDelegate.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Receive universal link or app scheme deep link // when app is installed, and app is in "not running" state, and either: // - User clicks link, or // - Another app opens link using // UIApplication.open(_:options:completionHandler:). func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { // Handle incoming universal link if let userActivity = connectionOptions.userActivities.first, userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingLink = userActivity.webpageURL { DeeplinkHandler.handleDeeplink(incomingLink) }
// Handle incoming app scheme deep link else if let urlContext = connectionOptions.urlContexts.first { let incomingLink = urlContext.url DeeplinkHandler.handleDeeplink(incomingLink) } }
// Receive universal link when app is installed, // and app is in background state, and either: // - User clicks link, or // - Another app opens link using // UIApplication.open(_:options:completionHandler:). func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingLink = userActivity.webpageURL { // Handle incoming universal link DeeplinkHandler.handleDeeplink(incomingLink) } }
// Receive app scheme deep link when app is installed, and either: // - App is in background state, and user clicks link or another app opens link using // UIApplication.open(_:options:completionHandler:), or // - App is in foreground and opens its own link using // UIApplication.open(_:options:completionHandler:). func scene( _ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext> ) { if let urlContext = URLContexts.first { let incomingLink = urlContext.url
// Handle incoming app scheme deep link DeeplinkHandler.handleDeeplink(incomingLink) } }}
#import "DeeplinkHandler.h"#import "SceneDelegate.h"
@implementation SceneDelegate
// Receive universal link or app scheme deep link// when app is installed, and app is in "not running" state, and either:// - User clicks link, or// - Another app opens link using// [UIApplication openURL:options:completionHandler:].- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { // Handle incoming universal link if (connectionOptions.userActivities.count > 0) { NSUserActivity *userActivity = connectionOptions.userActivities.allObjects.firstObject; if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb] && userActivity.webpageURL) { NSURL *incomingLink = userActivity.webpageURL; [DeeplinkHandler handleDeeplink:incomingLink]; } } // Handle incoming app scheme deep link else if (connectionOptions.URLContexts.count > 0) { UIOpenURLContext *urlContext = connectionOptions.URLContexts.allObjects.firstObject; NSURL *incomingLink = urlContext.URL; [DeeplinkHandler handleDeeplink:incomingLink]; }}
// Receive universal link when app is installed,// and app is in background state, and either:// - User clicks link, or// - Another app opens link using// [UIApplication openURL:options:completionHandler:].- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity { if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { NSURL *incomingLink = userActivity.webpageURL;
// Handle incoming universal link [DeeplinkHandler handleDeeplink:incomingLink]; }}
// Receive app scheme deep link when app is installed, and either:// - App is in background state, and user clicks link or another app opens link// using [UIApplication openURL:options:completionHandler:], or// - App is in foreground and opens its own link using// [UIApplication openURL:options:completionHandler:].- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts { UIOpenURLContext *urlContext = URLContexts.allObjects.firstObject; if (urlContext) { NSURL *incomingLink = urlContext.URL;
// Handle incoming app scheme deep link [DeeplinkHandler handleDeeplink:incomingLink]; }}
@end
SwiftUI apps using AppDelegate lifecycle
If you haven’t already done so, create an AppDelegate.swift
file in your project’s main directory and reference it in your main application file (for example: App.swift
as shown below). This is required to handle app lifecycle events and Adjust SDK integration. Also implement onOpenURL
, which receives all direct deep links.
import SwiftUI
@mainstruct MyApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene { WindowGroup { ContentView() // Receive universal link or app scheme deep link // when app is installed, and app is in "not running" or background state, and either: // - User clicks link, or // - Another app opens link using // UIApplication.open(_:options:completionHandler:) or SwiftUI's openURL. // // Receive app scheme deep link when app is installed, // and app is in foreground and opens its own link using // UIApplication.open(_:options:completionHandler:) or SwiftUI's openURL. .onOpenURL { incomingLink in DeeplinkHandler.handleDeeplink(incomingLink) } } }}
Update your AppDelegate to implement deferred deep linking.
import Adjustimport UIKit
class AppDelegate: UIResponder, UIApplicationDelegate, AdjustDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Configure Adjust SDK // Replace {YourAppToken} with your Adjust app token let appToken = "{YourAppToken}" var adjustConfig: ADJConfig?
#if DEBUG adjustConfig = ADJConfig( appToken: appToken, environment: ADJEnvironmentSandbox) adjustConfig?.logLevel = ADJLogLevelVerbose #else adjustConfig = ADJConfig( appToken: appToken, environment: ADJEnvironmentProduction, allowSuppressLogLevel: true) adjustConfig?.logLevel = ADJLogLevelSuppress #endif
// Wait up to 120 seconds after app open for user to respond to ATT // before sending install session to Adjust's servers. // Ensure this interval is long enough for user to respond. adjustConfig?.attConsentWaitingInterval = 120
// Create delegate for deferred deep linking adjustConfig?.delegate = self
// Initialize Adjust SDK Adjust.initSdk(adjustConfig)
return true }
// Receive deferred deep link via AdjustDelegate method func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool { if let incomingLink = deeplink { if UserDefaults.standard.bool(forKey: "HasCompletedOnboarding") { // If onboarding is complete, handle deferred deep link immediately DeeplinkHandler.handleDeeplink(incomingLink) } else { // Store deferred deep link to invoke after onboarding screens and login UserDefaults.standard.set(incomingLink.absoluteString, forKey: "lastDeferredLink") } } // Return true to let Adjust SDK attempt to open deep link immediately // upon receipt (for example: app has no ATT, onboarding screens, or login). // Otherwise, return false to prevent SDK from opening the deep link immediately. return false }}
Most apps have some kind of onboarding process (for example: ATT prompt, onboarding screens, login prompt). When setting up deferred deep linking, you have to ensure that onboarding and launching deferred deep links don’t interfere with each other. One approach is to wait until after onboarding to launch deferred deep links. Here’s how it works in the code examples:
- A user who doesn’t have the app installed clicks an Adjust deep link, which redirects them to the app store.
- The user installs and opens the app.
- The app begins its onboarding process.
- After the ATT prompt response or timeout, the Adjust SDK sends session and attribution requests to Adjust’s servers.
- Adjust’s servers respond with attribution data, including the deep link the user clicked on (“deferred deep link”).
- The Adjust SDK triggers a deferred deep link callback in the app (shown in the AppDelegate implementation above). The callback checks whether onboarding is complete:
- If onboarding is complete, it handles the deep link immediately.
- If onboarding isn’t complete, it stores the deep link.
- Once onboarding completes, the app checks for and handles any stored deferred deep link (shown in the ContentView example class below).
- The app navigates the user to the deep link screen.
import Adjustimport Foundationimport SwiftUI
struct ContentView: View { var body: some View { NavigationStack { VStack { // Check if onboarding has been completed if !UserDefaults.standard.bool(forKey: "HasCompletedOnboarding") { // Show onboarding screens and login prompt // Show ATT prompt after delay to ensure app is active .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { Adjust.requestTrackingAuthorizationWithCompletionHandler { _ in } }
// After onboarding, set hasCompletedOnboarding to true UserDefaults.standard.set(true, forKey: "HasCompletedOnboarding")
// Check for deferred deep link that arrived during onboarding if let deferredLinkString = UserDefaults.standard.string( forKey: "lastDeferredLink" ), let deferredLink = URL(string: deferredLinkString) { // Remove stored deferred deep link to avoid handling again later UserDefaults.standard.removeObject(forKey: "lastDeferredLink") // Handle deferred deep link DeeplinkHandler.handleDeeplink(deferredLink) } } } else { // Show main content } } } }}
Lastly, implement your deep link handling logic:
SwiftUI apps using SceneDelegate lifecycle
Follow the steps in the SwiftUI apps using AppDelegate lifecycle. In addition, implement the following method in your SceneDelegate.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Receive universal link or app scheme deep link // when app is installed, and app is in "not running" state, and either: // - User clicks link, or // - Another app opens link using // UIApplication.open(_:options:completionHandler:) or SwiftUI's openURL. func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { // Handle incoming universal link if let userActivity = connectionOptions.userActivities.first, userActivity.activityType == NSUserActivityTypeBrowsingWeb, let incomingLink = userActivity.webpageURL { DeeplinkHandler.handleDeeplink(incomingLink) } // Handle incoming app scheme deep link else if let urlContext = connectionOptions.urlContexts.first { let incomingLink = urlContext.url DeeplinkHandler.handleDeeplink(incomingLink) } }}
Deep link handler
The preceding code examples use an example DeeplinkHandler class. This example class is shown below and handles all types of links:
- Adjust branded links (full go.link links)
- Adjust short branded links (short go.link links)
- Adjust universal links (adj.st links)
- Non-Adjust universal links (example.com links)
- App scheme deep links (example:// links)
The class performs the following tasks:
- The class uses Adjust’s
processAndResolveDeeplink
method, which sends the deep link to Adjust’s servers to accomplish two things:
- Record the deep link click for attribution purposes.
- If the deep link is an Adjust short branded link, respond with the corresponding full URL. Otherwise, respond with the original link.
- After processing, the class parses the link and navigates to the appropriate screen. This part of the code is specific to each app. Your app has to implement its own logic for handling deep links and opening the corresponding content. Your deep link handling has to meet the following key requirements:
- Your app should treat Adjust branded links the same as other universal links, such as your own. For example, the following links should navigate to the same screen in your app:
- Adjust branded link:
https://example.go.link/summer-clothes?promo=beach
- Your universal link:
https://www.example.com/summer-clothes?promo=beach
- Adjust branded link:
- In cases where iOS doesn’t support universal links, Adjust automatically converts them to app scheme deep links. Additionally, Adjust’s servers convert all deferred deep links to app scheme deep link format. Therefore it’s crucial for the app to handle universal links and app scheme deep links equivalently. For example, the following links should navigate to the same screen in your app:
- Adjust branded link:
https://example.go.link/summer-clothes?promo=beach
- App scheme deep link:
example://summer-clothes?promo=beach
- Adjust branded link:
import Adjust// import SwiftUI and/or UIKit
class DeeplinkHandler { static func handleDeeplink(_ incomingLink: URL) { // Send incoming deep link to Adjust's servers for attribution // and retrieve full URL if short branded link. // If not, retrieve original link. let deeplink = ADJDeeplink(deeplink: incomingLink) Adjust.processAndResolveDeeplink(deeplink) { processedLinkString in guard let processedLink = URL(string: processedLinkString) else { return }
// Extract path, query items, and fragment from the processed link. guard let components = URLComponents( url: processedLink, resolvingAgainstBaseURL: true ) else { return }
// For app scheme deep links, set path = host + path var path: String if let scheme = processedLink.scheme, scheme == "http" || scheme == "https" { path = components.path } else { path = (components.host ?? "") + components.path if !path.isEmpty && !path.hasPrefix("/") { path = "/" + path } }
let queryItems = components.queryItems ?? [] // Parse query parameters into a dictionary for easier access let params = queryItems.reduce(into: [String: String]()) { result, item in result[item.name] = item.value } let fragment = components.fragment
// Implement the navigation or other app-specific logic based on // the deep link components. DispatchQueue.main.async { // Example of navigating based on the path or other components. // Replace with your actual navigation logic. switch path { case "/product": if let productId = params["id"] { handleProduct(productId: productId) } case "/category": if let categoryName = params["name"] { handleCategory(category: categoryName) } case "/search": if let query = params["q"] { handleSearch(query: query) } default: print("Unhandled deep link path: \(path)") } } } }
private static func handleProduct(productId: String) { // Example UIKit implementation: // let productVC = ProductViewController(productId: productId) // navigationController.pushViewController(productVC, animated: true)
// Example SwiftUI implementation: // let productView = ProductView(productId: productId) // navigationPath.append(productView) // or: router.navigate(to: productView) }
private static func handleCategory(category: String) { // Example UIKit implementation: // let categoryVC = CategoryViewController(category: category) // navigationController.pushViewController(categoryVC, animated: true)
// Example SwiftUI implementation: // let categoryView = CategoryView(category: category) // navigationPath.append(categoryView) // or: router.navigate(to: categoryView) }
private static func handleSearch(query: String) { // Example UIKit implementation: // let searchVC = SearchViewController(searchQuery: query) // navigationController.pushViewController(searchVC, animated: true)
// Example SwiftUI implementation: // let searchView = SearchView(searchQuery: query) // navigationPath.append(searchView) // or: router.navigate(to: productView) }}
#import <Adjust/Adjust.h>#import "DeeplinkHandler.h"
@implementation DeeplinkHandler
+ (void)handleDeeplink:(NSURL *)incomingLink { // Send incoming deep link to Adjust's servers for attribution // and retrieve full URL if short branded link. // If not, retrieve original link. ADJDeeplink *deeplink = [[ADJDeeplink alloc] initWithDeeplink:incomingURL]; [Adjust processAndResolveDeeplink:deeplink withCompletionHandler:^(NSString *_Nonnull processedLinkString) { NSURL *processedLink = [NSURL URLWithString:processedLinkString]; if (!processedLink) return;
// Extract path, query items, and fragment from the processed link. NSURLComponents *components = [NSURLComponents componentsWithURL:processedLink resolvingAgainstBaseURL:YES];
// For app scheme deep links, set path = host + path NSString *path; if ([processedLink.scheme isEqualToString:@"http"] || [processedLink.scheme isEqualToString:@"https"]) { path = components.path; } else { path = [NSString stringWithFormat:@"%@%@", components.host ?: @"", components.path]; if (path.length > 0 && ![path hasPrefix:@"/"]) { path = [@"/" stringByAppendingString:path]; } }
NSArray<NSURLQueryItem *> *queryItems = components.queryItems ?: @[];
// Parse query parameters into a dictionary for easier access NSMutableDictionary<NSString *, NSString *> *params = [NSMutableDictionary dictionary]; for (NSURLQueryItem *item in queryItems) { params[item.name] = item.value; }
NSString *fragment = components.fragment;
// Implement the navigation or other app-specific logic based on // the deep link components. dispatch_async(dispatch_get_main_queue(), ^{ // Example of navigating based on the path or other components. // Replace with your actual navigation logic. if ([path isEqualToString:@"/product"]) { NSString *productId = params[@"id"]; if (productId) { ProductViewController *productVC = [[ProductViewController alloc] initWithProductId:productId]; [self navigateToViewController:productVC]; } } else if ([path isEqualToString:@"/category"]) { NSString *categoryName = params[@"name"]; if (categoryName) { CategoryViewController *categoryVC = [[CategoryViewController alloc] initWithCategory:categoryName]; [self navigateToViewController:categoryVC]; } } else if ([path isEqualToString:@"/search"]) { NSString *query = params[@"q"]; if (query) { SearchViewController *searchVC = [[SearchViewController alloc] initWithSearchQuery:query]; [self navigateToViewController:searchVC]; } } else { NSLog(@"Unhandled deep link path: %@", path); } }); }];}
+ (void)navigateToViewController:(UIViewController *)viewController { // Example navigation implementation: // UINavigationController *navigationController = [self // getNavigationController]; [navigationController // pushViewController:viewController animated:YES];}
@end