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
- Register the iOS Application in a LimeLink Project.
- Copy the canonical Project UUID, a public resource identifier suitable for app configuration.
- Configure Associated Domains and any app-owned callback schemes.
- 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 incoming links
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:
| Field | Contract |
|---|---|
deeplinkUrl | Nullable resolved app destination; nil when a Universal Link is unresolved or unregistered |
source | directDeepLink, universalLink, or deferredDeepLink |
originalUrl | Nullable original inbound/server URL |
isDeferred | true 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
- Treat
deeplinkUrlas nullable. - Handle unresolved Universal Links as successful results and use the exact
originalUrlonly for an allowlisted browser fallback.
Migrating from 0.4.1
- Replace removed
handleUniversalLink(_:)withhandleIncomingLink(_:). - Replace
resolvedUriwith nullabledeeplinkUrl. - Remove
queryParamsandpathParams; parsedeeplinkUrlin the app when needed. - Use
sourceandoriginalUrlfor source-aware behavior. - Expect native capacity-10 success replay and exact-URL five-second deduplication.
- Keep automatic deferred lookup enabled and choose one completion/listener navigation owner.