adstage
行動 SDK深層連結

iOS

AdStage DeepLink 整合指南(iOS)

目錄

  1. 概覽
  2. 專案設定
  3. Info.plist 設定
  4. AppDelegate 設定
  5. 深層連結接收處理
  6. 建立深層連結
  7. 進階功能
  8. 疑難排解

概覽

AdStage DeepLink SDK 提供以下功能:

  • 即時深層連結:透過 URL Scheme、Universal Links 立即處理
  • 延遲深層連結:應用程式安裝後首次啟動時自動還原
  • 動態深層連結建立:透過伺服器 API 建立可追蹤的連結
  • 歸因追蹤:以 UTM 參數為基礎的行銷分析

專案設定

CocoaPods 設定

Podfile

platform :ios, '15.0'
 
target 'YourApp' do
  use_frameworks!
  
  # AdStage SDK
  pod 'AdapterAdStage', '3.0.11'
end
 
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
    end
  end
end

安裝:

pod install

Info.plist 設定

1. URL Scheme 設定

於 Info.plist 中新增:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLName</key>
        <string>com.example.myapp</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myapp</string>
        </array>
    </dict>
</array>

於 Info.plist 中新增:

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:go.myapp.com</string>
    <string>applinks:go.adstage.net</string>
</array>

Xcode 設定:

  1. 選擇 Signing & Capabilities 分頁
  2. 點擊 + Capability
  3. 新增 Associated Domains
  4. 新增網域:
    • applinks:go.myapp.com
    • applinks:go.adstage.net

3. Apple App Site Association 檔案

部署至伺服器:https://go.myapp.com/.well-known/apple-app-site-association

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAM_ID.com.example.myapp",
        "paths": ["*"]
      }
    ]
  }
}

注意事項:

  • 沒有副檔名(請勿加上 .json)
  • Content-Type:application/json
  • 必須使用 HTTPS
  • 置於根路徑或 .well-known 資料夾

4. 必要權限設定

<!-- 網路通訊 -->
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
</dict>
 
<!-- 背景模式(選用) -->
<key>UIBackgroundModes</key>
<array>
    <string>fetch</string>
    <string>remote-notification</string>
</array>

AppDelegate 設定

Swift - AppDelegate.swift

