์š”์•ฝ: ํ†ตํ•ฉ ๋”ฅ๋งํ‚น(UDL: Unified Deep Linking)์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ฑ์„ ์—ด์ž๋งˆ์ž ์•ฑ์˜ ํŠน์ • ์ธ์•ฑ ์•กํ‹ฐ๋น„ํ‹ฐ(์˜ˆ: ์•ฑ์˜ ํŠน์ • ํŽ˜์ด์ง€)์— ์ƒˆ ์‚ฌ์šฉ์ž ๋ฐ ๊ธฐ์กด ์‚ฌ์šฉ์ž๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“˜

UDL ํ”„๋ผ์ด๋ฒ„์‹œ ๋ณดํ˜ธ

For new users, the UDL method only returns parameters relevant to deferred deep linking: deep_link_value and deep_link_sub1-10. If you try to get any other parameters (media_source, campaign, af_sub1-5, etc.), they return null.

์ˆœ์„œ

iOS UDL flow!

์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

  1. ์‚ฌ์šฉ์ž๊ฐ€ ์›๋งํฌ ๋งํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์„ค์น˜ํ•œ ๊ฒฝ์šฐ, ์œ ๋‹ˆ๋ฒ„์„ค ๋งํฌ๋‚˜ URI ์Šคํ‚ด์ด ์•ฑ์„ ์—ฝ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์„ค์น˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์•ฑ ์Šคํ† ์–ด๋กœ ๋ฆฌ๋””๋ ‰์…˜๋˜๊ณ , ๋‹ค์šด๋กœ๋“œ ํ›„์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์—ฝ๋‹ˆ๋‹ค.
  2. ์—ด๋ฆฐ ์•ฑ์ด ์•ฑ์Šคํ”Œ๋ผ์ด์–ด SDK๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  3. AppsFlyer SDK๋Š” UDL API๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. UDL API๋Š” AppsFlyer ์„œ๋ฒ„์—์„œ ์›๋งํฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  5. The UDL API calls back the didResolveDeepLink() in the DeepLinkDelegate.
  6. The didResolveDeepLink() method gets a DeepLinkResult object.
  7. The DeepLinkResult object includes:
    • ์ƒํƒœ(์ฐพ์Œ/์ฐพ์„ ์ˆ˜ ์—†์Œ/์˜ค๋ฅ˜)
    • A DeepLink object that carries the deep_link_value and deep_link_sub1-10 parameters that the developer uses to route the user to a specific in-app activity, which is the main goal of OneLink.

์„ ํ–‰ ์กฐ๊ฑด

  • UDL์—๋Š” AppsFlyer ์•ˆ๋“œ๋กœ์ด๋“œ SDK V6.1 ์ด์ƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ณ„ํš

When setting up OneLink, the marketer uses parameters to create the links, and the developer customizes the behavior of the app based on the values received. It is the developer's responsibility to make sure the parameters are handled correctly in the app, for both in-app routing, and personalizing data in the link.

์›๋งํฌ๋ฅผ ๊ณ„ํšํ•˜๋Š” ๋ฐฉ๋ฒ•:

  1. URL์„ ํด๋ฆญํ•  ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐ”๋žŒ์งํ•œ ๋™์ž‘๊ณผ ๊ฐœ์ธ์  ๊ฒฝํ—˜์„ ๋งˆ์ผ€ํ„ฐ๋กœ๋ถ€ํ„ฐ ์–ป์Šต๋‹ˆ๋‹ค.
  2. Based on the desired behavior, plan the deep_link_value and other parameters that are needed to give the user the desired personal experience.
    • The deep_link_value is set by the marketer in the URL and used by the developer to redirect the user to a specific place inside the app. For example, if you have a fruit store and want to direct users to apples, the value of deep_link_value can be apples.
    • The deep_link_sub1-10 parameters can also be added to the URL to help personalize the user experience. For example, to give a 10% discount, the value of deep_link_sub1 can be 10.

๊ตฌํ˜„ํ•˜๊ธฐ

