Skip to main content
Linkrunner does not have a dedicated Unity SDK. This guide walks you through integrating the native Android and iOS SDKs into your Unity project using platform bridge plugins.

Prerequisites

  • Unity 2021.3 LTS or newer
  • Android: Android 5.0+ (API 21), Gradle 8.0+
  • iOS: iOS 15.0+, Xcode 14.0+, Swift 5.9+
  • A Linkrunner project token — get it from Dashboard → Documentation
Important assumptions in this guide:
  1. iOS requires a Swift bridging layer. The Linkrunner iOS SDK (LinkrunnerKit) is a pure Swift module — it does not inherit from NSObject and has no @objc annotations. Since Unity’s native plugin system uses C/Objective-C, we provide a Swift wrapper file (LinkrunnerUnityBridge.swift) that exposes @_cdecl C-callable functions which internally call the Swift SDK’s async methods.
  2. Android uses a Java-friendly callback wrapper. The Linkrunner Android SDK provides LinkrunnerJava, a callback-based wrapper around the Kotlin SDK. This avoids Kotlin coroutine interop issues (Result<T> mangling, Continuation type mismatches, Kotlin version conflicts) that prevent Java callers from using the suspend-based API directly.
  3. iOS SPM dependency must be re-added each time Unity regenerates the Xcode project. See the Automation Tips section for a partial workaround.
  4. The bridge code is reference code, not a drop-in package. You may need to adjust method signatures or imports based on your Unity version, Xcode version, and SDK version updates.

Architecture Overview

The integration uses Unity’s native plugin system:
  • Android: A Java bridge class calls LinkrunnerJava (the SDK’s callback-based Java API) and communicates results back to Unity via UnitySendMessage.
  • iOS: A Swift bridge file wraps the Linkrunner iOS SDK’s async methods into C-callable functions (via @_cdecl), which Unity calls through [DllImport("__Internal")].
  • C#: A LinkrunnerSDK.cs wrapper provides a unified cross-platform API.

Android Setup

Step 1: Add the SDK Dependency

In your Unity project, create or edit the file Assets/Plugins/Android/mainTemplate.gradle (or your custom Gradle template) and add:
Make sure Maven Central is included in your repositories. In Assets/Plugins/Android/settingsTemplate.gradle:
If you’re using Unity 2022.2+ with the Gradle template system, you may need to add the dependency in unityLibrary/build.gradle instead. Check Unity’s documentation for your version.

Step 2: Permissions

Add the following to your Assets/Plugins/Android/AndroidManifest.xml:
If your app targets children and you need to disable advertising ID collection, remove the AD_ID permission:
Disabling AAID collection is not recommended unless absolutely necessary. The GAID is a primary signal for Google Ads attribution and install matching, so disabling it reduces attribution accuracy. Only disable it if your app is built for children or families and must comply with Google Play’s Family Policy.

Step 3: Create the Java Bridge

Create Assets/Plugins/Android/LinkrunnerBridge.java:
The bridge uses LinkrunnerJava, a callback-based wrapper included in the Android SDK. It handles all Kotlin coroutine execution internally — no Kotlin imports, no BuildersKt.runBlocking, and no background thread management needed in your bridge code. Callbacks are invoked on a background IO thread, which is safe for UnitySendMessage.

iOS Setup

Step 1: Add the SDK

After building your Unity project for iOS and opening the generated Xcode project:
  1. In Xcode, select FileAdd Package Dependencies…
  2. Enter the repository URL:
  3. Select the latest version (3.8.0+)
  4. Click Add Package and choose the LinkrunnerStatic library
You’ll need to add the SPM dependency each time you regenerate the Xcode project from Unity. Consider using a post-build script to automate this — see the Automation Tips section.

Step 2: Info.plist Configuration

Add to your Info.plist (can also be done via Unity’s Assets/Plugins/iOS/Info.plist additions):

Step 3: Create the Swift Bridge

The Linkrunner iOS SDK is a pure Swift module — it does not inherit from NSObject and has no @objc annotations, so it cannot be called directly from Objective-C. We use a Swift bridge file with @_cdecl to expose C-callable functions that Unity can invoke via [DllImport("__Internal")]. Create Assets/Plugins/iOS/LinkrunnerUnityBridge.swift:
Swift files in Unity iOS plugins: Unity does not natively compile .swift files in Assets/Plugins/iOS/. After Unity generates the Xcode project, you must manually add LinkrunnerUnityBridge.swift to the Xcode project’s UnityFramework target and ensure:
  1. The file is added to the Compile Sources build phase of the UnityFramework target
  2. A bridging header exists (Xcode usually prompts to create one when adding the first Swift file)
  3. SWIFT_VERSION is set to 5.0+ in the UnityFramework build settings
