com.amanotes.gdk 0.2.47 → 0.2.49

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/Editor/AmaGDKEditor.cs +133 -65
  3. package/Editor/AmaGDKExtra.cs +31 -0
  4. package/Editor/AmaGDKExtra.cs.meta +11 -0
  5. package/Editor/Utils/AmaGDKEditor.ExtractVersion.cs +1 -1
  6. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  7. package/Extra/AmaGDKProject.unitypackage +0 -0
  8. package/Extra/SDKVersionTracking.unitypackage +0 -0
  9. package/Extra/SDKVersionTracking.unitypackage.meta +7 -0
  10. package/Packages/AmaGDKConfig.unitypackage +0 -0
  11. package/Packages/AmaGDKExample.unitypackage +0 -0
  12. package/Packages/AmaGDKTest.unitypackage +0 -0
  13. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  14. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  15. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  16. package/Packages/IronSourceAdapter.unitypackage +0 -0
  17. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  18. package/Runtime/AmaGDK.Adapters.cs +0 -4
  19. package/Runtime/AmaGDK.Ads.cs +89 -29
  20. package/Runtime/AmaGDK.Analytics.cs +97 -64
  21. package/Runtime/AmaGDK.IAP.cs +39 -45
  22. package/Runtime/AmaGDK.RemoteConfig.cs +76 -52
  23. package/Runtime/AmaGDK.UserProfile.cs +106 -124
  24. package/Runtime/AmaGDK.cs +46 -35
  25. package/Runtime/Internal/AmaGDK.Event.cs +185 -0
  26. package/Runtime/Internal/AmaGDK.Event.cs.meta +3 -0
  27. package/Runtime/Internal/AmaGDK.Internal.cs +3 -0
  28. package/Runtime/Internal/AmaGDK.Utils.cs +85 -24
  29. package/Runtime/Klavar/Attributes/AccumulatedCountAttribute.cs +19 -0
  30. package/Runtime/Klavar/Attributes/AccumulatedCountAttribute.cs.meta +11 -0
  31. package/Runtime/Klavar/Attributes/ConnectionAttribute.cs +18 -0
  32. package/Runtime/Klavar/Attributes/ConnectionAttribute.cs.meta +11 -0
  33. package/Runtime/Klavar/Attributes/CountInSessionAttribute.cs +27 -0
  34. package/Runtime/Klavar/Attributes/CountInSessionAttribute.cs.meta +11 -0
  35. package/Runtime/Klavar/Attributes/DescriptionAttribute.cs +7 -0
  36. package/Runtime/Klavar/Attributes/DescriptionAttribute.cs.meta +11 -0
  37. package/Runtime/Klavar/Attributes/DynamicValidateAttribute.cs +30 -0
  38. package/Runtime/Klavar/Attributes/DynamicValidateAttribute.cs.meta +11 -0
  39. package/Runtime/Klavar/Attributes/IgnoreAttribute.cs +16 -0
  40. package/Runtime/Klavar/Attributes/IgnoreAttribute.cs.meta +11 -0
  41. package/Runtime/Klavar/Attributes/MinMaxAttribute.cs +130 -0
  42. package/Runtime/Klavar/Attributes/MinMaxAttribute.cs.meta +11 -0
  43. package/Runtime/Klavar/Attributes/MinMaxLengthAttribute.cs +88 -0
  44. package/Runtime/Klavar/Attributes/MinMaxLengthAttribute.cs.meta +11 -0
  45. package/Runtime/Klavar/Attributes/NameAttribute.cs +35 -0
  46. package/Runtime/Klavar/Attributes/NameAttribute.cs.meta +11 -0
  47. package/Runtime/Klavar/Attributes/NotNullAttribute.cs +16 -0
  48. package/Runtime/Klavar/Attributes/NotNullAttribute.cs.meta +11 -0
  49. package/Runtime/Klavar/Attributes/RegexPatternAttribute.cs +58 -0
  50. package/Runtime/Klavar/Attributes/RegexPatternAttribute.cs.meta +11 -0
  51. package/Runtime/Klavar/Attributes/TimeDiffLastFireAttribute.cs +28 -0
  52. package/Runtime/Klavar/Attributes/TimeDiffLastFireAttribute.cs.meta +11 -0
  53. package/Runtime/Klavar/Attributes/ToStringAttribute.cs +97 -0
  54. package/Runtime/Klavar/Attributes/ToStringAttribute.cs.meta +11 -0
  55. package/Runtime/Klavar/Attributes/ValueAttribute.cs +30 -0
  56. package/Runtime/Klavar/Attributes/ValueAttribute.cs.meta +11 -0
  57. package/Runtime/Klavar/Attributes.meta +8 -0
  58. package/Runtime/Klavar/KlavarEvent.cs +91 -0
  59. package/Runtime/Klavar/KlavarEvent.cs.meta +11 -0
  60. package/Runtime/Klavar/KlavarEventAttribute.cs +39 -0
  61. package/Runtime/Klavar/KlavarEventAttribute.cs.meta +11 -0
  62. package/Runtime/Klavar/KlavarEventTools.cs +92 -0
  63. package/Runtime/Klavar/KlavarEventTools.cs.meta +11 -0
  64. package/Runtime/Klavar/KlavarEventUtils.cs +58 -0
  65. package/Runtime/Klavar/KlavarEventUtils.cs.meta +11 -0
  66. package/Runtime/{Core.meta → Klavar.meta} +1 -1
  67. package/package.json +1 -1