์„ ํƒํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ UDL API ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

  1. Assign the AppDelegate using self to AppsFlyerLib.shared().deepLinkDelegate.
  2. ๋‹ค์Œ์„ ํ—ˆ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค:
    • ๋‹ค์Œ์œผ๋กœ ์œ ๋‹ˆ๋ฒ„์„ค ๋งํฌ ์ง€์› continue.
    • ๋‹ค์Œ์„ ํ†ตํ•œ URI ์Šคํ‚ค๋งˆ ์ง€์› handleOpen.
  3. Create DeepLinkDelegate as an extension of AppDelegate.
  4. Add application functions to support Universal Links and URI schemes.
  5. In DeepLinkDelegate, make sure you override the callback function, didResolveDeepLink().
    didResolveDeepLink() accepts a DeepLinkResult object as an argument.
  6. Use DeepLinkResult.status to query whether the deep linking match is found.
  7. For when the status is an error, call DeepLinkResult.error and run your error flow.
  8. For when the status is found, use DeepLinkResult.deepLink to retrieve the DeepLink object.
    The DeepLink object contains the deep linking information arranged in public variables to retrieve the values from well-known OneLink keys, for example, DeepLink.deeplinkValue for deep_link_value.
  9. Use deepLinkObj.clickEvent["deep_link_sub1"] to retrieve deep_link_sub1. Do the same for deep_link_sub2-10 parameters, changing the string value as required.
  10. Once deep_link_value and deep_link_sub1-10 are retrieved, pass them to an in-app router and use them to personalize the user experience.

Supporting legacy OneLink links

Legacy OneLink links are links that don't contain the parameters recommended for Unified Deep Linking: deep_link_value and deep_link_sub1-10.
Usually these are links that already exist in the field when migrating from legacy methods to UDL.
News users using legacy links are handled by onConversionDataSuccess in the context of extended deferred deep linking.
UDL handles deep linking for existing users. It's recommended that you add support in the UDL callback didResolveDeepLink for legacy parameters.
Swift code example

Code example

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  ...
  AppsFlyerLib.shared().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 {
  AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
  return true
}

// Open URI-scheme for iOS 9 and above
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
  AppsFlyerLib.shared().handleOpen(url, options: options)
  return true
}

extension AppDelegate: DeepLinkDelegate {
    func didResolveDeepLink(_ result: DeepLinkResult) {
        var fruitNameStr: String?
        switch result.status {
        case .notFound:
            NSLog("[AFSDK] Deep link not found")
            return
        case .failure:
            print("Error %@", result.error!)
            return
        case .found:
            NSLog("[AFSDK] Deep link found")
        }
        
        guard let deepLinkObj:DeepLink = result.deepLink else {
            NSLog("[AFSDK] Could not extract deep link object")
            return
        }
        
        if deepLinkObj.clickEvent.keys.contains("deep_link_sub2") {
            let ReferrerId:String = deepLinkObj.clickEvent["deep_link_sub2"] as! String
            NSLog("[AFSDK] AppsFlyer: Referrer ID: \(ReferrerId)")
        } else {
            NSLog("[AFSDK] Could not extract referrerId")
        }        
        
        let deepLinkStr:String = deepLinkObj.toString()
        NSLog("[AFSDK] DeepLink data is: \(deepLinkStr)")
            
        if( deepLinkObj.isDeferred == true) {
            NSLog("[AFSDK] This is a deferred deep link")
        }
        else {
            NSLog("[AFSDK] This is a direct deep link")
        }
        
        fruitNameStr = deepLinkObj.deeplinkValue
        walkToSceneWithParams(fruitName: fruitNameStr!, deepLinkData: deepLinkObj.clickEvent)
    }
}
// User logic
fileprivate func walkToSceneWithParams(deepLinkObj: DeepLink) {
    let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true, completion: nil)
    guard let fruitNameStr = deepLinkObj.clickEvent["deep_link_value"] as? String else {
         print("Could not extract query params from link")
         return
    }
    let destVC = fruitNameStr + "_vc"
    if let newVC = storyBoard.instantiateVC(withIdentifier: destVC) {
       print("AppsFlyer routing to section: \(destVC)")
       newVC.deepLinkData = deepLinkObj
       UIApplication.shared.windows.first?.rootViewController?.present(newVC, animated: true, completion: nil)
    } else {
        print("AppsFlyer: could not find section: \(destVC)")
    }
}

โ‡ฒ Github ๋งํฌ: Swift

Testing deferred deep linking

Before you begin

The test link

