using System;
using System.Threading;
using UnityEngine;
namespace JustTrack
{
///
/// Unity MonoBehaviour component that manages the justtrack SDK lifecycle and operations.
///
public class JustTrackSDKBehaviour : MonoBehaviour
{
// Invoked once the attribution has been retrieved from the backend if not null.
private static Action? onInitialized = null;
// Invoked if an error occurs during attribution if not null.
private static Action? onError = null;
// Stores the attribution response after the SDK has been initialized.
private static AttributionResponse? attributionResponse = null;
// Stores the error if getting the attribution fails.
private static string? initError = null;
// Lock guarding the attribution results and callbacks.
private static readonly object SyncLock = new object();
static JustTrackSDKBehaviour()
{
}
private void Awake()
{
if (unityMainThreadId != -1)
{
// we have been initialized a second time and thus can skip initialization
return;
}
// set the main thread id first - we can't do that in the constructur or similar
// (unity might load stuff on a background thread), so doing it here is the first
// place we can do that.
// This also serves as a check above whether we have already created an SDK instance once
unityMainThreadId = Thread.CurrentThread.ManagedThreadId;
var settings = JustTrackSettings.LoadFromResources();
if (settings == null)
{
Debug.LogError("There are no settings defined for the justtrack SDK, can not initialize");
return;
}
gameObject.name = "JustTrackSDKBehaviour";
if (gameObject.transform.parent != null)
{
Debug.Log("Detaching from parent so we can mark ourselves as DontDestroyOnLoad");
gameObject.transform.parent = null;
}
DontDestroyOnLoad(gameObject);
#if UNITY_IOS
if (settings.IosTrackingSettings.RequestTrackingPermission)
{
JustTrackSDK.RequestTrackingAuthorization((authorized) => { });
}
#endif
if (settings.UseRuntimeConstructor)
{
return;
}
Init(settings);
}
private void Init(JustTrackSettings settings)
{
#if UNITY_WEBGL
var apiToken = settings.WebglApiToken;
var automaticInAppPurchaseTracking = false;
var manualStart = settings.ManualStart;
var enableLogging = settings.EnableConsoleLogging;
string? bundleId = null;
string? appVersion = null;
string? appCode = null;
#elif UNITY_IOS
var apiToken = settings.IosApiToken;
var automaticInAppPurchaseTracking = !settings.IosDisableAutomaticInAppPurchaseTracking;
var manualStart = settings.ManualStart;
var enableLogging = settings.EnableConsoleLogging;
string? bundleId = settings.IosBundleId;
string? appVersion = settings.IosAppVersion;
string? appCode = settings.IosAppCode;
#else
var apiToken = settings.AndroidApiToken;
var automaticInAppPurchaseTracking = !settings.AndroidDisableAutomaticInAppPurchaseTracking;
var manualStart = settings.ManualStart;
var enableLogging = settings.EnableConsoleLogging;
string? bundleId = settings.AndroidBundleId;
string? appVersion = settings.AndroidAppVersion;
string? appCode = settings.AndroidAppCode;
#endif
string trackingId = string.Empty;
string trackingProvider = string.Empty;
JustTrackSDK.Init(
apiToken,
trackingId,
trackingProvider,
null,
automaticInAppPurchaseTracking,
manualStart,
enableLogging,
settings.ServerUrl,
bundleId,
appVersion,
appCode,
(response) =>
{
lock (SyncLock)
{
attributionResponse = response;
if (onInitialized != null)
{
var toCall = onInitialized;
CallOnMainThread(() =>
{
toCall(response);
});
}
onInitialized = null;
onError = null;
}
}, (error) =>
{
lock (SyncLock)
{
initError = error;
if (onError != null)
{
var toCall = onError;
CallOnMainThread(() =>
{
toCall(error);
});
}
onInitialized = null;
onError = null;
}
});
}
// Retrieve the attribution produced by the SDK. If the SDK already can provide an attribution, your
// callbacks are immediately invoked with the attribution result. Otherwise they are stored and called
// as soon as a result is available.
// You can call this method as many times as you want - each invocation will add your delegates to
// the list of delegates to call as soon as the attribution is available.
///
/// Gets the attribution response from the justtrack SDK.
///
/// Callback invoked when attribution is successfully retrieved.
/// Callback invoked if an error occurs during attribution retrieval.
public static void GetAttribution(Action pOnInitialized, Action pOnError)
{
lock (SyncLock)
{
if (attributionResponse != null)
{
CallOnMainThread(() =>
{
pOnInitialized(attributionResponse);
});
}
else if (initError != null)
{
CallOnMainThread(() =>
{
pOnError(initError);
});
}
else
{
if (onInitialized == null)
{
onInitialized = pOnInitialized;
}
else
{
onInitialized += pOnInitialized;
}
if (onError == null)
{
onError = pOnError;
}
else
{
onError += pOnError;
}
}
}
}
private static int unityMainThreadId = -1;
///
/// Checks whether the current thread is the Unity main thread.
///
/// True if running on the main thread, false otherwise.
internal static bool IsOnMainThread()
{
return Thread.CurrentThread.ManagedThreadId == unityMainThreadId;
}
private static Action? actionsOnMainThead = null;
private static readonly object OnMainThreadLock = new object();
///
/// Executes the specified action on the Unity main thread.
///
/// The action to execute on the main thread.
internal static void CallOnMainThread(Action pAction)
{
lock (OnMainThreadLock)
{
if (actionsOnMainThead == null)
{
actionsOnMainThead = pAction;
}
else
{
actionsOnMainThead += pAction;
}
}
}
private void Update()
{
Action? action = null;
lock (OnMainThreadLock)
{
action = actionsOnMainThead;
actionsOnMainThead = null;
}
if (action != null)
{
action();
}
}
}
}