@@ -9,6 +9,8 @@ using static Amanotes.Core.AmaGDK;
9
9
 
10
10
  namespace Amanotes.Core
11
11
  {
12
+
13
+
12
14
  public static class AdExtension
13
15
  {
14
16
  public static IAdCallback OnAdOpened(this IAdCallback ad, Action callback)
@@ -18,7 +20,7 @@ namespace Amanotes.Core
18
20
  Ads.context.onOpened += callback;
19
21
  return ad;
20
22
  }
21
-
23
+
22
24
  public static IAdCallback OnRewardReceived(this IAdCallback ad, Action callback)
23
25
  {
24
26
  if (!MakeSureAdNotNull(ad)) return null;
@@ -26,7 +28,7 @@ namespace Amanotes.Core
26
28
  Ads.context.onRewardReceived += callback;
27
29
  return ad;
28
30
  }
29
-
31
+
30
32
  public static IAdCallback OnAdClicked(this IAdCallback ad, Action callback)
31
33
  {
32
34
  if (!MakeSureAdNotNull(ad)) return null;
@@ -34,7 +36,7 @@ namespace Amanotes.Core
34
36
  Ads.context.onClicked += callback;
35
37
  return ad;
36
38
  }
37
-
39
+
38
40
  public static IAdCallback OnAdShowFailed(this IAdCallback ad, Action callback)
39
41
  {
40
42
  if (!MakeSureAdNotNull(ad)) return null;
@@ -42,7 +44,7 @@ namespace Amanotes.Core
42
44
  Ads.context.onShowFailed += callback;
43
45
  return ad;
44
46
  }
45
-
47
+
46
48
  public static IAdCallback OnAdShowSuccess(this IAdCallback ad, Action callback)
47
49
  {
48
50
  if (!MakeSureAdNotNull(ad)) return null;
@@ -50,7 +52,7 @@ namespace Amanotes.Core
50
52
  Ads.context.onShowSuccess += callback;
51
53
  return ad;
52
54
  }
53
-
55
+
54
56
  public static IAdCallback OnAdClosed(this IAdCallback ad, Action callback)
55
57
  {
56
58
  if (!MakeSureAdNotNull(ad)) return null;
@@ -99,6 +101,27 @@ namespace Amanotes.Core
99
101
  }
100
102
  public partial class AmaGDK // Ads module
101
103
  {
104
+ public static partial class Event
105
+ {
106
+ public const string INTER_REQUEST = nameof(INTER_REQUEST);
107
+ public const string INTER_SHOW_CALLED = nameof(INTER_SHOW_CALLED);
108
+ public const string INTER_SHOW_READY = nameof(INTER_SHOW_READY);
109
+ public const string INTER_SHOW_NOT_READY = nameof(INTER_SHOW_NOT_READY); // reason: string
110
+ public const string INTER_SHOW_BEGIN = nameof(INTER_SHOW_BEGIN); // always call result: true / false
111
+ public const string INTER_SHOW_END = nameof(INTER_SHOW_END); // always call result: true / false
112
+
113
+ public const string REWARD_REQUEST = nameof(REWARD_REQUEST);
114
+ public const string REWARD_VIDEO_SHOW_CALLED = nameof(REWARD_VIDEO_SHOW_CALLED);
115
+ public const string REWARD_VIDEO_SHOW_READY = nameof(REWARD_VIDEO_SHOW_READY);
116
+ public const string REWARD_VIDEO_SHOW_NOT_READY = nameof(REWARD_VIDEO_SHOW_NOT_READY); // reason: string
117
+ // public const string REWARD_VIDEO_REWARD_GRANTED = nameof(REWARD_VIDEO_REWARD_GRANTED);
118
+ public const string REWARD_VIDEO_SHOW_BEGIN = nameof(REWARD_VIDEO_SHOW_BEGIN); // always call result: true / false
119
+ public const string REWARD_VIDEO_SHOW_END = nameof(REWARD_VIDEO_SHOW_END); // always call result: true / false
120
+
121
+ public const string BANNER_SHOW = nameof(BANNER_SHOW);
122
+ }
123
+
124
+
102
125
  [Serializable]
103
126
  internal class AdStat
104
127
  {
@@ -177,6 +200,41 @@ namespace Amanotes.Core
177
200
  internal protected static AdAdapter _adapter;
178
201
  internal protected static float _savedVolume = -1;
179
202
  internal protected static float _savedTimeScale = -1;
203
+
204
+ public static void OnInter_Request(Action callback)
205
+ {
206
+ dispatcher.AddListener(Event.INTER_REQUEST, callback, false);
207
+ }
208
+
209
+ public static void OnInter_ShowCalled(Action callback)
210
+ {
211
+ dispatcher.AddListener(Event.INTER_SHOW_CALLED, callback, false);
212
+ }
213
+
214
+ public static void OnReward_ShowCalled(Action callback)
215
+ {
216
+ dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_CALLED, callback, false);
217
+ }
218
+
219
+ public static void OnInter_ShowReady(Action callback)
220
+ {
221
+ dispatcher.AddListener(Event.INTER_SHOW_READY, callback, false);
222
+ }
223
+
224
+ public static void OnReward_ShowReady(Action callback)
225
+ {
226
+ dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_READY, callback, false);
227
+ }
228
+
229
+ public static void OnInter_ShowNotReady(Action<AdShowReadyStatus> callback)
230
+ {
231
+ dispatcher.AddListener(Event.INTER_SHOW_NOT_READY, callback, false);
232
+ }
233
+
234
+ public static void OnReward_ShowNotReady(Action<AdShowReadyStatus> callback)
235
+ {
236
+ dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_NOT_READY, callback, false);
237
+ }
180
238
  }
