Unity
Overview
Project Setup
Unity Project Configuration
Android Platform Setup
iOS Platform Setup
Creating Deep Links
Troubleshooting
The AdStage DeepLink SDK for Unity provides the following features:
Real-time Deep Links : Instant processing via URL Scheme, App Link/Universal Links
Deferred Deep Links : Automatic restoration on first launch after app installation
Dynamic Deep Link Creation : Generate trackable links via server API
Attribution Tracking : Marketing analysis based on UTM parameters
Cross-Platform : Unified API for Android/iOS
URL Scheme : myapp://promo/summer
Android App Links : https://go.myapp.com/abc123
iOS Universal Links : https://go.myapp.com/abc123
Deferred Deep Links : App not installed → Store → Install → App launch → Restoration
Install via Package Manager:
Window → Package Manager → + → Add package from git URL
https://github.com/nbase-io/NBase-SDK-Unity.git?path=/AdStageSDK-Package
Or edit manifest.json directly:
{
"dependencies" : {
"com.nbase.adstage" : "https://github.com/nbase-io/NBase-SDK-Unity.git?path=/AdStageSDK-Package#3.0.0"
}
}
Automatically included with package installation:
Newtonsoft.Json : JSON serialization
Native Plugins : iOS/Android bridge
using AdStageSDK ;
using UnityEngine ;
public class AdStageInitializer : MonoBehaviour
{
void Start ()
{
// Initialize AdStage
AdStage. Initialize (
apiKey : "your-api-key-here"
);
// Register deep link listener
SetupDeepLinkListener ();
Debug. Log ( "✅ AdStage SDK Initialized" );
}
private void SetupDeepLinkListener ()
{
AdStage. SetDeepLinkListener (
onDeepLink : ( data ) => {
Debug. Log ( $"✅ Deep Link Received: { data . shortPath }" );
if (data.parameters != null && data.parameters.Count > 0 )
{
foreach ( var param in data.parameters)
{
Debug. Log ( $" - { param . Key }: { param . Value }" );
}
}
},
onError : ( error ) => {
Debug. LogError ( $"❌ Deep Link Failed: { error }" );
}
);
}
}
Create Assets/Plugins/Android/AndroidManifest.xml :
<? xml version = "1.0" encoding = "utf-8" ?>
< manifest xmlns:android = "http://schemas.android.com/apk/res/android"
package = "com.example.myapp" >
< application
android:allowBackup = "true"
android:icon = "@drawable/app_icon"
android:label = "@string/app_name" >
< activity
android:name = "com.unity3d.player.UnityPlayerActivity"
android:theme = "@style/UnityThemeSelector"
android:screenOrientation = "fullSensor"
android:launchMode = "singleTask"
android:configChanges = "mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density"
android:exported = "true" >
<!-- Default launcher -->
< intent-filter >
< action android:name = "android.intent.action.MAIN" />
< category android:name = "android.intent.category.LAUNCHER" />
</ intent-filter >
<!-- URL Scheme deep link -->
< intent-filter >
< action android:name = "android.intent.action.VIEW" />
< category android:name = "android.intent.category.DEFAULT" />
< category android:name = "android.intent.category.BROWSABLE" />
< data android:scheme = "your_app_scheme" />
</ intent-filter >
</ activity >
</ application >
</ manifest >
android:launchMode="singleTask"
✅ singleTask : Reuse existing Activity (recommended)
⚠️ singleTop : Reuse only when at top of stack
❌ standard : Create new instance every time (causes duplicate deep links)
<!-- URL Scheme Configuration -->
< key >CFBundleURLTypes</ key >
< array >
< dict >
< key >CFBundleTypeRole</ key >
< string >Editor</ string >
< key >CFBundleURLName</ key >
< string >com.example.myapp</ string >
< key >CFBundleURLSchemes</ key >
< array >
< string >myapp</ string >
</ array >
</ dict >
</ array >
public async void CreateDetailedDeepLink ()
{
try
{
var builder = new DeepLinkBuilder ( "Unity Test Link" )
. SetDescription ( "Unity SDK Test" )
. SetCampaign ( "unity_test" )
. SetChannel ( "app_channel" )
. SetRedirectType (RedirectType.APP)
. SetAndroidConfig ( "your.package.name" , "your_aos_scheme" , "https://yourdomain.com" )
. SetIOSConfig ( "your.appstoreid" , "your_ios_scheme" , "https://yourdomain.com" )
. SetWebConfig ( "https://yourdomain.com" )
. AddParameter ( "user_id" , "value" )
. AddParameter ( "test" , "true" );
AdStage. CreateDeeplink (
builder : builder,
onSuccess : ( shortUrl ) =>
{
InAppLog ( "✅ Deep Link Created Successfully!" );
InAppLog ( $" URL: { shortUrl }" );
},
onError : ( error ) =>
{
InAppLog ( $"❌ Deep Link Creation Failed: { error }" );
}
);
}
catch ( System . Exception e )
{
Debug. LogError ( $"❌ Error: { e . Message }" );
}
}
public enum RedirectType
{
Store , // Redirect to store
App , // App not installed → Redirect to store
// App installed → Launch app (real-time deep link)
Web // Always redirect to web URL
// Regardless of app installation
}
Android Deep Link Flow:
User clicks deep link (myapp://abc123)
↓
Android System creates Intent
↓
UnityPlayerActivity starts/resumes
↓
AdStageLifecyclePlugin.onActivityCreated/Resumed()
↓
AdStageUnityWrapper.handleIntent(intent)
↓
AdStage.handleIntent(context, intent)
↓
DeeplinkHandler.handleIntent()
├─ Extract URI: myapp://abc123
├─ Parse shortPath: abc123
├─ API call: GET /deeplinks/abc123
└─ DeeplinkListener.onDeeplinkReceived()
↓
UnitySendMessage("AdStageCallbackReceiver", "OnDeepLinkReceived", json)
↓
AdStageCallbackReceiver.OnDeepLinkReceived(json)
↓
User callback invoked
iOS Deep Link Flow:
User clicks deep link (myapp://abc123)
↓
iOS System delivers URL
↓
AdStageUnityAppController.application:openURL: or
AdStageUnityAppController.application:continueUserActivity:
↓
AdStageUnityBridge.AdStageIOS_HandleDeepLink(url)
↓
AdStageManager.shared.handleDeepLink(url)
↓
DeepLinkManager.handleDeepLink()
├─ Parse URL
├─ API call
└─ DeepLinkDelegate.onDeepLinkReceived()
↓
UnitySendMessage("AdStageCallbackReceiver", "OnDeepLinkReceived", json)
↓
AdStageCallbackReceiver.OnDeepLinkReceived(json)
↓
User callback invoked
This is normal behavior! Editor only outputs logs.
Testing Method:
# if UNITY_EDITOR
[ MenuItem ( "AdStage/Test DeepLink" )]
public static void TestDeepLink ()
{
var testData = new DeepLinkData
{
ShortPath = "TEST123" ,
Source = DeepLinkSource.Realtime,
Parameters = new Dictionary < string , string >
{
{ "promo" , "EDITOR_TEST" }
}
};
AdStage. SimulateDeepLink (testData);
}
# endif
Checklist:
Check AndroidManifest.xml
Verify android:launchMode="singleTask" setting
Verify Intent Filter is correct
Check adb logcat
adb logcat | grep -i adstage
Test Intent
# Test URL Scheme
adb shell am start -W -a android.intent.action.VIEW -d "myapp://promo/summer" com.example.myapp
# Test HTTPS App Link
adb shell am start -W -a android.intent.action.VIEW -d "https://go.myapp.com/abc123" com.example.myapp
Checklist:
Check Info.plist
CFBundleURLTypes configuration
Associated Domains configuration
Verify Universal Links
# Check Apple App Site Association file
curl https://go.myapp.com/.well-known/apple-app-site-association
Check Xcode Console
Check error messages
Check deep link reception logs
Android:
# Check Install Referrer
adb shell dumpsys package com.example.myapp | grep -i referrer
Solution:
Add permission to AndroidManifest.xml :
< uses-permission android:name = "com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" />
Configure Install Referrer in Play Console
Cause: Using launchMode="standard"
Solution:
<!-- AndroidManifest.xml -->
android:launchMode="singleTask"
Issue:
TypeLoadException: Could not load type 'AdStageSDK.DeepLinkData'
Solution: Create link.xml file
Assets/link.xml:
< linker >
< assembly fullname = "AdStageSDK" preserve = "all" />
< assembly fullname = "AdStageSDK.Models" preserve = "all" />
< assembly fullname = "Newtonsoft.Json" preserve = "all" />
</ linker >
Issue:
JsonSerializationException: Error converting value
Solution:
// Use Dictionary<string, object> for Parameters
var parameters = new Dictionary < string , object >
{
{ "key1" , "value1" },
{ "key2" , 123 }, // int also supported
{ "key3" , true } // bool also supported
};
Verification Method:
# Verify Digital Asset Links
curl https://go.myapp.com/.well-known/assetlinks.json
Checklist:
✅ Using HTTPS
✅ Content-Type: application/json
✅ Verify SHA256 fingerprint is correct
✅ Package name matches
Q: Can I test deep links in Unity Editor?
A: In Editor, you can simulate using the AdStage.SimulateDeepLink() method.
Q: Can I use the same deep link URL for Android and iOS?
A: Yes, both URL Scheme and HTTPS links can be used identically.
Q: How do deferred deep links work?
A: App install → First launch → Query Install Referrer → Restore saved deep link → Invoke callback
Q: Is there a limit to the number of deep link parameters?
A: No server limit, but consider URL length limitation (~2000 characters).
Q: Do deep links work offline?
A: Real-time deep links require network. Deferred deep links are cached and restored even offline.
Q: Does it work with Unity WebGL?
A: WebGL cannot use native plugins, so it's not supported. In web environments, parse URL parameters directly.
Contact:
© 2025 NBase. All rights reserved.