com.amanotes.gdk 0.2.50 → 0.2.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/Editor/Extra/GDKCIBuildCommand.cs +312 -0
- package/Editor/Extra/GDKCIBuildCommand.cs.meta +3 -0
- package/Editor/Extra/{GDKAutoBuild.cs → GDKLocalBuild.cs} +49 -34
- package/Extra/AmaGDKInstaller.unitypackage +0 -0
- package/Extra/CheckDiskSpace.unitypackage +0 -0
- package/Extra/PostProcessor.unitypackage +0 -0
- package/Extra/{AndroidPostProcessor.unitypackage.meta → PostProcessor.unitypackage.meta} +1 -1
- package/Extra/SDKVersionTracking.unitypackage +0 -0
- package/Packages/AmaGDKConfig.unitypackage +0 -0
- package/Packages/AmaGDKExample.unitypackage +0 -0
- package/Packages/AmaGDKTest.unitypackage +0 -0
- package/Packages/AppsFlyerAdapter.unitypackage +0 -0
- package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
- package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
- package/Packages/IronSourceAdapter.unitypackage +0 -0
- package/Packages/RevenueCatAdapter.unitypackage +0 -0
- package/Runtime/AmaGDK.Adapters.cs +1 -1
- package/Runtime/AmaGDK.Ads.cs +17 -17
- package/Runtime/AmaGDK.Analytics.cs +316 -151
- package/Runtime/AmaGDK.UserProfile.cs +36 -32
- package/Runtime/AmaGDK.cs +2 -2
- package/Runtime/Internal/AmaGDK.Internal.cs +24 -0
- package/Runtime/Internal/AmaGDK.Utils.cs +27 -1
- package/package.json +1 -1
- package/Extra/AndroidPostProcessor.unitypackage +0 -0
- /package/Editor/Extra/{GDKAutoBuild.cs.meta → GDKLocalBuild.cs.meta} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
using System;
|
|
2
|
+
using System.Collections.Concurrent;
|
|
2
3
|
using System.Collections.Generic;
|
|
3
4
|
using System.Text;
|
|
4
5
|
using System.Text.RegularExpressions;
|
|
@@ -21,37 +22,52 @@ namespace Amanotes.Core
|
|
|
21
22
|
|
|
22
23
|
public class EventParams : IEventParamsBuilder
|
|
23
24
|
{
|
|
24
|
-
public
|
|
25
|
-
public Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
25
|
+
public string eventName { get; private set; }
|
|
26
|
+
public readonly Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
26
27
|
public string funnelSignature;
|
|
27
28
|
public bool accumulated;
|
|
28
29
|
public bool withinSession;
|
|
29
30
|
public bool doNotIncreaseCounter;
|
|
30
31
|
|
|
31
32
|
public bool overrideConfig;
|
|
32
|
-
public HashSet<string> ignoreAdapterIds =
|
|
33
|
-
public HashSet<string> allowAdapterIds =
|
|
33
|
+
public HashSet<string> ignoreAdapterIds = null;
|
|
34
|
+
public HashSet<string> allowAdapterIds = null;
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
public EventParams(string eventName)
|
|
36
|
+
private EventDetail _detail;
|
|
37
|
+
public EventDetail EventDetail
|
|
38
38
|
{
|
|
39
|
-
|
|
39
|
+
get
|
|
40
|
+
{
|
|
41
|
+
if (_detail != null) return _detail;
|
|
42
|
+
return _detail = localData.GetEventDetail(eventName, true);
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
internal EventParams Init(string eventName)
|
|
43
47
|
{
|
|
44
|
-
|
|
48
|
+
this.eventName = eventName;
|
|
49
|
+
parameters.Clear();
|
|
50
|
+
funnelSignature = "";
|
|
51
|
+
accumulated = false;
|
|
52
|
+
withinSession = false;
|
|
53
|
+
doNotIncreaseCounter = false;
|
|
54
|
+
overrideConfig = false;
|
|
55
|
+
ignoreAdapterIds = null;
|
|
56
|
+
allowAdapterIds = null;
|
|
57
|
+
_detail = null;
|
|
58
|
+
return this;
|
|
45
59
|
}
|
|
46
60
|
|
|
61
|
+
public bool IsFunnelEvent => !string.IsNullOrEmpty(funnelSignature);
|
|
62
|
+
|
|
47
63
|
public bool IsAdapterForbidden(string adapterId)
|
|
48
64
|
{
|
|
49
|
-
if (ignoreAdapterIds.Count > 0)
|
|
65
|
+
if (ignoreAdapterIds != null && ignoreAdapterIds.Count > 0)
|
|
50
66
|
{
|
|
51
67
|
return ignoreAdapterIds.Contains(adapterId);
|
|
52
68
|
}
|
|
53
69
|
|
|
54
|
-
if (allowAdapterIds.Count > 0)
|
|
70
|
+
if (allowAdapterIds != null && allowAdapterIds.Count > 0)
|
|
55
71
|
{
|
|
56
72
|
return !allowAdapterIds.Contains(adapterId);
|
|
57
73
|
}
|
|
@@ -71,31 +87,22 @@ namespace Amanotes.Core
|
|
|
71
87
|
|
|
72
88
|
public static IEventParamsBuilder LogEvent(string eventName)
|
|
73
89
|
{
|
|
74
|
-
|
|
75
|
-
if (localData.GetEventDetail(eventName) == null && localData.eventDetails.Count >= 500)
|
|
76
|
-
{
|
|
77
|
-
LogWarning($" - You have reported 500 types of events. New event <{eventName}> will be ignored.");
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
var result = new EventParams(eventName);
|
|
90
|
+
var result = PrepareEvent(eventName);
|
|
81
91
|
eventQueue.Enqueue(result);
|
|
82
92
|
return result;
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
public static IEventParamsBuilder LogEvent(string eventName, Dictionary<string, object> parameters)
|
|
86
96
|
{
|
|
87
|
-
|
|
88
|
-
|
|
97
|
+
var result = PrepareEvent(eventName, parameters);
|
|
98
|
+
eventQueue.Enqueue(result);
|
|
99
|
+
return result;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
public static IEventParamsBuilder LogEvent(string eventName, params (string, object)[] parameters)
|
|
92
103
|
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
for (var i = 0; i < parameters.Length; i++)
|
|
96
|
-
{
|
|
97
|
-
result.AddParam(parameters[i].Item1, parameters[i].Item2);
|
|
98
|
-
}
|
|
104
|
+
var result = PrepareEvent(eventName, parameters);
|
|
105
|
+
eventQueue.Enqueue(result);
|
|
99
106
|
return result;
|
|
100
107
|
}
|
|
101
108
|
|
|
@@ -113,6 +120,24 @@ namespace Amanotes.Core
|
|
|
113
120
|
{
|
|
114
121
|
return LogEvent(eventName, parameters).SetAsFunnel(signature);
|
|
115
122
|
}
|
|
123
|
+
|
|
124
|
+
public static void LogEventImmediately(string eventName)
|
|
125
|
+
{
|
|
126
|
+
var eventParams = PrepareEvent(eventName);
|
|
127
|
+
LogEventImmediately(eventParams);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public static void LogEventImmediately(string eventName, Dictionary<string, object> parameters)
|
|
131
|
+
{
|
|
132
|
+
var eventParams = PrepareEvent(eventName, parameters);
|
|
133
|
+
LogEventImmediately(eventParams);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public static void LogEventImmediately(string eventName, params (string, object)[] parameters)
|
|
137
|
+
{
|
|
138
|
+
var eventParams = PrepareEvent(eventName, parameters);
|
|
139
|
+
LogEventImmediately(eventParams);
|
|
140
|
+
}
|
|
116
141
|
|
|
117
142
|
public static int GetAccumulatedCount(string eventName, bool withinSession = false)
|
|
118
143
|
{
|
|
@@ -128,12 +153,18 @@ namespace Amanotes.Core
|
|
|
128
153
|
|
|
129
154
|
public static void SetUserId(string userId)
|
|
130
155
|
{
|
|
131
|
-
|
|
156
|
+
foreach (AnalyticsAdapter s in listAdapters)
|
|
157
|
+
{
|
|
158
|
+
s.SetUserId(userId);
|
|
159
|
+
}
|
|
132
160
|
}
|
|
133
161
|
|
|
134
162
|
public static void SetUserProperty(string key, string value)
|
|
135
163
|
{
|
|
136
|
-
|
|
164
|
+
foreach (AnalyticsAdapter s in listAdapters)
|
|
165
|
+
{
|
|
166
|
+
s.SetUserProperty(key, value);
|
|
167
|
+
}
|
|
137
168
|
}
|
|
138
169
|
|
|
139
170
|
private static IntegrityFlag MergeData(List<string> funnelEvents, Dictionary<string, int> eventCountMap, bool sumEventCount)
|
|
@@ -151,12 +182,13 @@ namespace Amanotes.Core
|
|
|
151
182
|
}
|
|
152
183
|
|
|
153
184
|
if (eventCountMap != null)
|
|
185
|
+
{
|
|
154
186
|
foreach (KeyValuePair<string, int> e in eventCountMap)
|
|
155
187
|
{
|
|
156
188
|
EventDetail eventDetail = localData.GetEventDetail(e.Key);
|
|
157
189
|
if (eventDetail == null)
|
|
158
190
|
{
|
|
159
|
-
localData.
|
|
191
|
+
localData.AddEventDetail(new EventDetail
|
|
160
192
|
{
|
|
161
193
|
eventName = e.Key,
|
|
162
194
|
totalCount = e.Value
|
|
@@ -175,6 +207,8 @@ namespace Amanotes.Core
|
|
|
175
207
|
eventDetail.totalCount += e.Value;
|
|
176
208
|
}
|
|
177
209
|
}
|
|
210
|
+
}
|
|
211
|
+
|
|
178
212
|
|
|
179
213
|
Profiler.EndSample();
|
|
180
214
|
return flag;
|
|
@@ -237,11 +271,12 @@ namespace Amanotes.Core
|
|
|
237
271
|
|
|
238
272
|
internal static readonly Dictionary<string, EventConfig> sendAtCount = new Dictionary<string, EventConfig>();
|
|
239
273
|
internal static Predicate<EventParams> logEventHook;
|
|
240
|
-
internal static readonly
|
|
241
|
-
internal static readonly Queue<Action> actionQueue = new Queue<Action>();
|
|
274
|
+
internal static readonly ConcurrentQueue<EventParams> eventQueue = new ConcurrentQueue<EventParams>();
|
|
242
275
|
internal static readonly List<AnalyticsAdapter> listAdapters = new List<AnalyticsAdapter>();
|
|
243
|
-
internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile();
|
|
244
|
-
internal static readonly SessionStat sessionStat = new SessionStat();
|
|
276
|
+
internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile().BuildCache();
|
|
277
|
+
internal static readonly SessionStat sessionStat = _config.analytics.enableEventStat ? new SessionStat() : null;
|
|
278
|
+
internal static readonly Pool<StringBuilder> sbPool = new Pool<StringBuilder>(3);
|
|
279
|
+
internal static readonly Pool<EventParams> epPool = new Pool<EventParams>(1);
|
|
245
280
|
|
|
246
281
|
internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
|
|
247
282
|
{
|
|
@@ -298,68 +333,109 @@ namespace Amanotes.Core
|
|
|
298
333
|
// TODO: Refactor Resolve Early Calls
|
|
299
334
|
onFrameUpdate -= ProcessEventQueue;
|
|
300
335
|
onFrameUpdate += ProcessEventQueue;
|
|
301
|
-
|
|
302
|
-
onFrameUpdate -= ProcessActionQueue;
|
|
303
|
-
onFrameUpdate += ProcessActionQueue;
|
|
304
336
|
}
|
|
305
|
-
|
|
337
|
+
|
|
338
|
+
internal static EventParams PrepareEvent(string eventName)
|
|
339
|
+
{
|
|
340
|
+
PrepareEventCheck(eventName);
|
|
341
|
+
var result = epPool.Get().Init(eventName);
|
|
342
|
+
PostPrepareEventProcess(result);
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
internal static EventParams PrepareEvent(string eventName, Dictionary<string, object> parameters)
|
|
347
|
+
{
|
|
348
|
+
if (parameters == null) return PrepareEvent(eventName);
|
|
349
|
+
PrepareEventCheck(eventName);
|
|
350
|
+
var result = epPool.Get().Init(eventName);
|
|
351
|
+
result.AddParam(parameters);
|
|
352
|
+
PostPrepareEventProcess(result);
|
|
353
|
+
return result;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
internal static EventParams PrepareEvent(string eventName, params (string, object)[] parameters)
|
|
357
|
+
{
|
|
358
|
+
if (parameters == null) return PrepareEvent(eventName);
|
|
359
|
+
PrepareEventCheck(eventName);
|
|
360
|
+
var result = epPool.Get().Init(eventName);
|
|
361
|
+
for (var i = 0; i < parameters.Length; i++)
|
|
362
|
+
{
|
|
363
|
+
result.AddParam(parameters[i].Item1, parameters[i].Item2);
|
|
364
|
+
}
|
|
365
|
+
PostPrepareEventProcess(result);
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
|
|
306
369
|
internal static void ProcessEventQueue()
|
|
307
370
|
{
|
|
308
371
|
if (eventQueue.Count <= 0) return;
|
|
309
372
|
|
|
310
373
|
Profiler.BeginSample("AmaGDK.Analytics.ProcessEventQueue()");
|
|
311
|
-
AnalyticsConfig config = Config.analytics;
|
|
312
|
-
bool showAnalyticsLog = config.showAnalyticsLog;
|
|
313
|
-
sessionStat.ClearLastFrameEventInfo();
|
|
314
374
|
|
|
315
|
-
|
|
375
|
+
sessionStat?.Clear();
|
|
376
|
+
|
|
377
|
+
while (eventQueue.TryDequeue(out var eventData))
|
|
316
378
|
{
|
|
317
|
-
var
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (eventData.accumulated || eventData.parameters.ContainsKey("accumulated_count"))
|
|
322
|
-
{
|
|
323
|
-
UpdateAccumulatedCount(eventData, countInSession, totalCount);
|
|
324
|
-
}
|
|
379
|
+
var (eventNameToSend, inUseAdapterIDs) = LogEventActually(eventData);
|
|
380
|
+
sessionStat?.Add(eventNameToSend, eventData, inUseAdapterIDs);
|
|
381
|
+
epPool.Return(eventData);
|
|
382
|
+
}
|
|
325
383
|
|
|
326
|
-
|
|
327
|
-
|
|
384
|
+
localData.SaveIfDirty();
|
|
385
|
+
sessionStat?.Save();
|
|
386
|
+
Profiler.EndSample();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
internal static (string eventNameToSend, List<string> inUseAdapterIDs) LogEventActually(EventParams eventParams)
|
|
390
|
+
{
|
|
391
|
+
if (eventParams == null) return ("", null);
|
|
392
|
+
if (!ShouldSendEvent(eventParams)) return ("", null);
|
|
393
|
+
var (countInSession, totalCount) = localData.IncreaseCounter(eventParams);
|
|
394
|
+
if (eventParams.accumulated || eventParams.parameters.ContainsKey("accumulated_count"))
|
|
395
|
+
{
|
|
396
|
+
UpdateAccumulatedCount(eventParams, countInSession, totalCount);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
string eventNameToSend = GetEventNameToSend(eventParams.eventName, countInSession, totalCount);
|
|
400
|
+
AnalyticsConfig config = Config.analytics;
|
|
401
|
+
if (config.normalizeEventName) NormalizeEventName(ref eventNameToSend);
|
|
402
|
+
|
|
403
|
+
if (config.showAnalyticsLog)
|
|
404
|
+
{
|
|
405
|
+
Debug.Log($"AmaGDK [Analytics] Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventParams.parameters, true)}");
|
|
406
|
+
}
|
|
328
407
|
|
|
329
|
-
|
|
330
|
-
if (config.normalizeEventName) NormalizeEventName(ref eventNameToSend);
|
|
408
|
+
config.quality.CheckEventQuality(eventParams.eventName, eventParams.parameters);
|
|
331
409
|
|
|
332
|
-
|
|
410
|
+
var inUseAdapterIDs = config.enableEventStat ? new List<string>(listAdapters.Count) : null;
|
|
411
|
+
foreach (AnalyticsAdapter m in listAdapters)
|
|
412
|
+
{
|
|
413
|
+
if (eventParams.overrideConfig)
|
|
333
414
|
{
|
|
334
|
-
|
|
415
|
+
// IMPORTANT NOTE:
|
|
416
|
+
//
|
|
417
|
+
// Once set overrideConfig, we should skip the adapter config completely!!!
|
|
418
|
+
//
|
|
419
|
+
if (eventParams.IsAdapterForbidden(m.adapterId)) continue;
|
|
335
420
|
}
|
|
336
|
-
|
|
337
|
-
config.quality.CheckEventQuality(eventData.eventName, eventData.parameters);
|
|
338
|
-
|
|
339
|
-
var inUseAdapterIDs = new List<string>();
|
|
340
|
-
foreach (AnalyticsAdapter m in listAdapters)
|
|
421
|
+
else // Do not remove else
|
|
341
422
|
{
|
|
342
|
-
if (
|
|
343
|
-
{
|
|
344
|
-
// IMPORTANT NOTE:
|
|
345
|
-
//
|
|
346
|
-
// Once set overrideConfig, we should skip the adapter config completely!!!
|
|
347
|
-
//
|
|
348
|
-
if (eventData.IsAdapterForbidden(m.adapterId)) continue;
|
|
349
|
-
}
|
|
350
|
-
else // Do not remove else
|
|
351
|
-
{
|
|
352
|
-
if (m.IsForbidden(eventData.eventName)) continue;
|
|
353
|
-
}
|
|
354
|
-
m.LogEvent(eventNameToSend, eventData.parameters);
|
|
355
|
-
inUseAdapterIDs.Add(m.adapterId);
|
|
423
|
+
if (m.IsForbidden(eventParams.eventName)) continue;
|
|
356
424
|
}
|
|
357
|
-
|
|
425
|
+
m.LogEvent(eventNameToSend, eventParams.parameters);
|
|
426
|
+
inUseAdapterIDs?.Add(m.adapterId);
|
|
358
427
|
}
|
|
359
428
|
|
|
429
|
+
return (eventNameToSend, inUseAdapterIDs);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
internal static void LogEventImmediately(EventParams eventParams)
|
|
433
|
+
{
|
|
434
|
+
var (eventNameToSend, inUseAdapterIDs) = LogEventActually(eventParams);
|
|
435
|
+
sessionStat?.Add(eventNameToSend, eventParams, inUseAdapterIDs);
|
|
436
|
+
epPool.Return(eventParams);
|
|
437
|
+
sessionStat?.Save();
|
|
360
438
|
localData.SaveIfDirty();
|
|
361
|
-
sessionStat.Save();
|
|
362
|
-
Profiler.EndSample();
|
|
363
439
|
}
|
|
364
440
|
|
|
365
441
|
internal static void UpdateAccumulatedCount(EventParams eventData, int countInSession, int totalCount)
|
|
@@ -399,19 +475,20 @@ namespace Amanotes.Core
|
|
|
399
475
|
{
|
|
400
476
|
Profiler.BeginSample("AmaGDK.Analytics.NormalizeEventName()");
|
|
401
477
|
{
|
|
402
|
-
StringBuilder sb =
|
|
478
|
+
StringBuilder sb = sbPool.Get();
|
|
403
479
|
sb.Clear();
|
|
404
480
|
NormalizeKeyString(ref eventName, sb, dryRun);
|
|
405
481
|
if (reservedEvents.Contains(eventName))
|
|
406
482
|
sb.AppendLine($" - EventName <{eventName}> is reserved and should not be used");
|
|
407
|
-
if (sb.Length > 0 && dryRun) LogWarningOnce($"Warning for event name <{eventName}>:\n{sb}", $"NormalizeEventName<{eventName}>");
|
|
483
|
+
if (sb.Length > 0 && dryRun) LogWarningOnce($"Warning for event name <{eventName}>:\n{sb}", $"NormalizeEventName<{eventName}>");
|
|
484
|
+
sbPool.Return(sb);
|
|
408
485
|
}
|
|
409
486
|
Profiler.EndSample();
|
|
410
487
|
}
|
|
411
488
|
|
|
412
489
|
internal static void NormalizeKeyString(ref string key, StringBuilder warningLog, bool dryRun)
|
|
413
490
|
{
|
|
414
|
-
Profiler.BeginSample("AmaGDK.Analytics.
|
|
491
|
+
Profiler.BeginSample("AmaGDK.Analytics.NormalizeKeyString()");
|
|
415
492
|
{
|
|
416
493
|
if (string.IsNullOrWhiteSpace(key))
|
|
417
494
|
{
|
|
@@ -420,52 +497,114 @@ namespace Amanotes.Core
|
|
|
420
497
|
return;
|
|
421
498
|
}
|
|
422
499
|
|
|
423
|
-
var
|
|
500
|
+
var tempLog = Config.common.logLevel == LogLevel.None ? null : sbPool.Get();
|
|
501
|
+
tempLog?.Clear();
|
|
502
|
+
|
|
503
|
+
var tempKey = sbPool.Get();
|
|
504
|
+
tempKey.Clear();
|
|
505
|
+
|
|
506
|
+
var hasChanged = false;
|
|
507
|
+
var trimKey = key.Trim();
|
|
424
508
|
|
|
425
|
-
|
|
426
|
-
.Replace(' ', '_')
|
|
427
|
-
.Replace('-', '_');
|
|
428
|
-
if (key != normalizedString)
|
|
509
|
+
foreach (var c in trimKey)
|
|
429
510
|
{
|
|
430
|
-
|
|
511
|
+
var isLetter = IsAlphabet(c);
|
|
512
|
+
var isNumber = char.IsDigit(c);
|
|
513
|
+
|
|
514
|
+
if (c == '_' || isLetter || isNumber)
|
|
515
|
+
{
|
|
516
|
+
tempKey.Append(c);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
hasChanged = true;
|
|
521
|
+
if (c == ' ' || c == '-')
|
|
522
|
+
{
|
|
523
|
+
tempKey.Append('_');
|
|
524
|
+
}
|
|
431
525
|
}
|
|
432
526
|
|
|
433
|
-
|
|
434
|
-
if (!r.IsMatch(normalizedString))
|
|
527
|
+
if (hasChanged)
|
|
435
528
|
{
|
|
436
|
-
|
|
437
|
-
sb.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
529
|
+
tempLog?.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
438
530
|
}
|
|
439
|
-
|
|
440
|
-
if (!
|
|
531
|
+
|
|
532
|
+
if (tempKey.Length > 0 && !IsAlphabet(tempKey[0]))
|
|
441
533
|
{
|
|
442
|
-
|
|
443
|
-
|
|
534
|
+
hasChanged = true;
|
|
535
|
+
tempKey.Insert(0, 'E');
|
|
536
|
+
tempLog?.Append($" - Name must start with a letter: <{key}>");
|
|
444
537
|
}
|
|
445
|
-
|
|
538
|
+
|
|
446
539
|
foreach (var prefix in reservedPrefixes)
|
|
447
540
|
{
|
|
448
|
-
if (!
|
|
449
|
-
|
|
450
|
-
|
|
541
|
+
if (tempKey.Length < prefix.Key.Length || !StringStartsWith(tempKey, prefix.Key)) continue;
|
|
542
|
+
hasChanged = true;
|
|
543
|
+
tempKey.Remove(0, prefix.Key.Length);
|
|
544
|
+
tempKey.Insert(0, prefix.Value);
|
|
545
|
+
tempLog?.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
|
|
451
546
|
}
|
|
452
547
|
|
|
453
|
-
if (
|
|
548
|
+
if (trimKey.Length > 40)
|
|
454
549
|
{
|
|
455
|
-
|
|
456
|
-
|
|
550
|
+
hasChanged = true;
|
|
551
|
+
tempLog?.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
|
|
552
|
+
tempKey.Length = 40;
|
|
457
553
|
}
|
|
458
554
|
|
|
459
555
|
if (dryRun)
|
|
460
556
|
{
|
|
461
|
-
warningLog.Append(
|
|
557
|
+
warningLog.Append(tempLog);
|
|
462
558
|
} else {
|
|
463
|
-
key =
|
|
559
|
+
if (hasChanged) key = tempKey.ToString();
|
|
464
560
|
}
|
|
561
|
+
|
|
562
|
+
if (tempLog != null) sbPool.Return(tempLog);
|
|
563
|
+
sbPool.Return(tempKey);
|
|
465
564
|
}
|
|
466
565
|
Profiler.EndSample();
|
|
467
566
|
}
|
|
468
567
|
|
|
568
|
+
private static bool StringStartsWith(StringBuilder stringBuilder, string prefix)
|
|
569
|
+
{
|
|
570
|
+
if (stringBuilder == null || prefix == null)
|
|
571
|
+
return false;
|
|
572
|
+
|
|
573
|
+
if (stringBuilder.Length < prefix.Length)
|
|
574
|
+
return false;
|
|
575
|
+
|
|
576
|
+
for (int i = 0; i < prefix.Length; i++)
|
|
577
|
+
{
|
|
578
|
+
if (stringBuilder[i] != prefix[i])
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private static bool IsAlphabet(char c)
|
|
586
|
+
{
|
|
587
|
+
if (c >= 'A' && c <= 'Z') return true;
|
|
588
|
+
if (c >= 'a' && c <= 'z') return true;
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
internal static void PrepareEventCheck(string eventName)
|
|
593
|
+
{
|
|
594
|
+
NormalizeEventName(ref eventName, true);
|
|
595
|
+
|
|
596
|
+
if (localData.GetEventDetail(eventName) == null && localData.totalEventDetailCount >= 500)
|
|
597
|
+
{
|
|
598
|
+
LogWarning($" - You have reported 500 types of events. New event <{eventName}> will be ignored.");
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
internal static void PostPrepareEventProcess(EventParams eventData)
|
|
603
|
+
{
|
|
604
|
+
if (!eventData.parameters.ContainsKey("ama_device_id"))
|
|
605
|
+
eventData.AddParam("ama_device_id", User.AmaDeviceId);
|
|
606
|
+
}
|
|
607
|
+
|
|
469
608
|
internal static bool ShouldSendEvent(EventParams eventData)
|
|
470
609
|
{
|
|
471
610
|
//Funnel event
|
|
@@ -489,33 +628,6 @@ namespace Amanotes.Core
|
|
|
489
628
|
|
|
490
629
|
return true;
|
|
491
630
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
internal static void ProcessActionQueue()
|
|
495
|
-
{
|
|
496
|
-
if (actionQueue.Count <= 0) return;
|
|
497
|
-
while (actionQueue.Count > 0)
|
|
498
|
-
{
|
|
499
|
-
var action = actionQueue.Dequeue();
|
|
500
|
-
action.Invoke();
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
internal static void InternalSetUserId(string userId)
|
|
505
|
-
{
|
|
506
|
-
foreach (AnalyticsAdapter s in listAdapters)
|
|
507
|
-
{
|
|
508
|
-
s.SetUserId(userId);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
internal static void InternalSetUserProperty(string key, string value)
|
|
513
|
-
{
|
|
514
|
-
foreach (AnalyticsAdapter s in listAdapters)
|
|
515
|
-
{
|
|
516
|
-
s.SetUserProperty(key, value);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
631
|
}
|
|
520
632
|
|
|
521
633
|
//PERSISTENT DATA
|
|
@@ -583,23 +695,63 @@ namespace Amanotes.Core
|
|
|
583
695
|
internal class AnalyticsData : IJsonFile
|
|
584
696
|
{
|
|
585
697
|
public List<string> funnelSignatures = new List<string>();
|
|
586
|
-
|
|
698
|
+
|
|
587
699
|
public MigrationLog migrationLog = new MigrationLog();
|
|
588
700
|
[NonSerialized] internal bool _dirty;
|
|
589
|
-
|
|
701
|
+
|
|
702
|
+
[SerializeField] internal List<EventDetail> eventDetails = new List<EventDetail>();
|
|
703
|
+
internal readonly Dictionary<string, EventDetail> cachedEventDetails = new Dictionary<string, EventDetail>();
|
|
704
|
+
|
|
705
|
+
public int totalEventDetailCount => eventDetails.Count;
|
|
706
|
+
public bool AddEventDetail(EventDetail ed)
|
|
707
|
+
{
|
|
708
|
+
if (cachedEventDetails.ContainsKey(ed.eventName))
|
|
709
|
+
{
|
|
710
|
+
Debug.LogWarning($"EventName <{ed.eventName}> existed!");
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
eventDetails.Add(ed);
|
|
715
|
+
cachedEventDetails.Add(ed.eventName, ed);
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
internal AnalyticsData BuildCache()
|
|
720
|
+
{
|
|
721
|
+
if (cachedEventDetails.Count > 0)
|
|
722
|
+
{
|
|
723
|
+
LogWarning("BuildCache should be called once!");
|
|
724
|
+
cachedEventDetails.Clear();
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
for (var i = 0; i < eventDetails.Count; i++)
|
|
728
|
+
{
|
|
729
|
+
var item = eventDetails[i];
|
|
730
|
+
if (cachedEventDetails.ContainsKey(item.eventName))
|
|
731
|
+
{
|
|
732
|
+
LogWarning($"Duplicated eventName <{item.eventName}> entry found in AnalyticData!");
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
cachedEventDetails.Add(item.eventName, item);
|
|
736
|
+
}
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
|
|
590
740
|
internal EventDetail GetEventDetail(string eventName, bool autoNew = false)
|
|
591
741
|
{
|
|
592
742
|
if (string.IsNullOrEmpty(eventName)) return null;
|
|
593
743
|
|
|
594
|
-
|
|
595
|
-
|
|
744
|
+
if (cachedEventDetails.TryGetValue(eventName, out var result))
|
|
745
|
+
{
|
|
746
|
+
return result;
|
|
747
|
+
}
|
|
596
748
|
if (autoNew == false) return null;
|
|
597
749
|
|
|
598
750
|
result = new EventDetail
|
|
599
751
|
{
|
|
600
752
|
eventName = eventName
|
|
601
753
|
};
|
|
602
|
-
|
|
754
|
+
AddEventDetail(result);
|
|
603
755
|
_dirty = true;
|
|
604
756
|
return result;
|
|
605
757
|
}
|
|
@@ -645,7 +797,7 @@ namespace Amanotes.Core
|
|
|
645
797
|
migrationLog.count++;
|
|
646
798
|
Log($"Analytics data was migrated {migrationLog.count} times");
|
|
647
799
|
|
|
648
|
-
if (migrationLog.count == 2) LogEvent("migration_error"
|
|
800
|
+
if (migrationLog.count == 2) LogEvent("migration_error", migrationLog.ToDictionary());
|
|
649
801
|
}
|
|
650
802
|
|
|
651
803
|
_dirty = true;
|
|
@@ -659,36 +811,44 @@ namespace Amanotes.Core
|
|
|
659
811
|
private readonly string fileName = nameof(SessionStat) + DateTime.Now.ToString("_yyMMdd_HHmmss") + ".tsv";
|
|
660
812
|
private StringBuilder contents = new StringBuilder();
|
|
661
813
|
private bool isFirstSave = true;
|
|
662
|
-
|
|
814
|
+
private readonly ConcurrentQueue<EventStat> lastFrameEventStats = new ConcurrentQueue<EventStat>();
|
|
815
|
+
internal readonly ConcurrentQueue<EventStat> savedEventStatsInLastFrame = new ConcurrentQueue<EventStat>();
|
|
663
816
|
|
|
664
817
|
internal void Add(string eventNameToSend, EventParams eventParams, List<string> adapterIDs)
|
|
665
818
|
{
|
|
819
|
+
if (string.IsNullOrEmpty(eventNameToSend) || adapterIDs == null) return;
|
|
666
820
|
var eventStat = new EventStat(eventNameToSend, eventParams, adapterIDs);
|
|
667
|
-
lastFrameEventStats.
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
internal void ClearLastFrameEventInfo()
|
|
671
|
-
{
|
|
672
|
-
lastFrameEventStats.Clear();
|
|
821
|
+
lastFrameEventStats.Enqueue(eventStat);
|
|
673
822
|
}
|
|
674
823
|
|
|
675
824
|
internal void Save()
|
|
676
825
|
{
|
|
677
|
-
if (!Config.analytics.enableEventStat || lastFrameEventStats.Count == 0) return;
|
|
678
|
-
|
|
679
826
|
contents.Clear();
|
|
680
827
|
if (isFirstSave)
|
|
681
828
|
{
|
|
682
829
|
contents = contents.AppendLine(TSV_HEADER_ROW);
|
|
683
830
|
isFirstSave = false;
|
|
684
831
|
}
|
|
685
|
-
|
|
832
|
+
while (lastFrameEventStats.TryDequeue(out var stat))
|
|
686
833
|
{
|
|
687
834
|
contents.AppendLine(stat.ToTsv());
|
|
835
|
+
savedEventStatsInLastFrame.Enqueue(stat);
|
|
688
836
|
}
|
|
689
837
|
|
|
690
838
|
GDKFileUtils.SaveAppend(fileName, contents.ToString());
|
|
691
839
|
}
|
|
840
|
+
|
|
841
|
+
internal void Clear()
|
|
842
|
+
{
|
|
843
|
+
//Clear() is supported from .Net Standard 2.1
|
|
844
|
+
#if UNITY_2021_3_OR_NEWER
|
|
845
|
+
sessionStat?.savedEventStatsInLastFrame.Clear();
|
|
846
|
+
#else
|
|
847
|
+
while (savedEventStatsInLastFrame.TryDequeue(out var stat))
|
|
848
|
+
{
|
|
849
|
+
}
|
|
850
|
+
#endif
|
|
851
|
+
}
|
|
692
852
|
}
|
|
693
853
|
}
|
|
694
854
|
}
|
|
@@ -740,6 +900,8 @@ namespace Amanotes.Core
|
|
|
740
900
|
}
|
|
741
901
|
|
|
742
902
|
eventData.overrideConfig = true;
|
|
903
|
+
eventData.ignoreAdapterIds ??= new HashSet<string>();
|
|
904
|
+
|
|
743
905
|
foreach (string mId in analyticIds)
|
|
744
906
|
{
|
|
745
907
|
eventData.ignoreAdapterIds.Add(mId);
|
|
@@ -764,6 +926,8 @@ namespace Amanotes.Core
|
|
|
764
926
|
}
|
|
765
927
|
|
|
766
928
|
eventData.overrideConfig = true;
|
|
929
|
+
eventData.allowAdapterIds ??= new HashSet<string>();
|
|
930
|
+
|
|
767
931
|
foreach (string mId in analyticIds)
|
|
768
932
|
{
|
|
769
933
|
eventData.allowAdapterIds.Add(mId);
|
|
@@ -771,7 +935,7 @@ namespace Amanotes.Core
|
|
|
771
935
|
return ap;
|
|
772
936
|
}
|
|
773
937
|
|
|
774
|
-
|
|
938
|
+
internal static IEventParamsBuilder AddParam(this IEventParamsBuilder ap, string key, object value)
|
|
775
939
|
{
|
|
776
940
|
if (ap == null) return null;
|
|
777
941
|
if (!IsValidKeyValue(ap, ref key, ref value)) return ap;
|
|
@@ -795,7 +959,7 @@ namespace Amanotes.Core
|
|
|
795
959
|
return ap;
|
|
796
960
|
}
|
|
797
961
|
|
|
798
|
-
|
|
962
|
+
internal static IEventParamsBuilder AddParam(this IEventParamsBuilder ap, Dictionary<string, object> dictParams)
|
|
799
963
|
{
|
|
800
964
|
if (ap == null) return null;
|
|
801
965
|
if (dictParams == null)
|
|
@@ -814,7 +978,7 @@ namespace Amanotes.Core
|
|
|
814
978
|
return ap;
|
|
815
979
|
}
|
|
816
980
|
|
|
817
|
-
|
|
981
|
+
internal static IEventParamsBuilder AddParam(this IEventParamsBuilder ap, params (string key, object value)[] parameters)
|
|
818
982
|
{
|
|
819
983
|
if (ap == null) return null;
|
|
820
984
|
if (parameters.Length == 0)
|
|
@@ -838,11 +1002,12 @@ namespace Amanotes.Core
|
|
|
838
1002
|
{
|
|
839
1003
|
string eventName = (ap as EventParams)?.eventName;
|
|
840
1004
|
|
|
841
|
-
StringBuilder sb =
|
|
1005
|
+
StringBuilder sb = sbPool.Get();
|
|
842
1006
|
sb.Clear();
|
|
843
1007
|
NormalizeKeyString(ref key, sb, AmaGDK.Config.analytics.normalizeEventName);
|
|
844
1008
|
|
|
845
1009
|
if (sb.Length > 0) LogWarningOnce($"Warning for event <{eventName}>, param <{key}>:\n{sb}", $"NormalizeParamKey <{eventName}>");
|
|
1010
|
+
sbPool.Return(sb);
|
|
846
1011
|
|
|
847
1012
|
if (string.IsNullOrWhiteSpace(key))
|
|
848
1013
|
{
|