LimeLink iOS SDK 1.0.0

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.0 is a breaking release with one incoming-link entry point and one result model.

View previous iOS SDK releases

Release availability

Swift Package Manager 1.0.0 is publicly available from the LimeLink binary repository. Use Swift Package Manager while CocoaPods 1.0.0 completes deployment; select CocoaPods after the CDN resolves it publicly.

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.0"
    )
]

Add the LimelinkIOSSDK product to the app target.

CocoaPods deployment status

After CocoaPods 1.0.0 becomes publicly resolvable, use:

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

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

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

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

LimeLinkResult contains:

FieldContract
deeplinkUrlRequired final URL and sole routing authority
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.

Always parse deeplinkUrl and exactly compare its scheme and host with an app-owned allowlist before navigation. The host app authorizes the final destination.

Manual deferred handling

LimeLinkSDK.shared.handleDeferredDeepLink { result, error in
    if let result {
        guard isAllowedDestination(result.deeplinkUrl) else { return }
        navigateTo(result.deeplinkUrl)
    } 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 0.4.1