com.amanotes.gdk 0.2.74 → 0.2.77

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 (77) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/Editor/AmaGDKEditor.cs +24 -15
  3. package/Editor/Utils/GDKPackageInstaller.cs +116 -0
  4. package/Editor/Utils/GDKPackageInstaller.cs.meta +11 -0
  5. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  6. package/Extra/AutoEventQC.unitypackage +0 -0
  7. package/{Runtime/GDKAudio/Plugins/iOS.meta → Extra/AutoEventQC.unitypackage.meta} +1 -2
  8. package/Extra/CheckDiskSpace.unitypackage +0 -0
  9. package/Extra/Consent.unitypackage +0 -0
  10. package/Extra/ForceUpdate.unitypackage +0 -0
  11. package/Extra/LegacyGDKUpdateHelper.unitypackage +0 -0
  12. package/Extra/PostProcessor.unitypackage +0 -0
  13. package/Packages/AmaGDKConfig.unitypackage +0 -0
  14. package/Packages/AmaGDKExample.unitypackage +0 -0
  15. package/Packages/AmaGDKTest.unitypackage +0 -0
  16. package/Packages/AppsFlyerAdapter.AdRevenue.AF6.14AndOlder.unitypackage +0 -0
  17. package/Packages/AppsFlyerAdapter.PurchaseConnector.unitypackage +0 -0
  18. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  19. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  20. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  21. package/Packages/IronSourceAdapter.AdQuality.unitypackage +0 -0
  22. package/{Runtime/GDKAudio/Plugins/macOS.meta → Packages/IronSourceAdapter.AdQuality.unitypackage.meta} +1 -2
  23. package/Packages/IronSourceAdapter.unitypackage +0 -0
  24. package/Packages/MaxAdNetworkAdapter.unitypackage +0 -0
  25. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  26. package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
  27. package/Runtime/Ad/AdLogic.cs +61 -65
  28. package/Runtime/Ad/AdShowContext.cs +1 -1
  29. package/Runtime/Ad/AmaGDK.Ads.cs +2 -1
  30. package/Runtime/AmaGDK.Analytics.cs +22 -16
  31. package/Runtime/AmaGDK.Consent.cs +5 -9
  32. package/Runtime/AmaGDK.Mono.cs +1 -1
  33. package/Runtime/AmaGDK.RemoteConfig.cs +12 -2
  34. package/Runtime/AmaGDK.Singleton.cs +3 -1
  35. package/Runtime/AmaGDK.UserProfile.cs +33 -24
  36. package/Runtime/AmaGDK.cs +83 -43
  37. package/Runtime/Core/GDKDebug.cs +12 -5
  38. package/Runtime/Core/GDKPrefabPool.cs +571 -0
  39. package/Runtime/Core/GDKPrefabPool.cs.meta +11 -0
  40. package/Runtime/Core/GDKRoutine.cs +48 -2
  41. package/Runtime/Internal/AmaGDK.Internal.cs +1 -1
  42. package/Runtime/Internal/AmaGDK.WebUtils.cs +4 -4
  43. package/Runtime/Internal/ForceQuitMonitor.cs +2 -2
  44. package/Runtime/Internal/GDKGeoLocationcs.cs +2 -1
  45. package/Runtime/Internal/GDKServerTime.cs +2 -1
  46. package/Runtime/UI/ScrollView/Editor/GDKScrollViewEditor.cs +50 -0
  47. package/Runtime/UI/ScrollView/Editor/GDKScrollViewEditor.cs.meta +11 -0
  48. package/Runtime/{GDKAudio/Resources.meta → UI/ScrollView/Editor.meta} +1 -1
  49. package/Runtime/UI/ScrollView/GDKScrollView.cs +702 -0
  50. package/Runtime/UI/ScrollView/GDKScrollView.cs.meta +12 -0
  51. package/Runtime/UI/ScrollView.meta +9 -0
  52. package/Runtime/UI/ScrollableText/GDKScrollableText.cs +68 -0
  53. package/Runtime/UI/ScrollableText/GDKScrollableText.cs.meta +3 -0
  54. package/Runtime/UI/ScrollableText/GDKScrollableText.prefab +806 -0
  55. package/Runtime/UI/ScrollableText/GDKScrollableText.prefab.meta +7 -0
  56. package/Runtime/UI/ScrollableText.meta +3 -0
  57. package/Runtime/{GDKAudio/Plugins.meta → UI.meta} +1 -1
  58. package/Runtime/Utils/GDKUtils.cs +18 -0
  59. package/package.json +1 -1
  60. package/Packages/AppsFlyerAdapter.AdRevenue.unitypackage +0 -0
  61. package/Runtime/GDKAudio/GDKAudio.cs +0 -483
  62. package/Runtime/GDKAudio/GDKAudio.cs.meta +0 -3
  63. package/Runtime/GDKAudio/Plugins/Android/atensor-release.aar +0 -0
  64. package/Runtime/GDKAudio/Plugins/Android/atensor-release.aar.meta +0 -32
  65. package/Runtime/GDKAudio/Plugins/Android.meta +0 -3
  66. package/Runtime/GDKAudio/Plugins/iOS/libatensor.a +0 -0
  67. package/Runtime/GDKAudio/Plugins/iOS/libatensor.a.meta +0 -68
  68. package/Runtime/GDKAudio/Plugins/iOS/libcrypto.a +0 -0
  69. package/Runtime/GDKAudio/Plugins/iOS/libcrypto.a.meta +0 -68
  70. package/Runtime/GDKAudio/Plugins/iOS/libssl.a +0 -0
  71. package/Runtime/GDKAudio/Plugins/iOS/libssl.a.meta +0 -68
  72. package/Runtime/GDKAudio/Plugins/macOS/libatensor.dylib +0 -0
  73. package/Runtime/GDKAudio/Plugins/macOS/libatensor.dylib.meta +0 -81
  74. package/Runtime/GDKAudio/Resources/GDKAudioMixer.mixer +0 -133
  75. package/Runtime/GDKAudio/Resources/GDKAudioMixer.mixer.meta +0 -8
  76. package/Runtime/GDKAudio.meta +0 -3
  77. /package/Packages/{AppsFlyerAdapter.AdRevenue.unitypackage.meta → AppsFlyerAdapter.AdRevenue.AF6.14AndOlder.unitypackage.meta} +0 -0
