Skip to content

Native iOS SDK for deep linking, mobile attribution, and conversion tracking.

License

Notifications You must be signed in to change notification settings

LinkForty/mobile-sdk-ios

Repository files navigation

LinkForty iOS SDK

Native iOS SDK for deep linking, mobile attribution, and conversion tracking.

Swift Version iOS Version License SPM Compatible

Features

  • Deferred Deep Linking: Match app installs to link clicks using privacy-compliant fingerprinting
  • Universal Links: Full support for iOS Universal Links (HTTPS deep links)
  • Custom URL Schemes: Handle custom app URL schemes
  • Event Tracking: Track in-app events and conversions
  • Offline Support: Queue events when offline with automatic retry
  • Privacy-First: No IDFA collection, complies with Apple's privacy requirements
  • Programmatic Link Creation: Create short links directly from your app
  • Zero Dependencies: Lightweight, no third-party dependencies
  • Swift-Native: 100% Swift, modern async/await APIs

Requirements

  • iOS 16.0+
  • Xcode 15.0+
  • Swift 5.9+

Installation

Swift Package Manager (Recommended)

Add the following to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/LinkForty/mobile-sdk-ios.git", from: "1.0.0")
]

Or in Xcode:

  1. File > Add Package Dependencies
  2. Enter: https://github.com/LinkForty/mobile-sdk-ios.git
  3. Select version and add to your target

CocoaPods

pod 'LinkFortySDK', '~> 1.0'

Carthage

github "LinkForty/mobile-sdk-ios" ~> 1.0

Quick Start

1. Initialize the SDK

In your AppDelegate.swift or @main App struct:

import LinkFortySDK

// In AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    Task {
        do {
            let config = LinkFortyConfig(
                baseURL: URL(string: "https://go.yourdomain.com")!,
                apiKey: "your-api-key", // Optional for self-hosted
                debug: true,
                attributionWindowHours: 168 // 7 days
            )
            try await LinkForty.shared.initialize(config: config)
        } catch {
            print("LinkForty initialization failed: \(error)")
        }
    }
    return true
}

2. Handle Deferred Deep Links (Install Attribution)

LinkForty.shared.onDeferredDeepLink { deepLinkData in
    if let data = deepLinkData {
        // User installed from a link - navigate to content
        print("Install attributed to: \(data.shortCode)")
        print("UTM Source: \(data.utmParameters?.source ?? "none")")

        // Navigate to the right content
        if let productId = data.customParameters?["productId"] {
            navigateToProduct(id: productId)
        }
    } else {
        // Organic install - no attribution
        print("Organic install")
    }
}

3. Handle Direct Deep Links (Universal Links)

First, enable Associated Domains in your Xcode project:

  1. Select your target > Signing & Capabilities
  2. Add "Associated Domains"
  3. Add domain: applinks:go.yourdomain.com

Then handle Universal Links:

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

    LinkForty.shared.handleDeepLink(url: url)
    return true
}

// Or in SwiftUI
.onOpenURL { url in
    LinkForty.shared.handleDeepLink(url: url)
}

// Register callback
LinkForty.shared.onDeepLink { url, deepLinkData in
    print("Deep link opened: \(url)")
    if let data = deepLinkData {
        print("Link data: \(data)")
        // Navigate using deep link path
        if let path = data.deepLinkPath {
            navigateToPath(path)
        }
    }
}

Server-side resolution: When the SDK is initialized, deep links are automatically resolved via the server to provide enriched data including deepLinkPath, appScheme, and linkId. If the server is unreachable, the SDK falls back to local URL parsing.

4. Track Events

// Track a simple event
try await LinkForty.shared.trackEvent(name: "button_clicked")

// Track event with properties
try await LinkForty.shared.trackEvent(
    name: "purchase",
    properties: [
        "product_id": "123",
        "amount": 29.99,
        "currency": "USD"
    ]
)