181
239
 
182
240
  public partial class Ads // Public
@@ -247,10 +305,11 @@ namespace Amanotes.Core
247
305
 
248
306
  if (_adapter == null)
249
307
  {
250
- //Debug.LogWarning("Adapter not found???");
251
308
  return;
252
309
  }
253
310
 
311
+
312
+ dispatcher.Dispatch(Event.BANNER_SHOW);
254
313
  _adapter.ShowBanner(_showingBannerPosition);
255
314
  }
256
315
 
@@ -344,8 +403,6 @@ namespace Amanotes.Core.Internal
344
403
  public abstract void HideBanner();
345
404
 
346
405
  // Internally used
347
- internal protected abstract void HandleBeforeAdShow();
348
- internal protected abstract void HandleAfterAdShow();
349
406
  internal protected abstract void SetUserId(string userId);
350
407
  }
351
408
 
@@ -524,6 +581,9 @@ namespace Amanotes.Core.Internal
524
581
  _isRequesting = true;
525
582
  Log("[Ad] LoadAdRoutine: RequestAd()");
526
583
  RequestAd();
584
+ dispatcher.Dispatch(
585
+ _isInterstitial ? AmaGDK.Event.INTER_REQUEST : AmaGDK.Event.REWARD_REQUEST
586
+ );
527
587
 
