Skip to content

MovableInk SDK with AppsFlyer

If you use AppsFlyer for deeplinking, and would like to use an MI Link as the deeplink value for a OneLink, you can do that! You'll just need to ask the MovableInk SDK to handle the url after AppsFlyer has unwrapped the OneLink.

You can also use OneLinks as the clickthrough URL of your MI Link. You'll just do the opposite and ask the AppsFlyer SDK to handle the OneLink after the MovableInk SDK has unwrapped the MI Link.

Here are examples of how you could achieve this.

In OneLink Management, when creating a new link, we're adding an MI Link as the Deep link value:

AppsFlyer_to_MI-Link

In your code, make sure that you DO NOT add your OneLink domain to the movable_ink_universal_link_domains list. Asking the MovableInk SDK to handle OneLink URLs will not work.

Instead, you'll need to let the AppsFlyer SDK resolve the OneLink, then pass the deep link value to the MovableInk SDK.

// MARK: - AppsFlyerLib - DeepLinkDelegate

/// This method is called by AppsFlyerLib when it resolves a deeplink
func didResolveDeepLink(_ result: DeepLinkResult) {
  // Attempt to grab the deeplinkValue from the resolved OneLinK
  guard let deeplink = result.deepLink, let value = deeplink.deeplinkValue else {
    debugPrint("AppsFlyer - Deeplink not found")
    debugPrint(result)
    return
  }

  // MI Links are URLs and can be able to be converted to a URL object
  //
  // https://mi.example.com/p/rpm/abcdefg012345/url
  if let url = URL(string: value) {
    // Ask MovableInk SDK to handle the URL if it can
    switch MIClient.handleUniversalLink(url: url) {
    case true:
      // break or return early here
      // handleUniversalLink(url:) will call your deeplink handler where you called MIClient.start
      return

    case false:
      // If the MovableInk SDK can't handle it, then it must be handled by you
    }
  }

  // deeplinkValue is not a URL here, and must be handled by you
}

Resolving without MovableInk SDK

If you prefer to not use the MovableInk SDK; AppsFlyer also has a package that can resolve MovableInk Links. You can find out more on their Github.

There's also an example of how to manually resolve MovableInk Links if you prefer to not have a dependency: Resolve without SDK

Example

When AppsFlyer resolves the OneLink, it will call didResolveDeeplink(_:) which is part of the DeepLinkDelegate. Here we can use AppsFlyers URLResolver to resolve MovableInk Links.

You can find URLResolver on their Github.

import AppsFlyerLib
import AppsFlyerURLResolver

...

func didResolveDeepLink(_ result: DeepLinkResult) {
  if result.status == .found {
    // Ask the AppsFlyerURLResolver package to resolve the
    // incoming link
    URLResolver().resolve(url: result.deepLink?.deeplinkValue) { value in
      guard let value else { debugPrint("The URL is: nil"); return }

      guard let url = URL(string: value) else { 
        debugPrint("The value was not URL coercible")
        return
      }

      // url is the resolved clickthrough link which you 
      // can now use to deeplink to the correct page
    }
  }
}

If you are using Braze for push notifications or in app messages, make sure to select Deep Link Into Application for the on click behavior and replace https:// with your app scheme:

https://movableink.onelink.me/LAqV/3t2m11m1 ->

my-app-scheme://movableink.onelink.me/LAqV/3t2m11m1

Here, we're adding a OneLink as the clickthrough URL for a Block:

MI-Link_to_AppsFlyer

In your code, make sure that you DO NOT add your OneLink domain to the movable_ink_universal_link_domains list. Asking the MovableInk SDK to handle OneLink URLs will not work.

When the MovableInk SDK resolves the MI Link, it'll give you the OneLink, you can then ask AppsFlyer to handle it.

MIClient.start { result in 
  switch result {
  case let .success(url):
    guard let url = URL(string: url) else { return }

    // Check if the URL is your OneLink
    // then ask AppsFlyer to handle it
    if let components = URLComponents(url: url, resolvingAgainstBaseURL: false), 
      components.host == "example.onelink.me" {
      AppsFlyer.shared().handleOpen(url)
      return
    }

    // url is not an AppsFlyer OneLink here
    // handle it manually

  default:
    break
  }
}