import UIKit
import AdapterAdStage
 
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    // MARK: - Application Lifecycle
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // 1. 初始化 AdStage SDK
        initializeAdStage()
        
        // 2. 設定深層連結監聽器
        setupDeepLinkListener()
        
        return true
    }
    
    // MARK: - AdStage Initialization
    
    private func initializeAdStage() {
        AdStageManager.shared.initialize(
            apiKey: "your-api-key-here",
            serverUrl: "https://api.adstage.app"  // 選用
        )
        
        print("✅ AdStage SDK 초기화 완료")
    }
    
    private func setupDeepLinkListener() {
        // 設定整合式深層連結監聽器
        DeepLinkManager.shared.setDeepLinkListener { [weak self] deepLinkData in
            guard let self = self else { return }
            
            print("""
            📱 딥링크 수신:
            - Short Path: \(deepLinkData.shortPath)
            - Link ID: \(deepLinkData.linkId)
            - Source: \(deepLinkData.source.description)
            - Parameters: \(deepLinkData.parameters)
            """)
            
            // 處理深層連結
            self.handleDeepLink(deepLinkData)
        }
    }
    
    // MARK: - Deep Link Handling
    
    private func handleDeepLink(_ data: DeepLinkData) {
        // 依來源分別處理
        switch data.source {
        case .realtime:
            print("🔗 실시간 딥링크 처리")
            handleRealtimeDeepLink(data)
            
        case .install:
            print("📦 디퍼드 딥링크 처리 (앱 설치 후 첫 실행)")
            handleDeferredDeepLink(data)
            
        case .unknown:
            print("❓ 알 수 없는 딥링크 소스")
        }
    }
    
    private func handleRealtimeDeepLink(_ data: DeepLinkData) {
        // 依參數切換畫面
        if let campaign = data.parameters["campaign"] {
            navigateToCampaign(campaign)
        } else if let promo = data.parameters["promo"] {
            navigateToPromotion(promo)
        } else {
            navigateToHome()
        }
    }
    
    private func handleDeferredDeepLink(_ data: DeepLinkData) {
        // 於導覽流程後處理,或立即處理
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
            self?.handleRealtimeDeepLink(data)
        }
    }
    
    // MARK: - Navigation
    
    private func navigateToCampaign(_ campaign: String) {
        print("🎯 캠페인 화면으로 이동: \(campaign)")
        
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            
            let storyboard = UIStoryboard(name: "Main", bundle: nil)
            if let campaignVC = storyboard.instantiateViewController(
                withIdentifier: "CampaignViewController"
            ) as? CampaignViewController {
                campaignVC.campaignId = campaign
                
                if let navController = self.window?.rootViewController as? UINavigationController {
                    navController.pushViewController(campaignVC, animated: true)
                }
            }
        }
    }
    
    private func navigateToPromotion(_ promo: String) {
        print("🎁 프로모션 적용: \(promo)")
        // 推廣處理邏輯
    }
    
    private func navigateToHome() {
        print("🏠 홈 화면으로 이동")
        // 前往首頁
    }
    
    // MARK: - URL Scheme Deep Link (iOS 8+)
    
    func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey : Any] = [:]
    ) -> Bool {
        
        print("📲 URL Scheme 딥링크 수신: \(url)")
        
        // 交由 AdStage 處理
        let handled = DeepLinkManager.shared.handleDeepLink(url)
        
        if handled {
            print("✅ AdStage가 딥링크를 처리했습니다")
            return true
        }
        
        // 處理其他 URL Scheme(例如 OAuth 回呼)
        if url.scheme == "myapp" {
            // 自訂處理
            return handleCustomScheme(url)
        }
        
        return false
    }
    
    // MARK: - Universal Links (iOS 9+)
    
    func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
    ) -> Bool {
        
        // 確認是否為 Universal Link
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let url = userActivity.webpageURL else {
            return false
        }
        
        print("🌐 Universal Link 수신: \(url)")
        
        // 交由 AdStage 處理
        let handled = DeepLinkManager.shared.handleUniversalLink(userActivity)
        
        if handled {
            print("✅ AdStage가 Universal Link를 처리했습니다")
            return true
        }
        
        // 處理其他 Universal Link
        return handleCustomUniversalLink(url)
    }
    
    // MARK: - Custom Handlers
    
    private func handleCustomScheme(_ url: URL) -> Bool {
        print("🔧 커스텀 URL Scheme 처리: \(url)")
        // 處理 OAuth、付款回呼等
        return false
    }
    
    private func handleCustomUniversalLink(_ url: URL) -> Bool {
        print("🔧 커스텀 Universal Link 처리: \(url)")
        // 處理一般網頁連結
        return false
    }
}

SwiftUI - App 結構

import SwiftUI
import AdapterAdStage
 
@main
struct MyApp: App {
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    // 處理 URL Scheme
                    print("📲 URL 수신: \(url)")
                    _ = DeepLinkManager.shared.handleDeepLink(url)
                }
        }
    }
}
 
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -> Bool {
        
        // 初始化 AdStage
        AdStageManager.shared.initialize(
            apiKey: "your-api-key-here",
            serverUrl: "https://api.adstage.app"
        )
        
        // 設定深層連結監聽器
        setupDeepLinkListener()
        
        return true
    }
    
    private func setupDeepLinkListener() {
        DeepLinkManager.shared.setDeepLinkListener { deepLinkData in
            print("📱 딥링크 수신: \(deepLinkData.shortPath)")
            // 處理邏輯
        }
    }
    
    func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
    ) -> Bool {
        // 處理 Universal Link
        return DeepLinkManager.shared.handleUniversalLink(userActivity)
    }
}

