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(); } } } }