LimeLink iOS SDK 1.0.1

iOS 12.0+ · Swift 5.0 · Xcode 14.0+

LimeLink iOS SDK handles direct links, Universal Links, deferred deep links, and explicit view tracking through a binary XCFramework. Version 1.0.1 delivers unresolved Universal Links through the unified success callback with a nullable destination.

View previous iOS SDK releases

Release availability

Swift Package Manager and CocoaPods 1.0.1 are publicly available.

Before you start

  1. Register the iOS Application in a LimeLink Project.
  2. Copy the canonical Project UUID, a public resource identifier suitable for app configuration.
  3. Configure Associated Domains and any app-owned callback schemes.
  4. Define an exact allowlist of destination schemes and HTTPS hosts.

Install

Swift Package Manager

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

Add the LimelinkIOSSDK product to the app target.

CocoaPods

source 'https://cdn.cocoapods.org/'
platform :ios, '12.0'
pod 'LimelinkIOSSDK', '~> 1.0.1'

Do not use Git, path, source, or local-podspec fallback as a production installation route.

Initialize

Register a strongly retained listener early, then initialize once during launch:

import LimelinkIOSSDK

// Retain and register the listener before initialization starts Deferred lookup.
_ = DeepLinkManager.shared

let config = LimeLinkConfig(
    projectId: "550e8400-e29b-41d4-a716-446655440000",
    loggingEnabled: false
)
LimeLinkSDK.initialize(config: config)

Automatic deferred lookup runs for every eligible installation.

Forward Universal Links through the source-neutral API:

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.handleIncomingLink(url)
    return true
}

For scenes, forward cold URLs from scene(_:willConnectTo:options:) and warm URLs from scene(_:continue:). Registered app-owned custom schemes can also enter handleIncomingLink(_:); the app remains responsible for deciding which lifecycle paths it forwards.

Pre-initialization links use a process-memory capacity-10 FIFO. Direct and Universal duplicates with the same source and exact inbound URL are suppressed while pending/in flight and for five seconds after success. Processing is independent, so callback order can differ from ingress order.

Receive results

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.deeplinkUrl ?? result.originalUrl,
              isAllowedDestination(destination) else { return }
        navigateTo(destination)
    }

    func onDeferredDeepLinkNotFound() {
        // Normal live-only no-match outcome.
    }

    func onDeeplinkError(error: LimeLinkError) {
        showSafeFallback(error.code, error.message)
    }
}

LimeLinkResult contains:

FieldContract
deeplinkUrlNullable resolved app destination; nil when a Universal Link is unresolved or unregistered
sourcedirectDeepLink, universalLink, or deferredDeepLink
originalUrlNullable original inbound/server URL
isDeferredtrue only for Deferred results

All public callbacks run on the main thread. Successful results completed without a listener use a capacity-10, drop-oldest, process-memory FIFO and replay once to the first later listener. Errors and deferred not-found outcomes are live-only.

For a resolved result, route deeplinkUrl. For an unresolved Universal Link, deeplinkUrl is nil, originalUrl preserves the exact inbound HTTPS URL, source is universalLink, and no separate error callback is emitted. If the app chooses browser fallback, use deeplinkUrl ?? originalUrl, then parse and exactly compare the selected URL's scheme and host with an app-owned allowlist before navigation.

Manual deferred handling

LimeLinkSDK.shared.handleDeferredDeepLink { result, error in
    if let result,
       let destination = result.deeplinkUrl ?? result.originalUrl {
        guard isAllowedDestination(destination) else { return }
        navigateTo(destination)
    } else if let error {
        showSafeFallback(error.code, error.message)
    } else {
        // Normal not-found result.
    }
}

Matched, not-found, and failed outcomes reach both the completion and current listener exactly once; their relative order is unspecified. Choose one channel as navigation owner.

Explicit stats

Dynamic Lookup already owns lookup attribution. Use trackLinkStatus(url:) only for a separate app-owned view event; it is best effort and should not duplicate a Universal Link event.

Privacy

The XCFramework includes an SDK-owned privacy manifest in every slice. The app remains responsible for its own required-reason APIs, data practices, third-party disclosures, and final merged privacy report.

Migrating from 1.0.0

Migrating from 0.4.1