深層連結接收處理

1. 即時深層連結處理

import AdapterAdStage
 
class DeepLinkHandler {
    
    static let shared = DeepLinkHandler()
    
    func setupListener() {
        DeepLinkManager.shared.setDeepLinkListener { [weak self] deepLinkData in
            guard let self = self else { return }
            
            // 取出深層連結資料
            let shortPath = deepLinkData.shortPath
            let parameters = deepLinkData.parameters
            let source = deepLinkData.source
            
            print("""
            ✅ 딥링크 수신 완료
            - Short Path: \(shortPath)
            - Link ID: \(deepLinkData.linkId)
            - Source: \(source.description)
            - Event Type: \(deepLinkData.eventType)
            """)
            
            // 取出 UTM 參數
            let utmParams = deepLinkData.getUtmParameters()
            print("📊 UTM Parameters: \(utmParams)")
            
            // 取出自訂參數
            let customParams = deepLinkData.getCustomParameters()
            print("🔧 Custom Parameters: \(customParams)")
            
            // 處理商業邏輯
            self.processDeepLink(deepLinkData)
        }
    }
    
    private func processDeepLink(_ data: DeepLinkData) {
        // 依參數分支處理
        if let campaign = data.getParameter("campaign") {
            handleCampaignDeepLink(campaign, data: data)
        } else if let productId = data.getParameter("product_id") {
            handleProductDeepLink(productId, data: data)
        } else if let promo = data.getParameter("promo") {
            handlePromoDeepLink(promo, data: data)
        } else {
            handleDefaultDeepLink(data)
        }
    }
    
    private func handleCampaignDeepLink(_ campaign: String, data: DeepLinkData) {
        print("🎯 캠페인 딥링크: \(campaign)")
        
        DispatchQueue.main.async {
            // 前往廣告活動畫面
            NotificationCenter.default.post(
                name: .navigateToCampaign,
                object: nil,
                userInfo: ["campaign": campaign, "data": data]
            )
        }
    }
    
    private func handleProductDeepLink(_ productId: String, data: DeepLinkData) {
        print("🛍️ 상품 딥링크: \(productId)")
        
        DispatchQueue.main.async {
            NotificationCenter.default.post(
                name: .navigateToProduct,
                object: nil,
                userInfo: ["productId": productId]
            )
        }
    }
    
    private func handlePromoDeepLink(_ promo: String, data: DeepLinkData) {
        print("🎁 프로모션 딥링크: \(promo)")
        
        // 自動套用推廣碼
        applyPromoCode(promo)
    }
    
    private func handleDefaultDeepLink(_ data: DeepLinkData) {
        print("📋 기본 딥링크 처리")
        
        DispatchQueue.main.async {
            // 前往首頁
            NotificationCenter.default.post(name: .navigateToHome, object: nil)
        }
    }
    
    private func applyPromoCode(_ code: String) {
        // 推廣套用邏輯
        print("프로모션 코드 적용: \(code)")
    }
}
 
// 定義 Notification 名稱
extension Notification.Name {
    static let navigateToCampaign = Notification.Name("navigateToCampaign")
    static let navigateToProduct = Notification.Name("navigateToProduct")
    static let navigateToHome = Notification.Name("navigateToHome")
}

2. 延遲深層連結(自動處理)

// 延遲深層連結會在 AdStageManager.initialize() 時自動處理。
// 無須另行實作!
 
// 初始化時會自動:
// 1. 收集裝置指紋
// 2. 向伺服器發出比對請求
// 3. 若有已儲存的深層連結,則自動呼叫 onDeepLinkReceived
 
// 延遲深層連結未提供手動觸發 API,會在 initialize() 之後自動處理。
// 比對結果會透過上方註冊的 setDeepLinkListener 回呼傳遞。