@@ -123,7 +123,8 @@ namespace Amanotes.Core
123
123
 
124
124
  public static partial class Consent //Internal
125
125
  {
126
- private static readonly ConsentData data = new ConsentData().LoadJsonFromFile();
126
+ private static readonly Lazy<ConsentData> _data = new Lazy<ConsentData>(() => new ConsentData().LoadJsonFromFile());
127
+ private static ConsentData data => _data.Value;
127
128
  private static Action _onConsentComplete;
128
129
 
129
130
  internal static bool checkedATT => data.att >= Status.Allowed;
@@ -142,7 +143,7 @@ namespace Amanotes.Core
142
143
  internal static bool InitModule()
143
144
  {
144
145
  if (allConsentChecked) return true;
145
- if (!_config.consent.autoGetConsent) return true;
146
+ if (!_config.autoGetConsent) return true;
146
147
  RequestAllConsents(null);
147
148
  return true;
148
149
  }
@@ -246,15 +247,10 @@ namespace Amanotes.Core
246
247
 
247
248
  namespace Amanotes.Core.Internal
248
249
  {
249
- [Serializable]
250
- public class ConsentConfig
250
+ public partial class ConfigAsset
251
251
  {
252
+ [SerializeField]
252
253
  [Tooltip("Auto pop-up ATT and CMP form")]
253
254
  public bool autoGetConsent = true;
254
255
  }
255
-
256
- public partial class ConfigAsset
257
- {
258
- [SerializeField] public ConsentConfig consent;
259
- }
260
256
  }
@@ -76,7 +76,7 @@ namespace Amanotes.Core.Internal
76
76
 
77
77
  public static void DelayCall(float seconds, Action action)
78
78
  {
79
- DoOnMainThread(() => AmaGDK._instance.StartCoroutine(DelayCallRoutine(seconds, action)));
79
+ StartCoroutine(DelayCallRoutine(seconds, action));
80
80
  }
81
81
 
82
82
  public static IEnumerator Timeout(float timeoutInSecs, Func<bool> completeCheckFunc)
@@ -1,5 +1,6 @@
1
1
  using System;
2
2
  using System.Collections.Generic;
3
+ using System.Globalization;
3
4
  using System.IO;
4
5
  using System.Text;
5
6
  using UnityEngine;
@@ -76,11 +77,20 @@ namespace Amanotes.Core
76
77
  {
77
78
  foreach (var c in embed.overrideConfig)
78
79
  if (c.key == key)
79
- return (T)Convert.ChangeType(c.value, typeof(T));
80
+ return (T)Convert.ChangeType(c.value, typeof(T), CultureInfo.InvariantCulture);
80
81
  }
81
82
  #endif
82
83
  if (DictConfig.ContainsKey(key))
83
- return (T)Convert.ChangeType(DictConfig[key], typeof(T));
84
+ {
85
+ try
86
+ {
87
+ return (T)Convert.ChangeType(DictConfig[key], typeof(T), CultureInfo.InvariantCulture);
88
+ }
89
+ catch (Exception e)
90
+ {
91
+ LogError($"[RemoteConfig] Convert failed with key: '{key}', value: '{DictConfig[key]}'.\nError: {e}");
92
+ }
93
+ }
84
94
  return defaultValue;
85
95
  }