You can use an existing OneLink link or ask your marketer to create a new one for testing. Both short and long OneLink URLs can be used.

Adding ad-hoc parameters to an existing link

  • Use only the domain and OneLink template of your link. For example: https://onelink-basic-app.onelink.me/H5hv.
  • Add OneLink parameters deep_link_value and deep_link_sub1-10 as expected by your application. The parameters should be added as query parameters.
    • ์˜ˆ: https://onelink-basic-app.onelink.me/H5hv?deep_link_value=apples&deep_link_sub1=23

Perform the test

  1. Click the link on your device.
  2. OneLink redirects you according to the link setup, to either the App Store or a website.
  3. Install the application.

    ์ค‘์š” ์ •๋ณด

    • If the application is still in development and not uploaded to the store yet, you see this image:
      drawing
    • Install the application from Xcode.
  4. UDL detects the deferred deep linking, matches the install to the click, and retrieves the OneLink parameters to didResolveDeepLink callback.

Expected logs results

๐Ÿ“˜

The following logs are available only when debug mode is enabled.

  • SDK initialized:
    [AppsFlyerSDK] [com.apple.main-thread] AppsFlyer SDK version 6.6.0 started build
    
  • UDL API starts:
    D/AppsFlyer_6.9.0: [DDL] start
    
  • UDL sends query to AppsFlyer to query a match with this install:
    [AppsFlyerSDK] [com.appsflyer.serial] [DDL] URL: https://dlsdk.appsflyer.com/v1.0/ios/id1512793879?sdk_version=6.6&af_sig=efcecc2bc95a0862ceaa7b62fa8e98ae1e3e022XXXXXXXXXXXXXXXX
    
  • UDL got a response and calls didResolveDeepLink callback with status=FOUND and OneLink link data:
    [AppsFlyerSDK] [com.appsflyer.serial] [DDL] Calling didResolveDeepLink with: {"af_sub4":"","click_http_referrer":"","af_sub1":"","click_event":{"af_sub4":"","click_http_referrer":"","af_sub1":"","af_sub3":"","deep_link_value":"peaches","campaign":"","match_type":"probabilistic","af_sub5":"","campaign_id":"","media_source":"","deep_link_sub1":"23","af_sub2":""},"af_sub3":"","deep_link_value":"peaches","campaign":"","match_type":"probabilistic","af_sub5":"","media_source":"","campaign_id":"","af_sub2":""}
    

Testing deep linking (Universal Links)

Before you begin

Create the test link

Use the same method as in deferred deep linking.

Perform the test

  1. Click the link on your device.
  2. UDL detects the Universal Link and retrieves the OneLink parameters to didResolveDeepLink callback.

Expected logs results

๐Ÿ“˜

The following logs are available only when debug mode is enabled.

  • If the link is a OneLink shortlink (e.g. https://onelink-basic-app.onelink.me/H5hv/apples):
    [AppsFlyerSDK] [com.apple.main-thread] NSUserActivity `webpageURL`: https://onelink-basic-app.onelink.me/H5hv/apples
    [AppsFlyerSDK] [com.appsflyer.serial] UniversalLink/Deeplink found:
    https://onelink-basic-app.onelink.me/H5hv/apples
    [AppsFlyerSDK] [com.appsflyer.serial] Shortlink found. Executing: https://onelink.appsflyer.com/shortlink-sdk/v2/H5hv?id=apples
    ...
    [AppsFlyerSDK] [com.appsflyer.serial]                        
    [Shortlink] OneLink:{
      c = test1;
      campaign = test1;
      "deep_link_sub1" = 23;
      "deep_link_value" = peaches;
      "is_retargeting" = true;
      "media_source" = SMS;
      pid = SMS;
    } 
    
  • UDL calls didResolveDeepLink callback with status=FOUND and OneLink link data:
    [AppsFlyerSDK] [com.appsflyer.serial] [DDL] Calling didResolveDeepLink with: {"af_sub4":null,"click_http_referrer":null,"af_sub1":null,"click_event":{"campaign":"test1","deep_link_sub1":"23","deep_link_value":"peaches","media_source":"SMS"},"af_sub3":null,"deep_link_value":"peaches","campaign":"test1","match_type":null,"af_sub5":null,"media_source":"SMS","campaign_id":null,"af_sub2":null}