์š”์•ฝ: ํ†ตํ•ฉ ๋”ฅ๋งํ‚น(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.

์ˆœ์„œ

Android UDL flow!

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

  1. ์‚ฌ์šฉ์ž๊ฐ€ ์›๋งํฌ ๋งํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์„ค์น˜ํ•œ ๊ฒฝ์šฐ, ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๋งํฌ๋‚˜ URI ์Šคํ‚ด์ด ์•ฑ์„ ์—ฝ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์„ค์น˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, ์•ฑ ์Šคํ† ์–ด๋กœ ๋ฆฌ๋””๋ ‰์…˜๋˜๊ณ , ๋‹ค์šด๋กœ๋“œ ํ›„์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์—ฝ๋‹ˆ๋‹ค.
  2. ์—ด๋ฆฐ ์•ฑ์ด ์•ฑ์Šคํ”Œ๋ผ์ด์–ด SDK๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  3. AppsFlyer SDK๋Š” UDL API๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  4. UDL API๋Š” AppsFlyer ์„œ๋ฒ„์—์„œ ์›๋งํฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  5. The UDL API calls back the onDeepLinking() ๊ฐœ๋ฐœ์ž๊ฐ€ DeepLinkingListener class.
  6. The onDeepLinking() method gets a DeepLinkResult object.
  7. The DeepLinkResult object includes:
    • ์ƒํƒœ(์ฐพ์Œ/์ฐพ์„ ์ˆ˜ ์—†์Œ/์˜ค๋ฅ˜)
    • A DeepLink object that carries the deep_link_value and deep_link_sub1-10 ์›๋ง์˜ ์ฃผ์š” ๋ชฉํ‘œ์ธ ํŠน์ • ์•ฑ ๋‚ด ํ™œ๋™์œผ๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๋ผ์šฐํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

์„ ํ–‰ ์กฐ๊ฑด

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

๊ณ„ํš

When setting up OneLinks, the marketer uses parameters to create the links, and the developer customizes the behavior of the app based on the values received. It's 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. ๋ฉ”์„œ๋“œ(from)๋ฅผ subscribeForDeepLink() ์‚ฌ์šฉํ•˜์—ฌ AppsFlyerLib์ธํ„ฐํŽ˜์ด์Šค ๋ฆฌ์Šค๋„ˆ๋ฅผ DeepLinkListener ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฐ์ฒด์— ๋”ฅ๋งํฌ ์ •๋ณด์™€ ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๊ฐ€ onDeepLinking().
    onDeepLinking() ํฌํ•จ๋œ ์ธ์ˆ˜๋กœ ํ—ˆ์šฉํ•˜๋Š” DeepLinkResult object.
  3. Use getStatus() to query whether the deep linking match is found.
  4. For when the status is an error, call getError() and run your error flow.
  5. For when the status is found, use getDeepLink() to retrieve the DeepLink object.
    The DeepLink ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•˜์—ฌ ์ž˜ ์•Œ๋ ค์ง„ ์›๋งํฌ ํ‚ค(์˜ˆ: nginx)์—์„œ ๊ฐ’์„ ์‰ฝ๊ฒŒ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก getDeepLinkValue().
  6. Use getDeepLinkValue() to retrieve the deep_link_value.
  7. Use getStringValue("deep_link_sub1") to retrieve deep_link_sub1. Do the same for deep_link_sub2-10 parameters, changing the string value as required.
  8. 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.

๐Ÿ“˜

์ฐธ๊ณ 

onDeepLinking is not called when the app is running in the background and Application LaunchMode is not standard.
To correct this, call setIntent(intent) method to set the intent value inside the overridden method onNewIntent if the application is using a non-standard LaunchMode.

       import android.content.Intent;
       ...
       ...
       ...
       @Override
       protected void onNewIntent(Intent intent) 
       { 
          super.onNewIntent(intent);     
          setIntent(intent);
       }

Supporting legacy OneLink links

Legacy OneLink are links that don't contain the parameters recommended for UDL: deep_link_value and deep_link_sub1-10.
Usually these are links that already exist and are in use 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. In this case, it's recommended to add support in the UDL callback onDeepLinking for legacy parameters.
Java code example

Code example

appsflyer.subscribForDeepLink(new DeepLinkListen
    @Override
    public void onDeepLinking(@NonNull DeepLinkResult deepLinkResult) {
        DeepLinkResult.Status dlStatus = deepLinkResult.getStatus();
        if (dlStatus == DeepLinkResult.Status.FOUND) {
            Log.d(LOG_TAG, "Deep link found");
        } else if (dlStatus == DeepLinkResult.Status.NOT_FOUND) {
            Log.d(LOG_TAG, "Deep link not found");
            return;
        } else {
            // dlStatus == DeepLinkResult.Status.ERROR
            DeepLinkResult.Error dlError = deepLinkResult.getError();
            Log.d(LOG_TAG, "There was an error getting Deep Link data: " + dlError.toString());
            return;
        }
        DeepLink deepLinkObj = deepLinkResult.getDeepLink();
        try {
            Log.d(LOG_TAG, "The DeepLink data is: " + deepLinkObj.toString());
        } catch (Exception e) {
            Log.d(LOG_TAG, "DeepLink data came back null");
            return;
        }
        // An example for using is_deferred
        if (deepLinkObj.isDeferred()) {
            Log.d(LOG_TAG, "This is a deferred deep link");
        } else {
            Log.d(LOG_TAG, "This is a direct deep link");
        }
        
        // ** Next if statement is optional **
        // Our sample app's user-invite carries the referrerID in deep_link_sub2
        // See the user-invite section in FruitActivity.java
        if (dlData.has("deep_link_sub2")){
            referrerId = deepLinkObj.getStringValue("deep_link_sub2");
            Log.d(LOG_TAG, "The referrerID is: " + referrerId);
        } else {
            Log.d(LOG_TAG, "deep_link_sub2/Referrer ID not found");
        }
        // An example for using a generic getter
        String fruitName = "";
        try {
            fruitName = deepLinkObj.getDeepLinkValue();
            Log.d(LOG_TAG, "The DeepLink will route to: " + fruitName);
        } catch (Exception e) {
            Log.d(LOG_TAG, "Custom param fruit_name was not found in DeepLink data");
            return;
        }
        goToFruit(fruitName, deepLinkObj);
    }
});
AppsFlyerLib.getInstance().subscribeForDeepLink(object : DeepLinkListener{
    override fun onDeepLinking(deepLinkResult: DeepLinkResult) {
        when (deepLinkResult.status) {
            DeepLinkResult.Status.FOUND -> {
                Log.d(
                    LOG_TAG,"Deep link found"
                )
            }
            DeepLinkResult.Status.NOT_FOUND -> {
                Log.d(
                    LOG_TAG,"Deep link not found"
                )
                return
            }
            else -> {
                // dlStatus == DeepLinkResult.Status.ERROR
                val dlError = deepLinkResult.error
                Log.d(
                    LOG_TAG,"There was an error getting Deep Link data: $dlError"
                )
                return
            }
        }
        var deepLinkObj: DeepLink = deepLinkResult.deepLink
        try {
            Log.d(
                LOG_TAG,"The DeepLink data is: $deepLinkObj"
            )
        } catch (e: Exception) {
            Log.d(
                LOG_TAG,"DeepLink data came back null"
            )
            return
        }

        // An example for using is_deferred
        if (deepLinkObj.isDeferred == true) {
            Log.d(LOG_TAG, "This is a deferred deep link");
        } else {
            Log.d(LOG_TAG, "This is a direct deep link");
        }

        try {
            val fruitName = deepLinkObj.deepLinkValue
            Log.d(LOG_TAG, "The DeepLink will route to: $fruitName")
        } catch (e:Exception) {
            Log.d(LOG_TAG, "There's been an error: $e");
            return;
        }
    }
})

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