86
96
 
@@ -1,4 +1,5 @@
1
1
 
2
+ using Amanotes.Core.Internal;
2
3
  using System.Threading;
3
4
  using static Amanotes.Core.GDKDebug;
4
5
  using static Amanotes.Core.Internal.Messsage;
@@ -21,7 +22,8 @@ namespace Amanotes.Core
21
22
  _instance = this;
22
23
  mainThreadId = Thread.CurrentThread.ManagedThreadId;
23
24
  DontDestroyOnLoad(this);
24
- StartCoroutine(InitRoutine());
25
+
26
+ GDKUtils.StartCoroutine(InitRoutine());
25
27
  }
26
28
  }
27
29
  }
@@ -9,21 +9,21 @@ namespace Amanotes.Core
9
9
  {
10
10
  public partial class AmaGDK //User profile
11
11
  {
12
- partial class Event
13
- {
14
- public const string GDK_USER_ID_UPDATED = nameof(GDK_USER_ID_UPDATED);
15
- }
16
-
17
- public static readonly UserProfile User = new UserProfile();
12
+ private static readonly Lazy<UserProfile> _user = new Lazy<UserProfile>(() => new UserProfile());
13
+ public static UserProfile User => _user.Value;
18
14
 
19
15
  /// <summary>
20
16
  /// We use multiple IDs to do the user mapping between AppsFlyer, IronSource & Firebase
21
17
  /// The callback triggers when a better UserID (gaid, idfv, pseudoId,...) was found and replace the current UserId
22
18
  /// </summary>
23
19
  /// <param name="onUserIdChange"></param>
24
- public static void SetCallback_OnUserIdUpdated(Action<string> onUserIdChange)
20
+
21
+ private static Action<string> _onUserIdChange;
22
+ public static void SetCallback_OnUserIdUpdated(Action<string> callback)
25
23
  {
26
- dispatcher.AddListener(Event.GDK_USER_ID_UPDATED, onUserIdChange);
24
+ if (callback == null) return;
25
+ _onUserIdChange -= callback;
26
+ _onUserIdChange += callback;
27
27
  }
28
28
 
29
29
  [Serializable]
@@ -46,18 +46,18 @@ namespace Amanotes.Core
46
46
 
47
47
  public partial class UserProfile //PUBLIC
48
48
  {
49
+ private readonly Dictionary<string, object> allUserIds = new Dictionary<string, object>();
49
50
  public Dictionary<string, object> CollectAllUserIds()
50
51
  {
51
- var dic = new Dictionary<string, object>();
52
- if (!string.IsNullOrWhiteSpace(IDFA)) dic["idfa"] = IDFA;
53
- if (!string.IsNullOrWhiteSpace(IDFV)) dic["idfv"] = IDFV;
54
- if (!string.IsNullOrWhiteSpace(GAId)) dic["gaid"] = GAId;
55
- if (!string.IsNullOrWhiteSpace(AndroidId)) dic["android_id"] = AndroidId;
56
- if (!string.IsNullOrWhiteSpace(PseudoId)) dic["pseudo_id"] = PseudoId;
57
- if (!string.IsNullOrWhiteSpace(AmaDeviceId)) dic["ama_device_id"] = AmaDeviceId;
58
- if (!string.IsNullOrWhiteSpace(AppsFlyerId)) dic["appsflyer_id"] = AppsFlyerId;
59
- if (!string.IsNullOrWhiteSpace(InstallationId)) dic["installation_id"] = InstallationId;
60
- return dic;
52
+ if (!string.IsNullOrWhiteSpace(IDFA)) allUserIds["idfa"] = IDFA;
53
+ if (!string.IsNullOrWhiteSpace(IDFV)) allUserIds["idfv"] = IDFV;
54
+ if (!string.IsNullOrWhiteSpace(GAId)) allUserIds["gaid"] = GAId;
55
+ if (!string.IsNullOrWhiteSpace(AndroidId)) allUserIds["android_id"] = AndroidId;
56
+ if (!string.IsNullOrWhiteSpace(PseudoId)) allUserIds["pseudo_id"] = PseudoId;
57
+ if (!string.IsNullOrWhiteSpace(AmaDeviceId)) allUserIds["ama_device_id"] = AmaDeviceId;
58
+ if (!string.IsNullOrWhiteSpace(AppsFlyerId)) allUserIds["appsflyer_id"] = AppsFlyerId;
59
+ if (!string.IsNullOrWhiteSpace(InstallationId)) allUserIds["installation_id"] = InstallationId;
60
+ return allUserIds;
61
61
  }
62
62
 
63
63
  public string UserId
@@ -71,8 +71,10 @@ namespace Amanotes.Core
71
71
  {
72
72
  if (_userId == value) return;
73
73
  _userId = value;
74
+
74
75
  Log($"GDK UserID Updated: {_userId}");
75
- dispatcher.Dispatch(Event.GDK_USER_ID_UPDATED, _userId);
76
+ if (_onUserIdChange != null) _onUserIdChange(_userId);
77
+
76
78
  _dirty = true;
77
79
  if (isReady) SendMapUserId();
78
80
  }
@@ -158,11 +160,7 @@ namespace Amanotes.Core
158
160
  get => _amaDeviceId;
159
161
  set
160
162
  {
161
- var pattern = ALPHANUMERIC_HYPHEN_PATTERN;
162
- #if UNITY_ANDROID && !UNITY_EDITOR_OSX
163
- pattern = ALPHANUMERIC_PATTERN;
164
- #endif
165
- if (!ValidateId(value, pattern))
163
+ if (!ValidateId(value, ALPHANUMERIC_OPTIONAL_HYPHEN_PATTERN))
166
164
  {
167
165
  LogError($"[UserProfile] Wrong format for AmaDeviceId. Value: {value}");
168
166
  return;
@@ -300,6 +298,7 @@ namespace Amanotes.Core
300
298
  [SerializeField]
301
299
  private string _country;
302
300
 
301
+ private const string ALPHANUMERIC_OPTIONAL_HYPHEN_PATTERN = @"^(?=.*\d)(?=.*[a-zA-Z])[a-zA-Z\d-]+$";
303
302
  private const string ALPHANUMERIC_HYPHEN_PATTERN = @"^(?=.*\d)(?=.*[a-zA-Z])(?=.*-).+$";
304
303
  private const string ALPHANUMERIC_PATTERN = @"^(?=.*\d)(?=.*[a-zA-Z])[a-zA-Z\d]+$";
305
304
  private const string NUMERIC_HYPHEN_PATTERN = @"^(?=.*\d)(?=.*-)[\d-]+$";
@@ -348,9 +347,19 @@ namespace Amanotes.Core
348
347
  switch (Application.platform)
349
348
  {
350
349
  case RuntimePlatform.IPhonePlayer:
350
+ if (!ValidateId(id, ALPHANUMERIC_HYPHEN_PATTERN))
351
+ {
352
+ LogWarning($"[UserProfile] Wrong format for IDFA. Value: {id}");
353
+ return;
354
+ }
351
355
  IDFA = id;
352
356
  break;
353
357
  case RuntimePlatform.Android:
358
+ if (!ValidateId(id, ALPHANUMERIC_HYPHEN_PATTERN))
359
+ {
360
+ LogWarning($"[UserProfile] Wrong format for GAId. Value: {id}");
361
+ return;
362
+ }
354
363
  GAId = id;
355
364
  break;
356
365
  }
package/Runtime/AmaGDK.cs CHANGED
@@ -24,15 +24,19 @@ namespace Amanotes.Core
24
24
  {
25
25
  public partial class AmaGDK : MonoBehaviour
26
26
  {
27
- public const string VERSION = "0.2.74";
27
+ public const string VERSION = "0.2.77";
28
28
 
29
29
  internal static Status _status = Status.None;
30
30
  private static ConfigAsset _config = null;
31
31
 
32
+ private static readonly Lazy<GDKGeoLocation> _geoLocation = new Lazy<GDKGeoLocation>(() => new GDKGeoLocation());
33
+ private static readonly Lazy<GDKServerTime> _serverTime = new Lazy<GDKServerTime>(() => new GDKServerTime());
34
+ private static readonly Lazy<ForceQuitMonitor> _forceQuit = new Lazy<ForceQuitMonitor>(() => new ForceQuitMonitor());
35
+
32
36
  internal static readonly GDKDispatcher dispatcher = new GDKDispatcher();
33
- internal static readonly GDKGeoLocation GeoLocation = new GDKGeoLocation();
34
- internal static readonly GDKServerTime ServerTime = new GDKServerTime();
35
- private static readonly ForceQuitMonitor ForceQuit = new ForceQuitMonitor();
37
+ internal static GDKGeoLocation GeoLocation => _geoLocation.Value;
38
+ internal static GDKServerTime ServerTime => _serverTime.Value;
39
+ private static ForceQuitMonitor ForceQuit => _forceQuit.Value;
36
40
 
37
41
  internal static bool _allowInit = false;
38
42
 
@@ -40,33 +44,46 @@ namespace Amanotes.Core
40
44
 
41
45
  internal static partial class Event
42
46
  {
43
- public const string GDK_HOOK_START = nameof(GDK_HOOK_START);
44
- public const string GDK_HOOK_END = nameof(GDK_HOOK_END);
45
-
46
- public const string GDK_INIT = nameof(GDK_INIT);
47
- public const string GDK_READY = nameof(GDK_READY);
48
- public const string ADAPTER_READY = nameof(ADAPTER_READY);
47
+ // public const string GDK_HOOK_START = nameof(GDK_HOOK_START);
48
+ // public const string GDK_HOOK_END = nameof(GDK_HOOK_END);
49
+ // public const string GDK_INIT = nameof(GDK_INIT);
50
+ // public const string GDK_READY = nameof(GDK_READY);
51
+ // public const string ADAPTER_READY = nameof(ADAPTER_READY);
49
52
  }
50
53
 
54
+ /// <summary>
55
+ /// Gets the ConfigAsset for the AmaGDK.
56
+ /// If the config hasn't been loaded yet, it loads the AmaGDKConfig from Resources.
57
+ /// In the Unity Editor's Play mode, it creates an instance of the config to avoid modifying the original asset.
58
+ /// In all other cases, it uses the loaded config directly.
59
+ /// </summary>
51
60
  public static ConfigAsset Config
52
61
  {
53
62
  get
54
63
  {
55
64
  if (_config != null) return _config;
56
- _config = Resources.Load<ConfigAsset>("AmaGDKConfig");
57
- GDKDebug.logLevel = _config.common.logLevel;
65
+ var config = Resources.Load<ConfigAsset>("AmaGDKConfig");
66
+ #if UNITY_EDITOR
67
+ if (EditorApplication.isPlayingOrWillChangePlaymode)
68
+ {
69
+ _config = Instantiate(config);
70
+ return _config;
71
+ }
72
+ #endif
73
+ _config = config;
58
74
  return _config;
59
75
  }
60
76
  }
61
77
 
62
78
  IEnumerator InitHook()
63
79
  {
64
- dispatcher.Dispatch(Event.GDK_HOOK_START);
80
+ // dispatcher.Dispatch(Event.GDK_HOOK_START);
81
+ if (_onHookStart!= null) GDKUtils.SafeInvokeAndClear(ref _onHookStart);
65
82
  int nHooks = Hook.hooks.Count;
66
83
  if (nHooks == 0)
67
84
  {
68
85
  Log($"[Hook] No hook registered!");
69
- dispatcher.Dispatch(Event.GDK_HOOK_END);
86
+ if (_onHookEnd!= null) GDKUtils.SafeInvokeAndClear(ref _onHookEnd);
70
87
  yield break;
71
88
  }
72
89
 
@@ -81,7 +98,7 @@ namespace Amanotes.Core
81
98
  yield return new WaitUntil(() => hookCompleted);
82
99
  float elapsed = Time.realtimeSinceStartup - stTime;
83
100
  Log($"[Hook] {nHooks} hooks complete after {elapsed} secs");
84
- dispatcher.Dispatch(Event.GDK_HOOK_END);
101
+ if (_onHookEnd!= null) GDKUtils.SafeInvokeAndClear(ref _onHookEnd);
85
102
  }
86
103
 
87
104
  IEnumerator WaitForManualInit()
@@ -165,7 +182,8 @@ namespace Amanotes.Core
165
182
  Log($"{adapter.adapterId} init took: {(endTime-beginTime):#0.00} s");
166
183
  }
167
184
  }
168
- dispatcher.Dispatch(Event.ADAPTER_READY, adapter.adapterId);
185
+
186
+ GDKUtils.SafeInvoke(_onAdapterReady, adapter.adapterId);
169
187
  sb.AppendLine($"[{(adapter.IsReady ? " OK " : "FAIL")}] {adapter.adapterId} (~ {Time.realtimeSinceStartup - startTime:#0.00}s)");
170
188
 
171
189
  // Wait for postprocessing of each adapter
@@ -196,8 +214,9 @@ namespace Amanotes.Core
196
214
  sb.Append($"- InitHook() took (~ {hookTime:#0.00}s)\n\n");
197
215
 
198
216
  _status = Status.Initialize;
199
- dispatcher.Dispatch(Event.GDK_INIT);
200
- yield return WaitForManualInit();
217
+ GDKUtils.SafeInvokeAndClear(ref _onGDKInit);
218
+
219
+ if (!_allowInit) yield return WaitForManualInit();
201
220
  yield return InitAdapters(sb);
202
221
 
203
222
  StartModules();
@@ -211,14 +230,17 @@ namespace Amanotes.Core
211
230
  ForceQuit.Init();
212
231
 
213
232
  _status = Status.Ready;
214
- dispatcher.Dispatch(Event.GDK_READY);
233
+ GDKUtils.SafeInvokeAndClear(ref _onGDKReady);
215
234
 
216
- var initDuration = Time.realtimeSinceStartup - startTime;
235
+ float initDuration = Time.realtimeSinceStartup - startTime;
217
236
  LogEvent_GDKInit(Mathf.RoundToInt(initDuration));
218
237
 
219
238
  sb.Append($"\nMapping UserId: {User.UserId}\n");
220
239
  ForceLog($"v{VERSION} | {READY} in {initDuration:#0.00}s\n\n{sb}");
221
240
  GDKPool.Return(sb);
241
+
242
+ // also clear callbacks
243
+ _onAdapterReady = null;
222
244
  }
223
245
 
224
246
  private void ConfigGeoLocation()
@@ -243,12 +265,21 @@ namespace Amanotes.Core
243
265
 
244
266
  private static void LogEvent_GDKInit(int initDuration)
245
267
  {
268
+ var BToMB = 1.0 / (1024 * 1024);
269
+ var reservedMemory = Math.Round(Profiler.GetTotalReservedMemoryLong() * BToMB, 2); // in MB
270
+ var allocatedMemory = Math.Round(Profiler.GetTotalAllocatedMemoryLong() * BToMB, 2); // in MB
271
+ var unusedReservedMemory = Math.Round(Profiler.GetTotalUnusedReservedMemoryLong() * BToMB, 2); // in MB
272
+
246
273
  var _dicKey = new Dictionary<string, object>
247
274
  {
248
275
  ["gdk_version"] = VERSION,
249
276
  ["session"] = User.Session,
250
277
  ["gdk_init_duration"] = initDuration,
251
- ["user_id"] = User.UserId
278
+ ["user_id"] = User.UserId,
279
+ ["device_spec"] = Device.GetDeviceSpec().ToString(),
280
+ ["reserved_memory"] = reservedMemory,
281
+ ["allocated_memory"] = allocatedMemory,
282
+ ["unused_memory"] = unusedReservedMemory
252
283
  };
253
284
 
254
285
  void AppendServiceKey(string adapterId, string paramName)
@@ -272,8 +303,8 @@ namespace Amanotes.Core
272
303
 
273
304
  public static LogLevel logLevel
274
305
  {
275
- get => _config == null ? Config.common.logLevel : GDKDebug.logLevel;
276
- set => GDKDebug.logLevel = value;
306
+ get => Config.common.logLevel;
307
+ set => Config.common.logLevel = value;
277
308
  }
278
309
 
279
310
  public static void Init(Action onReady = null)
@@ -281,13 +312,14 @@ namespace Amanotes.Core
281
312
  if (isReady)
282
313
  {
283
314
  LogWarning(SDK_INIT_CALLED);
284
- onReady?.Invoke();
315
+ if (onReady != null) onReady();
285
316
  return;
286
317
  }
287
318
 
288
319
  if (onReady != null)
289
320
  {
290
- dispatcher.AddListener(Event.GDK_READY, onReady, true);
321
+ _onGDKReady -= onReady;
322
+ _onGDKReady += onReady;
291
323
  }
292
324
 
293
325
  if (_allowInit)
@@ -303,6 +335,12 @@ namespace Amanotes.Core
303
335
  _instance = sdk.AddComponent<AmaGDK>();
304
336
  }
305
337
 
338
+ private static Action _onGDKInit;
339
+ private static Action _onGDKReady;
340
+ internal static Action _onHookStart;
341
+ internal static Action _onHookEnd;
342
+ private static Action<string> _onAdapterReady;
343
+
306
344
  /// <summary>
307
345
  /// Will be triggered right after all the cached data being loaded
308
346
  /// And before any Adapter has been called to Init
@@ -310,13 +348,15 @@ namespace Amanotes.Core
310
348
  /// <param name="onInit"></param>
311
349
  public static void SetCallback_OnGDKInit(Action onInit)
312
350
  {
351
+ if (onInit == null) return;
313
352
  if (isInitted)
314
353
  {
315
- onInit.Invoke();
354
+ onInit();
316
355
  return;
317
356
  }
318
-
319
- dispatcher.AddListener(Event.GDK_INIT, onInit, true);
357
+
358
+ _onGDKInit += onInit;
359
+ _onGDKInit -= onInit;
320
360
  }
321
361
 
322
362
  /// <summary>
@@ -325,30 +365,30 @@ namespace Amanotes.Core
325
365
  /// <param name="onReady"></param>
326
366
  public static void SetCallback_OnGDKReady(Action onReady)
327
367
  {
368
+ if (onReady == null) return;
369
+
328
370
  if (isReady)
329
371
  {
330
- onReady.Invoke();
372
+ onReady();
331
373
  return;
332
374
  }
333
375
 
334
- dispatcher.AddListener(Event.GDK_READY, onReady, true);
376
+ _onGDKReady -= onReady;
377
+ _onGDKReady += onReady;
335
378
  }
336
379
 
337
- public static void SetAdapterReadyCallback(Action<string> onAdapterReady)
380
+ public static void SetCallback_AdapterReady(Action<string> onReady)
338
381
  {
339
- if (onAdapterReady == null)
340
- {
341
- LogWarning("Cannot add a null callback!");
342
- return;
343
- }
344
-
345
- if (AmaGDK.isReady)
346
- {
347
- LogWarning("All adapters has been init / ready!");
348
- return;
349
- }
382
+ if (onReady == null || isReady) return;
350
383
 
351
- dispatcher.AddListener(Event.ADAPTER_READY, onAdapterReady);
384
+ _onAdapterReady -= onReady;
385
+ _onAdapterReady += onReady;
386
+ }
387
+
388
+ [Obsolete("Use SetCallback_AdapterReady instead")]
389
+ public static void SetAdapterReadyCallback(Action<string> onReady)
390
+ {
391
+ SetCallback_AdapterReady(onReady);
352
392
  }
353
393
  }
354
394
 
@@ -36,14 +36,13 @@ namespace Amanotes.Core
36
36
 
37
37
  public class GDKDebug
38
38
  {
39
- public static LogLevel logLevel;
40
39
  public static Action<string> logNonfatalErrorHook = null;
41
40
  private static readonly HashSet<string> nonFatalDict = new HashSet<string>();
42
41
  public static readonly HashSet<string> logWarningDict = new HashSet<string>();
43
42
 
44
43
  public static void LogWarningOnce(string message, string key = null)
45
44
  {
46
- if (logLevel < LogLevel.Warning) return;
45
+ if (AmaGDK.logLevel < LogLevel.Warning) return;
47
46
  if (string.IsNullOrEmpty(key)) key = message;
48
47
  if (!logWarningDict.Add(key)) return;
49
48
 
@@ -54,7 +53,7 @@ namespace Amanotes.Core
54
53
  }
55
54
  public static void LogWarning(string message)
56
55
  {
57
- if (logLevel < LogLevel.Warning) return;
56
+ if (AmaGDK.logLevel < LogLevel.Warning) return;
58
57
  using (NoStackTrace.Warning)
59
58
  {
60
59
  Debug.LogWarning($"AmaGDK {message}");
@@ -62,13 +61,21 @@ namespace Amanotes.Core
62
61
  }
63
62
  public static void LogError(string message)
64
63
  {
65
- if (logLevel < LogLevel.Error) return;
64
+ if (AmaGDK.logLevel < LogLevel.Error) return;
66
65
  using (NoStackTrace.Error)
67
66
  {
68
67
  Debug.LogError($"AmaGDK {message}");
69
68
  }
70
69
 
71
70
  if (logNonfatalErrorHook == null) return;
71
+
72
+ if (GDKUtils.isOnMainThread) // Most of the time
73
+ {
74
+ if (!nonFatalDict.Add(message)) return;
75
+ logNonfatalErrorHook(message);
76
+ return;
77
+ }
78
+
72
79
  GDKUtils.DoOnMainThread(() =>
73
80
  {
74
81
  if (!nonFatalDict.Add(message)) return; // LogOnce
@@ -78,7 +85,7 @@ namespace Amanotes.Core
78
85
 
79
86
  public static void Log(string message)
80
87
  {
81
- if (logLevel < LogLevel.Verbose) return;
88
+ if (AmaGDK.logLevel < LogLevel.Verbose) return;
82
89
  using (NoStackTrace.Log)
83
90
  {
84
91
  Debug.Log($"AmaGDK {message}");