Alternatively, you can automate this with a Unity PostProcessBuild script — see the Automation Tips section.

C# Wrapper

Create Assets/Scripts/LinkrunnerSDK.cs in your Unity project:

Usage

Scene Setup

  1. Create an empty GameObject in your first scene
  2. Name it LinkrunnerCallbackHandler (must match exactly)
  3. Attach the LinkrunnerSDK.cs script to it

Initialization (Required)

Call Initialize as early as possible — typically in your startup scene:
Find your project token at: Dashboard → Documentation

User Identification (Required)

Call Signup as soon as the user is identified — whether through signup or login. This is the moment Linkrunner ties the install (and any future events) to a user identifier.
Call HandleDeeplink when your app is opened via a deeplink — both cold start (app was closed) and warm start (app was in background):
Linkrunner sends the updated deeplink back after processing. For Linkrunner campaign links, use deeplink from OnDeeplinkHandled as the resolved destination instead of the original tracking URL.
The is_linkrunner field indicates whether the deeplink was created through Linkrunner. Use this to determine if you should apply Linkrunner-specific attribution logic.
For Unity deeplink handling, you’ll need to implement platform-specific code to capture the deeplink URL:
Create a custom UnityPlayerActivity to capture deeplinks:
Update your AndroidManifest.xml to use this activity and add intent filters for your deeplink scheme.

Set User Data on App Open

Call every time the app opens and the user is logged in:
SetUserData is optional and is not a replacement for Signup. Always call Signup first as soon as the user is identified (signup or login). Use SetUserData afterwards only when additional user details become available later — for example, when the user adds a phone number, email, or completes their profile after identification.

Get Attribution Data

The result arrives as a JSON string on the OnAttributionData event. With the reference bridge code in this guide, the shape differs by platform. iOS
Android

Track Events

When tracking revenue-related events, the amount field must be a number (not a string) for ad network revenue optimization to work correctly.

Capture Payment

Payment types: FIRST_PAYMENT, SECOND_PAYMENT, WALLET_TOPUP, FUNDS_WITHDRAWAL, SUBSCRIPTION_CREATED, SUBSCRIPTION_RENEWED, ONE_TIME, RECURRING, DEFAULT Payment statuses: PAYMENT_INITIATED, PAYMENT_COMPLETED, PAYMENT_FAILED, PAYMENT_CANCELLED

Remove Payment (Refunds)

Push Token

Privacy Controls


Function Placement Guide


Automating iOS Dependency with a Post-Build Script

Since Unity regenerates the Xcode project on each build, you can automate the SPM dependency addition using a Unity Editor script: Create Assets/Editor/LinkrunnerPostBuild.cs:
Unity’s PBXProject API does not natively support adding SPM packages. After the Xcode project is generated, you will need to add the LinkrunnerKit SPM dependency manually in Xcode, or use a third-party tool like unity-spm to automate it.

Testing

  1. Enable debug mode: LinkrunnerSDK.Initialize(token, debug: true)
  2. Create a test campaign at Dashboard → Create Campaign
  3. Uninstall the app from your test device
  4. Click the campaign link on the device (opens in browser)
  5. Install and open the app build within 3 minutes
  6. Verify in the dashboard that click count, install count, and signup count increase
  7. Call GetAttributionData() to confirm attribution is returned
For detailed testing steps, see the Integration Testing Guide.

Troubleshooting

Android

  • ProGuard/R8 issues: Add to your ProGuard rules:
  • Duplicate classes: If another plugin includes Kotlin stdlib, use Gradle’s exclude to avoid conflicts.

iOS

  • Swift file not compiling: Unity does not automatically compile .swift files. After generating the Xcode project, add LinkrunnerUnityBridge.swift to the UnityFramework target’s Compile Sources build phase manually.
  • “Use of unresolved identifier ‘LinkrunnerSDK’”: The LinkrunnerKit SPM package hasn’t been added to the Xcode project. Add it via File → Add Package Dependencies.
  • Bridging header issues: When Xcode prompts to create a bridging header after adding the first Swift file, accept it. Ensure SWIFT_VERSION is set to 5.0 or higher in UnityFramework build settings.
  • Linker errors: Ensure you selected LinkrunnerStatic (not the dynamic variant) when adding the SPM package.
  • ATT dialog not showing: The NSUserTrackingUsageDescription key must be present in Info.plist. The SDK handles requesting permission automatically during initialization.

General

  • Callbacks not received: Verify the GameObject is named exactly LinkrunnerCallbackHandler and has the LinkrunnerSDK.cs script attached. It must exist in the scene when native code calls UnitySendMessage.
  • Editor testing: All SDK calls are no-ops in the Unity Editor and log to the console instead. Test on actual Android/iOS devices.