#if UNITY_WEBGL
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using UnityEngine;
namespace JustTrack
{
///
/// WebGL-specific implementation of the SDK agent that communicates with the JavaScript Web SDK.
///
internal class SDKWebGLAgent : ISDKAgent
{
internal static SDKWebGLAgent INSTANCE = new SDKWebGLAgent();
private bool initialized = false;
private SDKWebGLAgent() {}
#pragma warning disable SA1309 // Field names should not begin with underscore (required for native interop)
[DllImport("__Internal")]
private static extern void _justtrack_webgl_init(string apiKey, string bundleId, string appVersion, string appCode, string userId, bool manualStart, bool isLoggingEnabled, string gameObjectName, string callbackMethodName);
[DllImport("__Internal")]
private static extern void _justtrack_webgl_start();
[DllImport("__Internal")]
private static extern void _justtrack_webgl_stop();
[DllImport("__Internal")]
private static extern bool _justtrack_webgl_is_running();
[DllImport("__Internal")]
private static extern void _justtrack_webgl_anonymize(string gameObjectName, string callbackMethodName);
[DllImport("__Internal")]
private static extern void _justtrack_webgl_track_event(string eventName, string dimensionsJson, string valueJson, string gameObjectName, string callbackMethodName);
#pragma warning restore SA1309
#pragma warning disable SA1401, SA1307 // Fields should be private; field names should begin with upper-case letter (required for JSON serialization)
[Serializable]
public class WebGLAttributionResponse
{
public string userType = "";
public string type = "";
public string campaignId = "";
public string campaignName = "";
public string campaignType = "";
public string channelId = "";
public string channelName = "";
public string channelIncent = "";
public string partnerId = "";
public string partnerName = "";
public string? sourceId = null;
public string? sourceBundleId = null;
public string? sourcePlacement = null;
public string? adsetId = null;
public string createdAt = "";
}
[Serializable]
public class WebGLCallbackResponse
{
public bool success = false;
public string? data = null;
public string? error = null;
}
#pragma warning restore SA1401, SA1307
private Action? initSuccessCallback = null;
private Action? initFailureCallback = null;
private Action? anonymizeSuccessCallback = null;
private Action? anonymizeFailureCallback = null;
private Action? attributionListenerCallback = null;
private Dictionary eventSuccessCallbacks = new Dictionary();
private Dictionary> eventFailureCallbacks = new Dictionary>();
public void Initialize(
string pApiKey,
string? pTrackingId,
string? pTrackingProvider,
string? pCustomUserId,
bool pAutomaticInAppPurchaseTracking,
bool pManualStart,
bool pEnableConsoleLogging,
string? pServerUrl,
string? pBundleId,
string? pAppVersion,
string? pAppCode,
Action pOnSuccess,
Action pOnFailure)
{
initSuccessCallback = pOnSuccess;
initFailureCallback = pOnFailure;
var settings = JustTrackSettings.LoadFromResources();
string bundleId = !string.IsNullOrEmpty(pBundleId) ? pBundleId : (!string.IsNullOrEmpty(settings?.WebglBundleId) ? settings.WebglBundleId : Application.identifier);
string appVersion = !string.IsNullOrEmpty(pAppVersion) ? pAppVersion : (!string.IsNullOrEmpty(settings?.WebglAppVersion) ? settings.WebglAppVersion : Application.version);
string appCode = !string.IsNullOrEmpty(pAppCode) ? pAppCode : (!string.IsNullOrEmpty(settings?.WebglAppCode) ? settings.WebglAppCode : appVersion);
string userId = !string.IsNullOrEmpty(settings?.WebglUserId) ? settings.WebglUserId : (pCustomUserId ?? "");
try
{
_justtrack_webgl_init(
pApiKey,
bundleId,
appVersion,
appCode,
userId,
pManualStart,
pEnableConsoleLogging,
"JustTrackSDKBehaviour",
"OnWebGLInitCallback"
);
initialized = true;
}
catch (Exception e)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
pOnFailure(e.Message);
});
}
}
public void OnWebGLInitCallback(string responseJson)
{
try
{
WebGLCallbackResponse response = JsonUtility.FromJson(responseJson);
if (response.success && response.data != null)
{
var attribution = ParseAttributionResponse(response.data);
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
initSuccessCallback?.Invoke(attribution);
});
}
else
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
initFailureCallback?.Invoke(response.error ?? "Unknown initialization error");
});
}
}
catch (Exception e)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
initFailureCallback?.Invoke(e.Message);
});
}
}
private AttributionResponse ParseAttributionResponse(string attributionJson)
{
WebGLAttributionResponse parsed = JsonUtility.FromJson(attributionJson);
if (!int.TryParse(parsed.campaignId, out int campaignId))
{
campaignId = 0;
}
if (!int.TryParse(parsed.channelId, out int channelId))
{
channelId = 0;
}
bool channelIncent = parsed.channelIncent == "true";
if (!int.TryParse(parsed.partnerId, out int partnerId))
{
partnerId = 0;
}
CultureInfo provider = CultureInfo.InvariantCulture;
if (!DateTime.TryParseExact(parsed.createdAt, "yyyy-MM-dd'T'HH:mm:ssK", provider, DateTimeStyles.None, out DateTime createdAt))
{
createdAt = DateTime.UtcNow;
}
return AttributionResponse.CreateResponse(
parsed.userType,
parsed.type,
campaignId,
parsed.campaignName,
parsed.campaignType,
channelId,
parsed.channelName,
channelIncent,
partnerId,
parsed.partnerName,
parsed.sourceId,
parsed.sourceBundleId,
parsed.sourcePlacement,
parsed.adsetId,
createdAt
);
}
public void Start()
{
try
{
_justtrack_webgl_start();
}
catch (Exception)
{
}
}
public void Stop()
{
try
{
_justtrack_webgl_stop();
}
catch (Exception)
{
}
}
public void Anonymize(Action pOnSuccess, Action pOnFailure)
{
anonymizeSuccessCallback = pOnSuccess;
anonymizeFailureCallback = pOnFailure;
try
{
_justtrack_webgl_anonymize("JustTrackSDKBehaviour", "OnWebGLAnonymizeCallback");
}
catch (Exception e)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
pOnFailure(e.Message);
});
}
}
public void OnWebGLAnonymizeCallback(string responseJson)
{
try
{
WebGLCallbackResponse response = JsonUtility.FromJson(responseJson);
if (response.success)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
anonymizeSuccessCallback?.Invoke();
});
}
else
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
anonymizeFailureCallback?.Invoke(response.error ?? "Unknown anonymize error");
});
}
}
catch (Exception e)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
anonymizeFailureCallback?.Invoke(e.Message);
});
}
}
public bool IsRunning()
{
try
{
return _justtrack_webgl_is_running();
}
catch (Exception)
{
return false;
}
}
public void RegisterAttributionListener(Action pListener)
{
lock (this)
{
if (attributionListenerCallback == null)
{
attributionListenerCallback = pListener;
}
else
{
attributionListenerCallback += pListener;
}
}
}
public void PublishEvent(AppEvent pEvent, Action? pOnSuccess, Action? pOnFailure)
{
try
{
string dimensionsJson = "{}";
if (pEvent.Dimensions.Count > 0)
{
var dimensionPairs = new System.Collections.Generic.List();
foreach (var kvp in pEvent.Dimensions)
{
string jsonValue = kvp.Value != null ? JsonUtility.ToJson(new StringWrapper { value = kvp.Value.ToString() }) : "null";
if (jsonValue.StartsWith("{\"value\":\"") && jsonValue.EndsWith("\"}"))
{
jsonValue = jsonValue.Substring(10, jsonValue.Length - 12);
}
dimensionPairs.Add($"\"{kvp.Key}\":\"{jsonValue}\"");
}
dimensionsJson = "{\"dimensions\":{" + string.Join(",", dimensionPairs.ToArray()) + "}}";
}
string valueJson = "null";
if (pEvent.Unit != null)
{
valueJson = JsonUtility.ToJson(new ValueWrapper
{
value = pEvent.Value,
unit = pEvent.Unit.ToString().ToLower()
});
}
else if (pEvent.Currency != null)
{
valueJson = JsonUtility.ToJson(new MoneyWrapper
{
value = pEvent.Value,
currency = pEvent.Currency
});
}
string callbackId = Guid.NewGuid().ToString();
if (pOnSuccess != null)
{
eventSuccessCallbacks[callbackId] = pOnSuccess;
}
if (pOnFailure != null)
{
eventFailureCallbacks[callbackId] = pOnFailure;
}
string callbackMethodName = pOnSuccess != null || pOnFailure != null
? $"OnWebGLEventCallback_{callbackId}"
: "";
_justtrack_webgl_track_event(
pEvent.Name,
dimensionsJson,
valueJson,
"JustTrackSDKBehaviour",
callbackMethodName
);
}
catch (Exception e)
{
if (pOnFailure != null)
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
pOnFailure(e.Message);
});
}
}
}
#pragma warning disable SA1401, SA1307 // Fields should be private; field names should begin with upper-case letter (required for JSON serialization)
[Serializable]
private class StringWrapper
{
public string value = "";
}
[Serializable]
private class ValueWrapper
{
public double value;
public string unit = "";
}
[Serializable]
private class MoneyWrapper
{
public double value;
public string currency = "";
}
#pragma warning restore SA1401, SA1307
public void OnWebGLEventCallback(string callbackData)
{
string[] parts = callbackData.Split(new[] { '|' }, 2);
if (parts.Length != 2)
{
return;
}
string callbackId = parts[0];
string responseJson = parts[1];
try
{
WebGLCallbackResponse response = JsonUtility.FromJson(responseJson);
if (response.success)
{
if (eventSuccessCallbacks.TryGetValue(callbackId, out var successCallback))
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
successCallback?.Invoke();
});
eventSuccessCallbacks.Remove(callbackId);
}
}
else
{
if (eventFailureCallbacks.TryGetValue(callbackId, out var failureCallback))
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
failureCallback?.Invoke(response.error ?? "Unknown event tracking error");
});
eventFailureCallbacks.Remove(callbackId);
}
}
}
catch (Exception e)
{
if (eventFailureCallbacks.TryGetValue(callbackId, out var failureCallback))
{
JustTrackSDKBehaviour.CallOnMainThread(() =>
{
failureCallback?.Invoke(e.Message);
});
eventFailureCallbacks.Remove(callbackId);
}
}
}
public bool IsInitialized()
{
return initialized;
}
}
}
#endif