LimeLink iOS SDK

Target SDK Version: 0.3.3 | iOS 12.0+ | Swift 5.0 | Xcode 14.0+

LimeLink iOS SDK provides Universal Link resolution, deferred deep links, and link event tracking through a binary XCFramework.

View previous iOS SDK releases


Requirements

ItemMinimum
iOS Deployment Target12.0
Swift5.0
Xcode14.0+
CocoaPods1.11.0+

Register the app in the LimeLink console, obtain an API key, and enable Associated Domains for the app target.

Binary Installation

Consumer releases are distributed as verified XCFramework binaries. The SDK source repository and manual source copying are not supported installation routes.

Swift Package Manager

In Xcode, select File > Add Package Dependencies and enter:

https://github.com/hellovelop/limelink-ios-sdk-binary.git

Select version 0.3.3, or add it to Package.swift:

dependencies: [
    .package(
        url: "https://github.com/hellovelop/limelink-ios-sdk-binary.git",
        from: "0.3.3"
    )
]

Then add the product to your app target:

.target(
    name: "YourApp",
    dependencies: [
        .product(name: "LimelinkIOSSDK", package: "limelink-ios-sdk-binary")
    ]
)

CocoaPods

platform :ios, '12.0'
use_frameworks!

target 'YourApp' do
  pod 'LimelinkIOSSDK', '~> 0.3.3'
end

Run pod install, then open the generated .xcworkspace.

Initialize the SDK

Initialize once during application launch:

import UIKit
import LimelinkIOSSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        _ = DeepLinkManager.shared

        let config = LimeLinkConfig(
            apiKey: "YOUR_API_KEY",
            loggingEnabled: false,
            deferredDeeplinkEnabled: true
        )
        LimeLinkSDK.initialize(config: config)
        return true
    }
}

Register a long-lived listener before initialization when possible so it can receive the automatic launch outcome immediately.

In Signing & Capabilities > Associated Domains, add:

applinks:limelink.org
applinks:*.limelink.org

For a custom domain, add its applinks: entry and provide a valid Apple App Site Association file.

AppDelegate

func application(
    _ application: UIApplication,
    continue userActivity: NSUserActivity,
    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL else {
        return false
    }

    LimeLinkSDK.shared.handleUniversalLink(url)
    return true
}

SceneDelegate

import LimelinkIOSSDK

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        if let activity = connectionOptions.userActivities.first,
           activity.activityType == NSUserActivityTypeBrowsingWeb,
           let url = activity.webpageURL {
            LimeLinkSDK.shared.handleUniversalLink(url)
        }
    }

    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let url = userActivity.webpageURL {
            LimeLinkSDK.shared.handleUniversalLink(url)
        }
    }

    func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) {
        if let url = contexts.first?.url {
            LimeLinkSDK.shared.handleUniversalLink(url)
        }
    }
}
import LimelinkIOSSDK

final class DeepLinkManager: NSObject, LimeLinkListener {
    static let shared = DeepLinkManager()

    private override init() {
        super.init()
        LimeLinkSDK.shared.addLinkListener(self)
    }

    func onDeeplinkReceived(result: LimeLinkResult) {
        guard let destination = result.resolvedUri else { return }
        // Route destination in your app.
    }

    func onDeferredDeepLinkNotFound() {
        // Normal outcome: continue the default launch flow.
    }

    func onDeeplinkError(error: LimeLinkError) {
        print("LimeLink error [\(error.code)]: \(error.message)")
    }
}

Listeners are weakly retained. Keep an app-wide listener alive, for example with static let shared. Public listener callbacks are delivered on the main thread.

Result fields

FieldDescription
originalUrlOriginal URL, when available
resolvedUriDestination URI resolved by LimeLink
queryParamsQuery parameters from the original URL
pathParamsParsed mainPath and optional subPath
isDeferredtrue for an install-time deferred result

With deferredDeeplinkEnabled: true, SDK initialization automatically attempts deferred resolution for an eligible first launch.

Manual usage:

LimeLinkSDK.shared.handleDeferredDeepLink { result, error in
    if let result {
        navigateTo(result.resolvedUri)
    } else if let error {
        print(error.message)
    } else {
        // Normal no-match outcome.
    }
}

Deferred matching uses the app bundle identifier and bounded device context. Advertising identifiers are not required, and raw IP is not included in the SDK request body.

Stats Tracking

Resolved Universal Links are tracked automatically. To track a link explicitly:

if let url = URL(string: resolvedUri) {
    LimeLinkSDK.shared.trackLinkStatus(url: url)
}

Objective-C

Import the generated binary module interface:

#import <LimelinkIOSSDK/LimelinkIOSSDK-Swift.h>

Initialize and handle a Universal Link through the public SDK facade:

LimeLinkConfig *config = [[LimeLinkConfig alloc] initWithApiKey:@"YOUR_API_KEY"
                                                        baseUrl:@"https://limelink.org/"
                                                 loggingEnabled:NO
                                        deferredDeeplinkEnabled:YES];
[LimeLinkSDK initializeWithConfig:config];

[[LimeLinkSDK shared] handleUniversalLink:url];

Use LimeLinkListener for results. The removed UniversalLinkHandlerBridge is not part of the 0.3.3 consumer API.

Public API

APIPurpose
LimeLinkSDK.initialize(config:)Initialize once
addLinkListener(_:)Register result callbacks
removeLinkListener(_:)Remove callbacks
handleUniversalLink(_:)Resolve a Universal Link
handleDeferredDeepLink(completion:)Explicitly check deferred resolution
trackLinkStatus(url:)Explicitly send link stats

Use the LimeLinkSDK facade and public configuration/result models. Resolver services, URL parsers, request models, and state management are internal implementation details.

Migrating to 0.3.3

Troubleshooting

SDK not initialized

Call LimeLinkSDK.initialize(config:) before forwarding links or requesting deferred resolution.

  1. Verify Associated Domains and the AASA file.
  2. Reinstall the app after changing Associated Domains.
  3. Test by tapping a link from another app; typing it into Safari does not trigger a Universal Link.
  4. Confirm AppDelegate or SceneDelegate forwards the URL.

Deferred result is not delivered

  1. Confirm deferred handling is enabled.
  2. Confirm the app bundle identifier matches the registered LimeLink application.
  3. Keep the listener alive and register it early.
  4. Treat onDeferredDeepLinkNotFound() as a successful resolution with no match.
  5. Retry transport failures on a later launch rather than treating them as no-match.

CocoaPods cannot find the module

Open the .xcworkspace, clean Derived Data, and confirm the selected pod version is 0.3.3 or later.