iOS Setup Guide

Last updated on Apr 04, 2026

iOS setup tutorial

Use this walkthrough to integrate the LinkMe iOS SDK into a SwiftUI or UIKit app. The goal is to reproduce the ExampleApp that ships in the SDK repo, then adapt it to your product.

Before you start

  • A LinkMe account with at least one workspace
  • An iOS bundle ID + associated team identifier
  • A LinkMe app configured with your bundle ID and (optionally) a branded domain

1. Create an app & grab keys

  1. Open the LinkMe portal → AppsCreate app.
  2. Enter the app name, bundle identifier, and (if needed) Apple Team ID.
  3. In App Settings → API Keys, generate an app key. Copy both appId and appKey—you will paste them into your code.
  4. Still in App Settings, toggle Pasteboard for Deferred Links if you want deterministic first-install attribution.

2. Install LinkMeKit

Swift Package Manager

  1. In Xcode choose File → Add Packages….
  2. Paste https://github.com/r-dev-limited/li-nk.me-ios-sdk and select tag v0.2.8.
  3. Add LinkMeKit to your main app target.
  4. Optional: open the sample found in the repo (ExampleApp folder) to see a complete implementation.

CocoaPods

Add LinkMeKit to your Podfile and run pod install:

pod 'LinkMeKit', '~> 0.2.8'

Use the latest published LinkMeKit pod matching the current SDK release tag (0.2.8 at time of writing).

3. Configure the SDK

Initialize LinkMe as soon as your app launches. Point baseUrl at either your branded domain or https://li-nk.me.

import LinkMeKit

@main
struct DemoApp: App {
  init() {
    LinkMe.shared.configure(config: .init(
      baseUrl: URL(string: "https://links.yourco.com")!,
      appId: ProcessInfo.processInfo.environment["LINKME_APP_ID"]!,
      appKey: ProcessInfo.processInfo.environment["LINKME_APP_KEY"],
      sendDeviceInfo: true,
      includeVendorId: true,
      includeAdvertisingId: false,
      debug: _isDebugAssertConfiguration()
    ))
  }

  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

Enable Associated Domains in your target capabilities and add applinks:links.yourco.com. LinkMe hosts the AASA file automatically once your domain is connected.

Required: This setup is mandatory for LinkMe on iOS. If Associated Domains and URL schemes are not configured, deep links will not open your app correctly.

Manual deep-link config mapping

Use these values for your iOS deep-link setup:

{
  "hosts": ["links.yourco.com"],
  "associatedDomains": ["links.yourco.com"],
  "schemes": ["yourapp"]
}

What each field does and why it must be set:

  • hosts: your HTTPS deep-link domain(s). iOS uses this domain for universal links.
  • associatedDomains: domain allowlist for iOS universal links. This must match your Associated Domains entitlement.
  • schemes: fallback custom URL scheme(s) used when universal links are unavailable or for explicit scheme opens.

Why this is required:

  • Without hosts / associatedDomains, iOS cannot validate your app for universal links on that domain.
  • Without schemes, scheme-based opens (for example yourapp://...) will not resolve into your app.
  • If these are missing or mismatched, links open in Safari or fail to route as expected.

add the same values manually in iOS:

  • hosts / associatedDomains → Xcode Signing & Capabilities → Associated Domains:
applinks:links.yourco.com
  • schemesInfo.plist URL types:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>yourapp</string>
    </array>
  </dict>
</array>

4. Handle direct and deferred links

Connect LinkMe to your SwiftUI or UIKit lifecycle.

struct ContentView: View {
  @State private var message = "Waiting for link"

  var body: some View {
    Text(message)
      .onOpenURL { url in LinkMe.shared.handle(url: url) }
      .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in
        LinkMe.shared.handle(userActivity: activity)
      }
      .task {
        LinkMe.shared.getInitialLink { initial in
          if let initial {
            message = "Opened via \(initial.path)"
          } else {
            LinkMe.shared.claimDeferredIfAvailable { deferred in
              if let deferred {
                message = "Deferred match \(deferred.path)"
              }
            }
          }
        }
      }
  }
}

Add a listener if you expect multiple incoming links while the app stays in memory:

let unsubscribe = LinkMe.shared.addListener { payload in
  routeUser(to: payload)
}

Track lifecycle events when helpful:

LinkMe.shared.track(event: "open")
LinkMe.shared.setAdvertisingConsent(true) // after ATT / consent UI

5. Test with the example app

The SDK repo ships with /ExampleApp, a runnable SwiftUI sample. Update ExampleApp/Configuration/linkme.env with your keys, run on device/simulator, and click a LinkMe short link to verify direct and deferred flows. Use this app as a reference when wiring your production code.

Next steps