528
588
  int timeout = Config.ad.adLoadTimeoutInSecs;
529
589
  var counter = 0;
@@ -581,7 +641,9 @@ namespace Amanotes.Core.Internal
581
641
  AdStat stat = Ads.localData.GetStat(adType);
582
642
  stat.callCount++;
583
643
  stat.lastCallTime = Time.realtimeSinceStartup;
584
- OnAdShowCalled();
644
+ dispatcher.Dispatch(
645
+ _isInterstitial ? AmaGDK.Event.INTER_SHOW_CALLED : AmaGDK.Event.REWARD_VIDEO_SHOW_CALLED
646
+ );
585
647
 
586
648
  if (_showAdRoutine != null) _instance.StopCoroutine(_showAdRoutine);
587
649
  _showAdRoutine = _instance.StartCoroutine(ShowAdRoutine());
@@ -597,7 +659,7 @@ namespace Amanotes.Core.Internal
597
659
  StartLoadAd();
598
660
  }
599
661
 
600
- HandleAfterAdShow();
662
+ TriggerOnAfterAdShow();
601
663
  if (_showAdRoutine == null) return;
602
664
  _instance.StopCoroutine(_showAdRoutine);
603
665
  _showAdRoutine = null;
@@ -682,10 +744,9 @@ namespace Amanotes.Core.Internal
682
744
 
683
745
  _showState = ShowAdsState.Showing;
684
746
  OnAdShowReadyStatus(true, AdShowReadyStatus.Ready);
685
- HandleBeforeAdShow();
747
+ TriggerBeforeAdShow();
686
748
  ShowAd();
687
-
688
- AdShowContext context = Ads.context;
749
+
689
750
  while (!context.potentiallyCompleted)
690
751
  {
691
752
  yield return null; // callback as quickly as possible
@@ -750,14 +811,14 @@ namespace Amanotes.Core.Internal
750
811
  }
751
812
 
752
813
  localData.Save();
753
- HandleAfterAdShow();
814
+ TriggerOnAfterAdShow();
754
815
 
755
816
  Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{JsonUtility.ToJson(Ads.context)}");
756
817
  Ads.context = null;
757
818
  _showState = ShowAdsState.None;
758
819
  }
759
820
 
760
- private void HandleBeforeAdShow()
821
+ private void TriggerBeforeAdShow()
761
822
  {
762
823
  bool willSaveVolume = Config.ad.autoMute
763
824
  && AudioListener.volume > 0
@@ -779,11 +840,11 @@ namespace Amanotes.Core.Internal
779
840
  Time.timeScale = 0;
780
841
  }
781
842
 
843
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
782
844
  Ads.context.onBeforeAdOpen?.Invoke();
783
- Ads._adapter.HandleBeforeAdShow();
784
845
  }
785
846
 
786
- private void HandleAfterAdShow()
847
+ private void TriggerOnAfterAdShow()
787
848
  {
788
849
  bool willRestoreVolume = Config.ad.autoMute
789
850
  && AudioListener.volume == 0
@@ -804,8 +865,9 @@ namespace Amanotes.Core.Internal
804
865
  Time.timeScale = Ads._savedTimeScale;
805
866
  Ads._savedTimeScale = -1;
806
867
  }