3. 依來源處理

func handleDeepLink(_ data: DeepLinkData) {
    switch data.source {
    case .realtime:
        print("🔗 실시간 딥링크 - 앱 실행 중 수신")
        // 可立即切換畫面
        navigateImmediately(data)
        
    case .install:
        print("📦 디퍼드 딥링크 - 앱 설치 후 첫 실행")
        // 於導覽流程後處理,或延後處理
        showOnboardingThenNavigate(data)
        
    case .unknown:
        print("❓ 알 수 없는 소스")
        handleAsDefault(data)
    }
}
 
private func showOnboardingThenNavigate(_ data: DeepLinkData) {
    // 導覽流程完成後處理
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
        self?.navigateImmediately(data)
    }
}

建立深層連結

1. Builder 模式

import AdapterAdStage
 
class DeepLinkCreator {
    
    // 建立簡單的深層連結
    func createSimpleDeepLink() {
        AdStageManager.shared.createDeepLinkBuilder()
            .setName("여름 프로모션")
            .setDescription("2024년 여름 시즌 프로모션")
            .setChannel("google-ads")
            .setCampaign("summer2024")
            .addParameter(key: "promo", value: "SUMMER20")
            .create { [weak self] deepLinkInfo, error in
                if let error = error {
                    print("❌ 딥링크 생성 실패: \(error.localizedDescription)")
                    return
                }
                
                guard let info = deepLinkInfo else {
                    print("❌ 딥링크 정보 없음")
                    return
                }
                
                print("""
                ✅ 딥링크 생성 완료
                - Short URL: \(info.shortUrl)
                - Short Path: \(info.shortPath)
                - Link ID: \(info.linkId)
                """)
                
                // 分享建立好的 URL
                self?.shareDeepLink(info.shortUrl)
            }
    }
    
    // 包含全部選項
    func createFullDeepLink() {
        AdStageManager.shared.createDeepLinkBuilder()
            // 基本資訊
            .setName("겨울 프로모션")
            .setDescription("2024-2025 겨울 시즌 프로모션")
            .setShortPath("WINTER24")  // 使用者指定的路徑
            
            // 追蹤參數
            .setChannel("facebook-ads")
            .setSubChannel("instagram")
            .setCampaign("winter2024")
            .setAdGroup("fashion-lovers")
            .setCreative("banner-001")
            .setContent("hero-image")
            .setKeyword("winter-sale")
            
            // Android 設定
            .setAndroidConfig(
                packageName: "com.example.myapp",
                appScheme: "myapp://promo/winter",
                webUrl: "https://example.com/promo/winter"
            )
            
            // iOS 設定
            .setIosConfig(
                appStoreId: "123456789",
                appScheme: "myapp://promo/winter",
                webUrl: "https://example.com/promo/winter"
            )
            
            // 網頁設定
            .setWebConfig(webUrl: "https://example.com/promo/winter")
            
            // 自訂參數
            .addParameter(key: "discount", value: "30")
            .addParameter(key: "promoCode", value: "WINTER30")
            .addParameter(key: "validUntil", value: "2025-03-31")
            
            .create { deepLinkInfo, error in
                if let error = error {
                    print("❌ 에러: \(error.localizedDescription)")
                    return
                }
                
                guard let info = deepLinkInfo else { return }
                print("✅ Short URL: \(info.shortUrl)")
            }
    }
    
    // 一次設定多個參數
    func createDeepLinkWithMultipleParams() {
        let parameters: [String: String] = [
            "campaign": "spring2024",
            "discount": "15",
            "promoCode": "SPRING15",
            "source": "email"
        ]
        
        AdStageManager.shared.createDeepLinkBuilder()
            .setName("봄 프로모션")
            .setChannel("email-marketing")
            .setParameters(parameters)
            .create { deepLinkInfo, error in
                // 處理
            }
    }
    