// Track revenue
try await LinkForty.shared.trackRevenue(
    amount: 29.99,
    currency: "USD",
    properties: ["product_id": "123"]
)

5. Create Links Programmatically

let result = try await LinkForty.shared.createLink(
    options: CreateLinkOptions(
        deepLinkParameters: ["route": "VIDEO_VIEWER", "id": "vid123"],
        title: "Check this out!",
        utmParameters: UTMParameters(source: "app", campaign: "share")
    )
)

print("Share this link: \(result.url)")
// e.g., "https://go.yourdomain.com/tmpl/abc123"

Note: Requires an API key in LinkFortyConfig. See API Reference for all options.

Advanced Usage

Self-Hosted LinkForty Core

If you're running your own LinkForty Core instance:

let config = LinkFortyConfig(
    baseURL: URL(string: "https://links.yourcompany.com")!,
    apiKey: nil, // No API key needed for self-hosted
    debug: false
)
try await LinkForty.shared.initialize(config: config)

Custom Attribution Window

let config = LinkFortyConfig(
    baseURL: URL(string: "https://go.yourdomain.com")!,
    attributionWindowHours: 24 // 1 day instead of default 7 days
)

Retrieve Install Data

if let installData = LinkForty.shared.getInstallData() {
    print("Short code: \(installData.shortCode)")
    print("UTM source: \(installData.utmParameters?.source ?? "none")")
}

if let installId = LinkForty.shared.getInstallId() {
    print("Install ID: \(installId)")
}

Event Queue Management

// Check queued events count
let count = LinkForty.shared.queuedEventCount

// Manually flush event queue
await LinkForty.shared.flushEvents()

// Clear event queue
LinkForty.shared.clearEventQueue()

Clear Data (for testing)

LinkForty.shared.clearData()

// Reset SDK to uninitialized state
LinkForty.shared.reset()

Universal Links Setup

1. Create AASA File

Your backend must serve an Apple App Site Association file at: https://go.yourdomain.com/.well-known/apple-app-site-association

Example:

{
  "applinks": {
    "apps": [],
    "details": [{
      "appID": "TEAM_ID.com.yourcompany.yourapp",
      "paths": ["*"]
    }]
  }
}

2. Configure Xcode

  1. Enable "Associated Domains" capability
  2. Add domain: applinks:go.yourdomain.com
  3. Handle Universal Links in AppDelegate (see Quick Start)

3. Test Universal Links

Use Apple's validation tool:

Or test manually:

  1. Create a link in LinkForty
  2. Open link in Safari on device
  3. Long press the link
  4. Verify "Open in YourApp" appears

Privacy & Security

Privacy-First Design

  • No IDFA: Does not collect Identifier for Advertisers
  • No Persistent IDs: Uses probabilistic fingerprinting only
  • Data Minimization: Collects only necessary attribution data
  • User Control: Provides clearData() for user data deletion
  • Privacy Manifest: Includes PrivacyInfo.xcprivacy file

Data Collected (for attribution only)

  • Device timezone
  • Device language
  • Screen resolution
  • iOS version
  • App version
  • User-Agent string

HTTPS Required

The SDK enforces HTTPS for all API endpoints (except localhost for testing).

Testing

Unit Tests

swift test

Or in Xcode: Cmd+U to run all tests

Integration Tests

See Tests/LinkFortySDKIntegrationTests/README.md for setup instructions.

Documentation

Example Apps

  • Basic Example - Simple SwiftUI app demonstrating all SDK features

Requirements

Backend

This SDK requires a running LinkForty backend:

  • LinkForty Core (open source): Self-host for free
  • LinkForty Cloud (SaaS): Managed service with advanced features

See: https://github.com/linkforty/core

Support

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Changelog

See CHANGELOG.md for version history.

License

LinkForty iOS SDK is available under the MIT license. See LICENSE for more info.

Related Projects


Made with ❤️ by the LinkForty team