Testing deferred deep linking

Before you begin

  • Complete UDL integration
  • Register your testing device
  • Enable debug mode in the app
  • Make sure the app isn't installed on your device
  • Ask your marketer for a OneLink template.
    • It will look something like this: https://onelink-basic-app.onelink.me/H5hv.
    • This example uses the OneLink subdomain onelink-basic-app.onelink.me and the OneLink template ID H5hv

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, either to Google Play 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 Android Studio or any other IDE you use.
  4. UDL detects the deferred deep linking, matches the install to the click and retrieves the OneLink parameters to onDeepLinking callback.

Expected logs results

๐Ÿ“˜

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

  • SDK initialized:

    D/AppsFlyer_6.9.0: Initializing AppsFlyer SDK: (v6.9.0.126)
    
  • The following log refers to direct deep linking, and can be ignored in a deferred deep linking scenario:

    D/AppsFlyer_6.9.0: No deep link detected
    
  • UDL API starts:

    D/AppsFlyer_6.9.0: [DDL] start
    
  • UDL sends query to AppsFlyer to query a match with this install:

    D/AppsFlyer_6.9.0: [DDL] Preparing request 1
    ...
    I/AppsFlyer_6.9.0: call = https://dlsdk.appsflyer.com/v1.0/android/com.appsflyer.onelink.appsflyeronelinkbasicapp?af_sig=<>&sdk_version=6.9; size = 239 bytes; body = {
          ...
          TRUNCATED
          ...
    }
    
  • UDL got a response and calls onDeepLinking callback with status=FOUND and OneLink link data:

    D/AppsFlyer_6.9.0: [DDL] Calling onDeepLinking with:
      {"deepLink":"{\"campaign_id\":\"\",\"af_sub3\":\"\",\"match_type\":\"probabilistic\",\"af_sub1\":\"\",\"deep_link_value\":\"apples\",\"campaign\":\"\",\"af_sub4\":\"\",\"timestamp\":\"2022-12-06T11:47:40.037\",\"click_http_referrer\":\"\",\"af_sub5\":\"\",\"media_source\":\"\",\"af_sub2\":\"\",\"deep_link_sub1\":\"23\",\"is_deferred\":true}","status":"FOUND"}
    
    

Testing deep linking (Android App 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 Android App Link and retrieves the OneLink parameters to onDeepLinking 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)
    D/AppsFlyer_6.9.0: HTTP: [258990367] GET:https://onelink.appsflyer.com/shortlink-sdk/v2/H5hv?id=apples 
    
  • UDL calls onDeepLinking callback with status=FOUND and OneLink link data
    D/AppsFlyer_6.9.0: [DDL] Calling onDeepLinking with:
        {"deepLink":"{\"path\":\"\\\/H5hv\",\"scheme\":\"https\",\"link\":\"https:\\\/\\\/onelink-basic-app.onelink.me\\\/H5hv?deep_link_value=apples&deep_link_sub1=23\",\"host\":\"onelink-basic-app.onelink.me\",\"deep_link_sub1\":\"23\",\"deep_link_value\":\"apples\",\"is_deferred\":false}","status":"FOUND"}
    

๐Ÿ“˜

ํŒ

If when clicking an Android App Link the OS shows a Disambiguation Dialog or redirects to Google Play or a website, check whether the SHA256 signature is correct.

  1. Use adb to get the app signature on the device:
adb shell pm get-app-links <PACKAGE_NAME>

-2. Make sure the subdomain is verified.
adb verified!

  1. If the subdomain isn't verified, it shows 1024.
    adb verified!