    // 分享功能
    private func shareDeepLink(_ url: String) {
        DispatchQueue.main.async {
            let text = """
            🎁 특별 프로모션 초대!
            
            이 링크를 통해 가입하면 5,000원 할인 쿠폰을 드립니다.
            \(url)
            """
            
            let activityVC = UIActivityViewController(
                activityItems: [text],
                applicationActivities: nil
            )
            
            if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
               let rootVC = windowScene.windows.first?.rootViewController {
                rootVC.present(activityVC, animated: true)
            }
        }
    }
}

2. async/await 方式

class AsyncDeepLinkCreator {
    
    func createDeepLink() async {
        do {
            let builder = AdStageManager.shared.createDeepLinkBuilder()
                .setName("신규 가입 이벤트")
                .setChannel("referral")
                .setCampaign("invite-friend")
                .addParameter(key: "referrer", value: "USER123")
                .addParameter(key: "bonus", value: "5000")
            
            let info = try await builder.createAsync()
            
            print("✅ 딥링크 생성 완료: \(info.shortUrl)")
            
            // 更新 UI
            await MainActor.run {
                self.updateUI(with: info.shortUrl)
            }
            
        } catch {
            print("❌ 딥링크 생성 실패: \(error.localizedDescription)")
            
            await MainActor.run {
                self.showError(error)
            }
        }
    }
    
    @MainActor
    private func updateUI(with url: String) {
        // 更新 UI
    }
    
    @MainActor
    private func showError(_ error: Error) {
        // 顯示錯誤
    }
}

3. Objective-C 相容方式

createDeepLinkBuilder() 與 DeepLinkBuilder 的鏈式方法、create(completion:) 皆已透過 @objc 公開,因此在 Objective-C 中也可直接使用。 你可以建立一個簡單的包裝器,讓回呼只取得 Short URL 字串。

// 可在 Objective-C 中使用的簡單包裝器
@objc class ObjCCompatibleDeepLinkCreator: NSObject {
    
    @objc func createSimpleDeepLink(name: String, completion: @escaping (String?, Error?) -> Void) {
        AdStageManager.shared.createDeepLinkBuilder()
            .setName(name)
            .create { info, error in
                completion(info?.shortUrl, error)
            }
    }
    
    @objc func createDeepLinkWithDescription(
        name: String,
        description: String,
        completion: @escaping (String?, Error?) -> Void
    ) {
        AdStageManager.shared.createDeepLinkBuilder()
            .setName(name)
            .setDescription(description)
            .create { info, error in
                completion(info?.shortUrl, error)
            }
    }
}

進階功能

1. 設定全域使用者屬性

以 UserAttributes 設定使用者資訊後,之後送出的事件會自動包含這些資訊。 setUserAttributes(_:) 以 UserAttributes 物件作為引數,所有欄位皆為選用值。

// 登入時
func onUserLogin(userProfile: UserProfile) {
    let userAttributes = UserAttributes(
        gender: userProfile.gender,
        country: userProfile.country,
        city: userProfile.city,
        age: "\(userProfile.age)",
        language: Locale.current.languageCode ?? "en"
    )
    AdStageManager.shared.setUserAttributes(userAttributes)
    
    print("✅ 사용자 정보 설정 완료")
}
 
// 登出時(以空屬性重設)
func onUserLogout() {
    AdStageManager.shared.setUserAttributes(UserAttributes())
    
    print("🚪 사용자 정보 초기화")
}

參考:裝置資訊(平台、機型、應用程式版本、OS 版本、IDFV/IDFA、ATT 狀態等) 由 SDK 在送出事件時自動收集並包含,因此無須另行設定。


疑難排解

檢查清單:

  • 確認 Associated Domains 設定
  • 確認已部署 apple-app-site-association 檔案
  • 確認使用 HTTPS
  • 確認 Team ID 與 Bundle ID 一致