807
-
808
- Ads._adapter.HandleAfterAdShow();
868
+
869
+ bool isSuccess = _showState == ShowAdsState.ShowSuccess;
870
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_END : AmaGDK.Event.REWARD_VIDEO_SHOW_END, isSuccess);
809
871
  }
810
872
 
811
873
  // Default implementation
@@ -877,20 +939,18 @@ namespace Amanotes.Core.Internal
877
939
  Ads.context.onAdShowReadyStatus?.Invoke(status);
878
940
  if (status == AdShowReadyStatus.Ready)
879
941
  {
880
- OnAdShowReady();
942
+ dispatcher.Dispatch(
943
+ _isInterstitial ? AmaGDK.Event.INTER_SHOW_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_READY
944
+ );
881
945
  } else if (status == AdShowReadyStatus.NoInternet || status == AdShowReadyStatus.TimeOut || status == AdShowReadyStatus.Wifi3GDisabled)
882
946
  {
883
- OnAdShowNotReady(status);
947
+ dispatcher.Dispatch(
948
+ _isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY,
949
+ status
950
+ );
884
951
  }
885
952
  }
886
-
887
- protected virtual void OnAdShowCalled()
888
- { }
889
- protected virtual void OnAdShowReady()
890
- { }
891
- protected virtual void OnAdShowNotReady(AdShowReadyStatus status)
892
- { }
893
-
953
+
894
954
  protected void OnAdOpen()
895
955
  {
896
956
  Log($"[Ad] {adType} OnAdOpen");
@@ -26,6 +26,7 @@ namespace Amanotes.Core
26
26
  public string funnelSignature;
27
27
  public bool accumulated;
28
28
  public bool withinSession;
29
+ public bool doNotIncreaseCounter;
29
30
 
30
31
  public bool overrideConfig;
31
32
  public HashSet<string> ignoreAdapterIds = new HashSet<string>();
@@ -241,11 +242,15 @@ namespace Amanotes.Core
241
242
  internal static readonly List<AnalyticsAdapter> listAdapters = new List<AnalyticsAdapter>();
242
243
  internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile();
243
244
  internal static readonly SessionStat sessionStat = new SessionStat();
244
- internal static AnalyticsAdapter primaryAdapter;
245
- internal static readonly HashSet<string> blackListPrefixes = new HashSet<string>() {
246
- "firebase_", "google_", "ga_"
245
+
246
+ internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
247
+ {
248
+ { "firebase_", "frb_" },
249
+ { "google_", "ggl_" },
250
+ { "ga_", "gga_" }
247
251
  };
248
- internal static readonly HashSet<string> blackListEvents = new HashSet<string>()
252
+
253
+ internal static readonly HashSet<string> reservedEvents = new HashSet<string>()
249
254
  {
250
255
  "ad_activeview",
251
256
  "ad_click",
@@ -284,8 +289,6 @@ namespace Amanotes.Core
284
289
  {
285
290
  listAdapters.Clear();
286
291
  listAdapters.AddRange(Adapter2.GetAllAdapter<AnalyticsAdapter>());
287
- if (listAdapters.Count != 0)
288
- primaryAdapter = listAdapters.Find(a => a.adapterId == AdapterID.FIREBASE_ANALYTICS) ?? listAdapters[0];
289
292
  }
290
293
 
291
294
  internal static void StartModule()
@@ -320,19 +323,34 @@ namespace Amanotes.Core
320
323
  UpdateAccumulatedCount(eventData, countInSession, totalCount);
321
324
  }
322
325
 
323
- eventData.AddParam("ama_device_id", User.AmaDeviceId);
326
+ if (!eventData.parameters.ContainsKey("ama_device_id"))
327
+ eventData.AddParam("ama_device_id", User.AmaDeviceId);
324
328
 
325
329
  string eventNameToSend = GetEventNameToSend(eventData.eventName, countInSession, totalCount);
326
330
  if (config.normalizeEventName) NormalizeEventName(ref eventNameToSend);
327
331
 
328
- if (showAnalyticsLog) Debug.Log($"AmaGDK | [Analytics] Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventData.parameters, true)}");
332
+ if (showAnalyticsLog)
333
+ {
334
+ Debug.Log($"AmaGDK [Analytics] Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventData.parameters, true)}");
335
+ }
329
336
 
330
337
  config.quality.CheckEventQuality(eventData.eventName, eventData.parameters);
331
338
 
332
339
  var inUseAdapterIDs = new List<string>();
333
340
  foreach (AnalyticsAdapter m in listAdapters)
334
341
  {
335
- if (IsAdapterForbidden(m, eventData)) continue;
342
+ if (eventData.overrideConfig)
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
+ }
336
354
  m.LogEvent(eventNameToSend, eventData.parameters);
337
355
  inUseAdapterIDs.Add(m.adapterId);
338
356
  }
@@ -356,35 +374,18 @@ namespace Amanotes.Core
356
374
  }