驗證方式:

# 1. 確認檔案是否可存取
curl https://go.myapp.com/.well-known/apple-app-site-association
 
# 2. 確認 Apple CDN 快取
curl https://app-site-association.cdn-apple.com/a/v1/go.myapp.com

偵錯:

func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    
    print("""
    Universal Link Debug:
    - Activity Type: \(userActivity.activityType)
    - Webpage URL: \(userActivity.webpageURL?.absoluteString ?? "nil")
    - User Info: \(userActivity.userInfo ?? [:])
    """)
    
    return DeepLinkManager.shared.handleUniversalLink(userActivity)
}

2. URL Scheme 無法運作

確認事項:

func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
    
    print("""
    URL Scheme Debug:
    - URL: \(url)
    - Scheme: \(url.scheme ?? "nil")
    - Host: \(url.host ?? "nil")
    - Path: \(url.path)
    - Query: \(url.query ?? "nil")
    - Source App: \(options[.sourceApplication] ?? "nil")
    """)
    
    return DeepLinkManager.shared.handleDeepLink(url)
}

3. 延遲深層連結無法運作

原因:

  • 裝置指紋收集失敗
  • 伺服器比對失敗
  • 網路連線問題

確認:

// 延遲深層連結會在 initialize() 之後自動處理(無手動觸發 API)。
// 比對結果會透過 setDeepLinkListener 回呼傳遞,請在監聽器中確認記錄。
AdStageManager.shared.setDeepLinkListener { data in
    print("✅ 디퍼드 딥링크 수신: \(data)")
}

4. 應用程式位於背景時收不到深層連結

SceneDelegate 設定(iOS 13+):

import UIKit
import AdapterAdStage
 
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    var window: UIWindow?
    
    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let _ = (scene as? UIWindowScene) else { return }
        
        // 處理 URL Context
        if let urlContext = connectionOptions.urlContexts.first {
            _ = DeepLinkManager.shared.handleDeepLink(urlContext.url)
        }
        
        // 處理 User Activity
        if let userActivity = connectionOptions.userActivities.first {
            _ = DeepLinkManager.shared.handleUniversalLink(userActivity)
        }
    }
    
    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        if let url = URLContexts.first?.url {
            _ = DeepLinkManager.shared.handleDeepLink(url)
        }
    }
    
    func scene(
        _ scene: UIScene,
        continue userActivity: NSUserActivity
    ) {
        _ = DeepLinkManager.shared.handleUniversalLink(userActivity)
    }
}

5. 確認建置設定

Build Settings:

- Deployment Target: iOS 15.0 以上
- Swift Language Version: 5.0 以上
- Enable Bitcode: No (Xcode 14+ 已移除)

Info.plist 必要項目:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>myapp</string>
</array>

測試方式

1. URL Scheme 測試

於 Safari 中測試:

myapp://promo/summer
myapp://promo?campaign=summer&discount=20

於終端機中測試:

xcrun simctl openurl booted "myapp://promo/summer"

於 Safari 中測試:

https://go.myapp.com/ABCDEF

於「備忘錄」應用程式中測試:

  1. 於「備忘錄」應用程式中輸入連結
  2. 長按該連結
  3. 選擇「Open in [應用程式名稱]」

於終端機中測試:

xcrun simctl openurl booted "https://go.myapp.com/ABCDEF"

3. 確認記錄

// 確認深層連結接收狀況
DeepLinkManager.shared.setDeepLinkListener { deepLinkData in
    print("""
    ==========================================
    딥링크 수신 테스트
    ==========================================
    Short Path: \(deepLinkData.shortPath)
    Link ID: \(deepLinkData.linkId)
    Source: \(deepLinkData.source.description)
    Parameters:
    \(deepLinkData.parameters.map { "  - \($0.key): \($0.value)" }.joined(separator: "\n"))
    ==========================================
    """)
}

參考資料


目錄