357
375
 
358
376
  int.TryParse(eventData.parameters[ACCUMULATED_COUNT].ToString(), out int oriAccCount);
359
- if (oriAccCount == countByGDK)
360
- {
361
- eventData.AddParam(ACCUMULATED_COUNT, countByGDK);
362
- }
363
- else
377
+ if (oriAccCount != countByGDK)
364
378
  {
365
379
  LogWarning($"[Analytics] event <{eventData.eventName}> has difference in accumulated count. Original count: {oriAccCount}. AmaGDK count: {countByGDK}");
380
+ if (Config.analytics.migrateAccumulatedCount && !eventData.withinSession)
381
+ {
382
+ Log($"[Analytics] Update event count of event <{eventData.eventName}> from {countByGDK} to {oriAccCount}");
383
+ eventData.EventDetail.totalCount = oriAccCount;
384
+ localData._dirty = true;
385
+ }
366
386
  }
367
387
  }
368
388
 
369
- internal static bool IsAdapterForbidden(AnalyticsAdapter adapter, EventParams eventData)
370
- {
371
- if (adapter == null) return false;
372
- if (eventData.overrideConfig)
373
- {
374
- // IMPORTANT NOTE:
375
- //
376
- // Once set overrideConfig, we should skip the adapter config completely!!!
377
- //
378
- if (eventData.IsAdapterForbidden(adapter.adapterId)) return true;
379
- }
380
- else // Do not remove else
381
- {
382
- if (adapter.IsForbidden(eventData.eventName)) return true;
383
- }
384
-
385
- return false;
386
- }
387
-
388
389
  internal static string GetEventNameToSend(string eventName, int countInSession, int totalCount)
389
390
  {
390
391
  if (!sendAtCount.TryGetValue(eventName, out var config)) return eventName;
@@ -401,14 +402,14 @@ namespace Amanotes.Core
401
402
  StringBuilder sb = tmpWarningSB;
402
403
  sb.Clear();
403
404
  NormalizeKeyString(ref eventName, sb, dryRun);
404
- if (blackListEvents.Contains(eventName))
405
+ if (reservedEvents.Contains(eventName))
405
406
  sb.AppendLine($" - EventName <{eventName}> is reserved and should not be used");
406
407
  if (sb.Length > 0 && dryRun) LogWarningOnce($"Warning for event name <{eventName}>:\n{sb}", $"NormalizeEventName<{eventName}>");
407
408
  }
408
409
  Profiler.EndSample();
409
410
  }
410
411
 
411
- internal static void NormalizeKeyString(ref string key, StringBuilder warningLog, bool dryRun = false)
412
+ internal static void NormalizeKeyString(ref string key, StringBuilder warningLog, bool dryRun)
412
413
  {
413
414
  Profiler.BeginSample("AmaGDK.Analytics.NormalizeEventName()");
414
415
  {
@@ -418,47 +419,53 @@ namespace Amanotes.Core
418
419
  Profiler.EndSample();
419
420
  return;
420
421
  }
422
+
423
+ var sb = new StringBuilder();
421
424
 
422
425
  string normalizedString = key.Trim()
423
426
  .Replace(' ', '_')
424
427
  .Replace('-', '_');
425
-
426
428
  if (key != normalizedString)
427
429
  {
428
- if (!dryRun)
429
- {
430
- key = normalizedString;
431
- } else
432
- {
433
- warningLog.AppendLine($" - Malformed name (should not contains <space> or <dash>): <{key}>");
434
- }
430
+ sb.Append($" - Malformed name (should not contains <space> or <dash>): <{key}>");
435
431
  }
436
432
 
437
433
  var r = new Regex("^[a-zA-Z0-9_]*$");
438
434
  if (!r.IsMatch(normalizedString))
439
435
  {
440
- warningLog.AppendLine($" - Name may only contain alphanumeric characters and underscores");
436
+ normalizedString = Regex.Replace(normalizedString, "[^a-zA-Z0-9_]", "");
437
+ sb.Append(" - Name may only contain alphanumeric characters and underscores");
441
438
  }
442
439
 
443
- if (!char.IsLetter(key[0]))
440
+ if (!char.IsLetter(normalizedString[0]))
444
441
  {
445
- warningLog.AppendLine($" - Name must start with a letter: <{key}> ");
442
+ normalizedString = "E" + normalizedString;
443
+ sb.Append($" - Name must start with a letter: <{key}> ");
446
444
  }
447
445
 
448
- foreach (var prefix in blackListPrefixes)
446
+ foreach (var prefix in reservedPrefixes)
449
447
  {
450
- if (!normalizedString.StartsWith(prefix)) continue;
451
- warningLog.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
448
+ if (!normalizedString.StartsWith(prefix.Key)) continue;
449
+ normalizedString = prefix.Value + normalizedString.Remove(0, prefix.Key.Length);
450
+ sb.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
452
451
  }
453
452
 
454
- if (key.Length > 40)
453
+ if (normalizedString.Length > 40)
454
+ {
455
+ sb.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
456
+ normalizedString = normalizedString.Substring(0, 40);
457
+ }
458
+
459
+ if (dryRun)
455
460
  {
456
- warningLog.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
461
+ warningLog.Append(sb);
462
+ } else {
463
+ key = normalizedString;
457
464
  }
458
465
  }
459
466
  Profiler.EndSample();
460
467
  }
461
-
468
+
462
469
  internal static bool ShouldSendEvent(EventParams eventData)
463
470
  {
464
471
  //Funnel event
@@ -609,8 +616,7 @@ namespace Amanotes.Core
609
616
  internal (int countInSession, int totalCount) IncreaseCounter(EventParams eventParams)
610
617
  {
611
618
  EventDetail result = GetEventDetail(eventParams.eventName, true);
612
- if (IsAdapterForbidden(primaryAdapter, eventParams))
613
- return (result.countInSession, result.totalCount);
619
+ if (eventParams.doNotIncreaseCounter) return (result.countInSession, result.totalCount);
614
620
  result.countInSession++;
615
621
  result.totalCount++;
616
622
  _dirty = true;
@@ -708,6 +714,15 @@ namespace Amanotes.Core
708
714
  return ap;
709
715
  }
710
716
 
717
+ public static IEventParamsBuilder SkipAccumulatedCount(this IEventParamsBuilder ap)
718
+ {
719
+ if (ap == null) return null;
720
+
721
+ var data = ap as EventParams;
722
+ data!.doNotIncreaseCounter = true;
723
+ return ap;
724
+ }
725
+
711
726
  public static IEventParamsBuilder Except(this IEventParamsBuilder ap, params string[] analyticIds)
712
727
  {
713
728
  if (ap == null) return null;
@@ -759,7 +774,7 @@ namespace Amanotes.Core
759
774
  public static IEventParamsBuilder AddParam(this IEventParamsBuilder ap, string key, object value)
760
775
  {
761
776
  if (ap == null) return null;
762
- if (!IsValidKeyValue(ap, key, value)) return ap;
777
+ if (!IsValidKeyValue(ap, ref key, ref value)) return ap;
763
778
 
764
779
  var eventParams = ap as EventParams;
765
780
  Dictionary<string, object> parameters = eventParams?.parameters;
@@ -789,10 +804,12 @@ namespace Amanotes.Core
789
804
  return ap;
790
805
  }
791
806
 
792
- foreach (KeyValuePair<string, object> kvp in dictParams)
807
+ foreach (var kvp in dictParams)
793
808
  {
794
- if (IsValidKeyValue(ap, kvp.Key, kvp.Value))
795
- ap.AddParam(kvp.Key, kvp.Value);
809
+ var key = kvp.Key;
810
+ var value = kvp.Value;
811
+ if (IsValidKeyValue(ap, ref key, ref value))
812
+ ap.AddParam(key, value);
796
813
  }
797
814
  return ap;
798
815
  }
@@ -808,33 +825,48 @@ namespace Amanotes.Core
808
825
 
809
826
  foreach (var kvp in parameters)
810
827
  {
811
- if (IsValidKeyValue(ap, kvp.key, kvp.value))
812
- ap.AddParam(kvp.key, kvp.value);
828
+ var key = kvp.key;
829
+ var value = kvp.value;
830
+ if (IsValidKeyValue(ap, ref key, ref value))
831
+ ap.AddParam(key, value);
813
832
  }
814
833
  return ap;
815
834
  }
816
835
 
817
836
  //https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Param
818
- private static bool IsValidKeyValue(IEventParamsBuilder ap, string key, object value)
837
+ private static bool IsValidKeyValue(IEventParamsBuilder ap, ref string key, ref object value)
819
838
  {
820
839
  string eventName = (ap as EventParams)?.eventName;
821
840
 
822
841
  StringBuilder sb = tmpWarningSB;
823
842
  sb.Clear();
824
- NormalizeKeyString(ref key, sb);
825
- if (sb.Length > 0) LogWarningOnce($"Warning for event <{eventName}>, param <{key}>:\n{sb}", $"NormalizeParamKey<{eventName}>");
843
+ NormalizeKeyString(ref key, sb, AmaGDK.Config.analytics.normalizeEventName);
844
+
845
+ if (sb.Length > 0) LogWarningOnce($"Warning for event <{eventName}>, param <{key}>:\n{sb}", $"NormalizeParamKey <{eventName}>");
826
846
 
827
847
  if (string.IsNullOrWhiteSpace(key))
828
848
  {
829
849
  LogWarning($"Param key is empty. Event name: {eventName}!");
830
850
  return false;
831
851
  }
852
+
832
853
  if (value == null)
833
854
  {
834
- LogWarning($"Param value of key <{key}> is null. Event name: {eventName}!");
855
+ LogWarning($"Param value is null. Event name: {eventName}, key: {key}!");
835
856
  return false;
836
857
  }
837
858
 
859
+ if (value.GetType() == typeof(string))
860
+ {
861
+ var v = value.ToString();
862
+ var strLimit = 100;
863
+ if (v.Length > strLimit)
864
+ {
865
+ value = v.Substring(0, strLimit);
866
+ LogWarning($"Param value exceeds the length limit ({strLimit}). Event name: {eventName}, key: {key}!");
867
+ }
868
+ }
869
+
838
870
  return true;
839
871
  }
840
872
  }
@@ -848,6 +880,7 @@ namespace Amanotes.Core.Internal
848
880
  public bool showAnalyticsLog = true;
849
881
  public bool normalizeEventName = true;
850
882
  public bool checkMigrationIntegrity = true;
883
+ public bool migrateAccumulatedCount = true;
851
884
  public bool enableEventStat;
852
885
  public AnalyticQualityConfig quality;
853
886
  }