com.amanotes.gdk 0.2.85 → 0.2.87

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 (45) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/Editor/Extra/GDKCIBuildCommand.cs +19 -2
  3. package/Editor/Extra/GDKLocalBuild.cs +25 -1
  4. package/Editor/Extra/SDKVersionTracking.cs +9 -1
  5. package/Editor/Utils/AmaGDKEditor.ExtractVersion.Max.cs +120 -0
  6. package/Editor/Utils/AmaGDKEditor.ExtractVersion.Max.cs.meta +3 -0
  7. package/Editor/Utils/AmaGDKEditor.ExtractVersion.cs +8 -10
  8. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  9. package/Extra/AutoEventQC.unitypackage +0 -0
  10. package/Extra/CheckDiskSpace.unitypackage +0 -0
  11. package/Extra/Consent.unitypackage +0 -0
  12. package/Extra/CrashlyticHook.unitypackage +0 -0
  13. package/Extra/ForceUpdate.unitypackage +0 -0
  14. package/Extra/LegacyGDKUpdateHelper.unitypackage +0 -0
  15. package/Extra/PostProcessor.unitypackage +0 -0
  16. package/Packages/AmaGDKConfig.unitypackage +0 -0
  17. package/Packages/AmaGDKExample.unitypackage +0 -0
  18. package/Packages/AmaGDKTest.unitypackage +0 -0
  19. package/Packages/AppsFlyerAdapter.PurchaseConnector.unitypackage +0 -0
  20. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  21. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  22. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  23. package/Packages/IronSourceAdapter.AdQuality.unitypackage +0 -0
  24. package/Packages/IronSourceAdapter.unitypackage +0 -0
  25. package/Packages/MaxAdNetworkAdapter.unitypackage +0 -0
  26. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  27. package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
  28. package/Runtime/Ad/AdLogic.cs +230 -148
  29. package/Runtime/AmaGDK.Adapters.cs +2 -0
  30. package/Runtime/AmaGDK.Analytics.cs +140 -78
  31. package/Runtime/AmaGDK.RemoteConfig.cs +50 -40
  32. package/Runtime/AmaGDK.Singleton.cs +2 -0
  33. package/Runtime/AmaGDK.cs +3 -1
  34. package/Runtime/AnalyticQualityAsset.cs +69 -38
  35. package/Runtime/AudioToolkit/Plugins/AudioDeviceDetector.cs +31 -17
  36. package/Runtime/Core/GDKDispatcher.cs +4 -2
  37. package/Runtime/Core/GDKSemVer.cs +23 -26
  38. package/Runtime/Fps/AmaFPSVisualizer.cs +48 -26
  39. package/Runtime/Internal/AmaGDK.Utils.cs +90 -46
  40. package/Runtime/Internal/ForceQuitMonitor.cs +43 -31
  41. package/Runtime/Klavar/Attributes/MinMaxAttribute.cs +12 -3
  42. package/Runtime/UI/ScrollView/GDKScrollView.cs +83 -48
  43. package/Runtime/Utils/GDKFileUtils.cs +3 -8
  44. package/Runtime/Utils/GDKUtils.cs +20 -8
  45. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  using System;
2
2
  using System.Collections;
3
+ using System.Collections.Generic;
3
4
  using UnityEngine;
4
5
  using static Amanotes.Core.GDKDebug;
5
6
  using static Amanotes.Core.AmaGDK;
@@ -69,55 +70,72 @@ namespace Amanotes.Core.Internal
69
70
  {
70
71
  yield return wait1Sec;
71
72
 
72
- if (!Ads.allowAdRequest)
73
- {
74
- Log("[Ad] LoadAdRoutine: allowAdRequest = false");
75
- continue;
76
- }
73
+ if (!CanRequestAd()) continue;
77
74
 
78
- if (!HasLocalNetworkConnection)
75
+ yield return ProcessAdRequest();
76
+ if (isAdReady)
79
77
  {
80
- Log("[Ad] LoadAdRoutine: hasInternet = " + HasLocalNetworkConnection);
81
- continue;
78
+ _loadState = LoadAdsState.Ready;
79
+ Log("[Ad] LoadAdRoutine: Ad is ready!");
80
+ yield break;
82
81
  }
82
+ }
83
+ }
83
84
 
84
- _loadState = LoadAdsState.Requesting;
85
- _isRequesting = true;
86
- Log("[Ad] LoadAdRoutine: RequestAd()");
87
- RequestAd();
88
- dispatcher.Dispatch(
89
- _isInterstitial ? AmaGDK.Event.INTER_REQUEST : AmaGDK.Event.REWARD_REQUEST
90
- );
85
+ private bool CanRequestAd()
86
+ {
87
+ if (!Ads.allowAdRequest)
88
+ {
89
+ Log("[Ad] LoadAdRoutine: allowAdRequest = false");
90
+ return false;
91
+ }
91
92
 
92
- int timeout = Config.ad.adLoadTimeoutInSecs;
93
- var counter = 0;
93
+ if (!HasLocalNetworkConnection)
94
+ {
95
+ Log("[Ad] LoadAdRoutine: hasInternet = " + HasLocalNetworkConnection);
96
+ return false;
97
+ }
98
+ return true;
99
+ }
94
100
 
95
- while (counter < timeout || timeout == -1)
96
- {
97
- yield return wait1Sec;
98
- counter++;
99
- if (_isRequesting == false) break;
100
- }
101
+ private IEnumerator ProcessAdRequest()
102
+ {
103
+ _loadState = LoadAdsState.Requesting;
104
+ _isRequesting = true;
105
+ Log("[Ad] LoadAdRoutine: RequestAd()");
106
+ RequestAd();
107
+ dispatcher.Dispatch(
108
+ _isInterstitial ? AmaGDK.Event.INTER_REQUEST : AmaGDK.Event.REWARD_REQUEST
109
+ );
101
110
 
102
- if (counter > timeout && timeout > 0) // timeout
103
- {
104
- Log("[Ad] LoadAdRoutine: RequestAd not responding (timeout) " + timeout + " secs");
105
- continue;
106
- }
107
-
108
- // request should be completed here!
109
- if (!isAdReady)
110
- {
111
- LogWarning($"[Ad] Request complete but failed! (load duration = {counter} secs)");
112
- continue;
113
- }
111
+ yield return WaitForAdRequestCompletion();
112
+ }
114
113
 
115
- _loadState = LoadAdsState.Ready;
116
- Log($"[Ad] LoadAdRoutine: Ad is ready! (load duration = {counter} secs)");
117
- yield break;
114
+ private IEnumerator WaitForAdRequestCompletion()
115
+ {
116
+ var wait1Sec = new WaitForSecondsRealtime(1f);
117
+ int timeout = Config.ad.adLoadTimeoutInSecs;
118
+ var counter = 0;
119
+
120
+ while (counter < timeout || timeout == -1)
121
+ {
122
+ yield return wait1Sec;
123
+ counter++;
124
+ if (_isRequesting == false) break;
125
+ }
126
+
127
+ if (counter > timeout && timeout > 0)
128
+ {
129
+ Log("[Ad] LoadAdRoutine: RequestAd not responding (timeout) " + timeout + " secs");
130
+ }
131
+ else if (!isAdReady)
132
+ {
133
+ LogWarning($"[Ad] Request complete but failed! (load duration = {counter} secs)");
118
134
  }
119
135
  }
120
136
 
137
+
138
+
121
139
  bool HasLocalNetworkConnection => Application.internetReachability != NetworkReachability.NotReachable;
122
140
 
123
141
  // Override by actual Ad instance
@@ -188,38 +206,48 @@ namespace Amanotes.Core.Internal
188
206
  // Wait for Ad
189
207
  if (!isAdReady)
190
208
  {
191
- if (_loadState == LoadAdsState.Ready)
192
- {
193
- LogWarning("[Ad] Inconsistent state report: isAdReady == false while _loadState == Ready");
194
- _loadState = LoadAdsState.None;
195
- }
209
+ yield return HandleNotReadyAd();
210
+ if (_showState == ShowAdsState.ShowFail) yield break;
211
+ }
196
212
 
197
- if (!HasLocalNetworkConnection)
198
- {
199
- EndShowAdRoutineWithFailure(AdShowReadyStatus.Wifi3GDisabled);
200
- yield break;
201
- }
213
+ yield return ExecuteAdShow();
214
+ }
202
215
 
203
- int timeout = Config.ad.adShowTimeoutInSecs;
204
- if (timeout == 0) // do not wait for Ad
205
- {
206
- EndShowAdRoutineWithFailure(AdShowReadyStatus.TimeOut);
207
- yield break;
208
- }
216
+ private IEnumerator HandleNotReadyAd()
217
+ {
218
+ if (_loadState == LoadAdsState.Ready)
219
+ {
220
+ LogWarning("[Ad] Inconsistent state report: isAdReady == false while _loadState == Ready");
221
+ _loadState = LoadAdsState.None;
222
+ }
209
223
 
210
- _showState = ShowAdsState.WaitForAd;
211
- OnAdShowReadyStatus(false, AdShowReadyStatus.WaitForAd);
224
+ if (!HasLocalNetworkConnection)
225
+ {
226
+ EndShowAdRoutineWithFailure(AdShowReadyStatus.Wifi3GDisabled);
227
+ yield break;
228
+ }
212
229
 
213
- yield return WaitForAdReadyWithTimeout(timeout);
214
-
215
- if (!isAdReady)
216
- {
217
- Log("[Ad] WaitForAd failed (timeout) " + " | timeout = " + timeout + " secs");
218
- EndShowAdRoutineWithFailure(AdShowReadyStatus.TimeOut);
219
- yield break;
220
- }
230
+ int timeout = Config.ad.adShowTimeoutInSecs;
231
+ if (timeout == 0) // do not wait for Ad
232
+ {
233
+ EndShowAdRoutineWithFailure(AdShowReadyStatus.TimeOut);
234
+ yield break;
235
+ }
236
+
237
+ _showState = ShowAdsState.WaitForAd;
238
+ OnAdShowReadyStatus(false, AdShowReadyStatus.WaitForAd);
239
+
240
+ yield return WaitForAdReadyWithTimeout(timeout);
241
+
242
+ if (!isAdReady)
243
+ {
244
+ Log("[Ad] WaitForAd failed (timeout) " + " | timeout = " + timeout + " secs");
245
+ EndShowAdRoutineWithFailure(AdShowReadyStatus.TimeOut);
221
246
  }
247
+ }
222
248
 
249
+ private IEnumerator ExecuteAdShow()
250
+ {
223
251
  _showState = ShowAdsState.Showing;
224
252
  OnAdShowReadyStatus(true, AdShowReadyStatus.Ready);
225
253
  TriggerBeforeAdShow();
@@ -241,38 +269,56 @@ namespace Amanotes.Core.Internal
241
269
  if (context != null && !context.hasReward && adType == AdType.VideoReward && !context.hasFailedOrCancelled) yield return null;
242
270
  }
243
271
 
272
+ private class FocusState
273
+ {
274
+ public bool hasOutOfFocus = false;
275
+ public bool hasFocusAgain = false;
276
+ }
277
+
244
278
  private IEnumerator HandleAdActivityKilledSilently()
245
279
  {
246
- bool hasOutOfFocus = false;
247
- bool hasFocusAgain = false;
248
- Action<bool> onApplicationFocusCallback = focus =>
249
- {
250
- if (focus)
251
- {
252
- hasFocusAgain = true;
253
- }
254
- else
255
- {
256
- hasOutOfFocus = true;
257
- }
258
- };
280
+ var focusState = new FocusState();
281
+ Action<bool> onApplicationFocusCallback = focus => UpdateFocusState(focus, focusState);
282
+
259
283
  unityCallbacks.OnApplicationFocus += onApplicationFocusCallback;
284
+ yield return MonitorAdActivity(focusState);
285
+ unityCallbacks.OnApplicationFocus -= onApplicationFocusCallback;
286
+ }
287
+
288
+ private void UpdateFocusState(bool focus, FocusState focusState)
289
+ {
290
+ if (focus)
291
+ {
292
+ focusState.hasFocusAgain = true;
293
+ }
294
+ else
295
+ {
296
+ focusState.hasOutOfFocus = true;
297
+ }
298
+ }
299
+
300
+ private IEnumerator MonitorAdActivity(FocusState focusState)
301
+ {
260
302
  while (context != null && !context.potentiallyCompleted)
261
303
  {
262
- if (hasFocusAgain && hasOutOfFocus)
304
+ if (focusState.hasFocusAgain && focusState.hasOutOfFocus)
263
305
  {
264
- // Start counting only after closed the ad
265
- yield return GDKUtils.WaitForSecondsRealtime(Config.ad.adCallBackTimeOut);
266
- if (context != null && !context.potentiallyCompleted)
267
- {
268
- LogError("Force close the ad");
269
- StopShowAd();
270
- break;
271
- }
306
+ yield return HandleFocusRegained();
307
+ if (context == null || context.potentiallyCompleted) break;
272
308
  }
273
309
  yield return null;
274
310
  }
275
- unityCallbacks.OnApplicationFocus -= onApplicationFocusCallback;
311
+ }
312
+
313
+ private IEnumerator HandleFocusRegained()
314
+ {
315
+ // Start counting only after closed the ad
316
+ yield return GDKUtils.WaitForSecondsRealtime(Config.ad.adCallBackTimeOut);
317
+ if (context != null && !context.potentiallyCompleted)
318
+ {
319
+ LogError("Force close the ad");
320
+ StopShowAd();
321
+ }
276
322
  }
277
323
 
278
324
  private void StopHandleAdActivityKilledRoutine()
@@ -304,19 +350,28 @@ namespace Amanotes.Core.Internal
304
350
  counter++;
305
351
  Log($"[Ad] Waiting for ad {counter} secs");
306
352
 
307
- // finish checking internet & result is false
308
- if (adConfig.checkInternet && hasInternet == false)
309
- {
310
- Log("[Ad] Stop WaitForAd : No internet!");
311
- EndShowAdRoutineWithFailure(AdShowReadyStatus.NoInternet);
312
- yield break;
313
- }
353
+ if (ShouldStopWaitingForInternet(hasInternet)) yield break;
354
+ if (IsAdLoadReady(counter, timeout)) break;
355
+ }
356
+ }
314
357
 
315
- if (_loadState != LoadAdsState.Ready) continue;
316
- Log("[Ad] WaitForAd success after " + counter + " | timeout = " + timeout + " secs");
317
- break;
358
+ private bool ShouldStopWaitingForInternet(bool? hasInternet)
359
+ {
360
+ if (adConfig.checkInternet && hasInternet == false)
361
+ {
362
+ Log("[Ad] Stop WaitForAd : No internet!");
363
+ EndShowAdRoutineWithFailure(AdShowReadyStatus.NoInternet);
364
+ return true;
318
365
  }
319
- }
366
+ return false;
367
+ }
368
+
369
+ private bool IsAdLoadReady(int counter, int timeout)
370
+ {
371
+ if (_loadState != LoadAdsState.Ready) return false;
372
+ Log("[Ad] WaitForAd success after " + counter + " | timeout = " + timeout + " secs");
373
+ return true;
374
+ }
320
375
 
321
376
  private void ShowAdRoutineCompleted(bool isSuccess)
322
377
  {
@@ -329,8 +384,15 @@ namespace Amanotes.Core.Internal
329
384
 
330
385
  _showState = isSuccess ? ShowAdsState.ShowSuccess : ShowAdsState.ShowFail;
331
386
 
387
+ UpdateAdStatistics(isSuccess);
388
+ TriggerOnAfterAdShow();
332
389
 
390
+ var currentContext = ProcessAdContext(isSuccess);
391
+ CompleteAdRoutine(currentContext, isSuccess);
392
+ }
333
393
 
394
+ private void UpdateAdStatistics(bool isSuccess)
395
+ {
334
396
  var localData = Ads.localData;
335
397
  var stat = _isInterstitial ? localData.interstitial : localData.reward;
336
398
  if (isSuccess)
@@ -343,15 +405,31 @@ namespace Amanotes.Core.Internal
343
405
  stat.failed++;
344
406
  stat.failedTotal++;
345
407
  }
346
-
347
408
  localData.Save();
348
- TriggerOnAfterAdShow();
409
+ }
349
410
 
350
- Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{JsonUtility.ToJson(Ads.context)}");
411
+ private AdShowContext ProcessAdContext(bool isSuccess)
412
+ {
413
+ var currentContext = Ads.context;
414
+ Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{(currentContext != null ? JsonUtility.ToJson(currentContext) : "Context is null")}");
351
415
 
416
+ // Fix: https://amanotes.sentry.io/issues/6366233489/events/0f3f58d81f0848b9bdbf1fd3e4a8161f/
417
+ if (currentContext != null)
418
+ {
419
+ currentContext.showFinishAt = Time.realtimeSinceStartup;
420
+ }
421
+ return currentContext;
422
+ }
423
+
424
+ private void CompleteAdRoutine(AdShowContext currentContext, bool isSuccess)
425
+ {
426
+ Action<bool> resultCallback = null;
427
+ if (currentContext != null)
428
+ {
429
+ resultCallback = currentContext.onAdResult;
430
+ }
431
+
352
432
  // Extra callback
353
- context.showFinishAt = Time.realtimeSinceStartup;
354
- var resultCallback = context.onAdResult;
355
433
  Ads.context = null;
356
434
  _showState = ShowAdsState.None;
357
435
  resultCallback?.Invoke(isSuccess);
@@ -361,60 +439,60 @@ namespace Amanotes.Core.Internal
361
439
  {
362
440
  if (Application.platform == RuntimePlatform.IPhonePlayer)
363
441
  {
364
- bool willSaveVolume = Config.ad.autoMute
365
- && AudioListener.volume > 0
366
- && Ads._savedVolume < 0;
442
+ HandleVolumeAndTimeScale();
443
+ }
367
444
 
368
- bool willSaveTimeScale = Config.ad.autoTimeScale
369
- && Time.timeScale > 0
370
- && Ads._savedTimeScale < 0;
445
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
446
+ Ads.context.onBeforeAdOpen?.Invoke();
447
+ }
371
448
 
372
- if (willSaveVolume)
373
- {
374
- Ads._savedVolume = AudioListener.volume;
375
- AudioListener.volume = 0;
376
- }
449
+ private void HandleVolumeAndTimeScale()
450
+ {
451
+ bool willSaveVolume = Config.ad.autoMute && AudioListener.volume > 0 && Ads._savedVolume < 0;
452
+ bool willSaveTimeScale = Config.ad.autoTimeScale && Time.timeScale > 0 && Ads._savedTimeScale < 0;
377
453
 
378
- if (willSaveTimeScale)
379
- {
380
- Ads._savedTimeScale = Time.timeScale;
381
- Time.timeScale = 0;
382
- }
454
+ if (willSaveVolume)
455
+ {
456
+ Ads._savedVolume = AudioListener.volume;
457
+ AudioListener.volume = 0;
383
458
  }
384
459
 
385
- dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
386
- Ads.context.onBeforeAdOpen?.Invoke();
460
+ if (willSaveTimeScale)
461
+ {
462
+ Ads._savedTimeScale = Time.timeScale;
463
+ Time.timeScale = 0;
464
+ }
387
465
  }
388
466
 
389
467
  private void TriggerOnAfterAdShow()
390
468
  {
391
469
  if (Application.platform == RuntimePlatform.IPhonePlayer)
392
470
  {
393
- bool willRestoreVolume = Config.ad.autoMute
394
- && Mathf.Approximately(AudioListener.volume, 0)
395
- && Ads._savedVolume > 0;
396
-
397
- bool willRestoreTimeScale = Config.ad.autoTimeScale
398
- && Mathf.Approximately(Time.timeScale, 0)
399
- && Ads._savedTimeScale > 0;
400
-
401
- if (willRestoreVolume)
402
- {
403
- AudioListener.volume = Ads._savedVolume;
404
- Ads._savedVolume = -1;
405
- }
406
-
407
- if (willRestoreTimeScale)
408
- {
409
- Time.timeScale = Ads._savedTimeScale;
410
- Ads._savedTimeScale = -1;
411
- }
471
+ RestoreVolumeAndTimeScale();
412
472
  }
413
473
 
414
474
  bool isSuccess = _showState == ShowAdsState.ShowSuccess;
415
475
  dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_END : AmaGDK.Event.REWARD_VIDEO_SHOW_END, isSuccess);
416
476
  }
417
477
 
478
+ private void RestoreVolumeAndTimeScale()
479
+ {
480
+ bool willRestoreVolume = Config.ad.autoMute && Mathf.Approximately(AudioListener.volume, 0) && Ads._savedVolume > 0;
481
+ bool willRestoreTimeScale = Config.ad.autoTimeScale && Mathf.Approximately(Time.timeScale, 0) && Ads._savedTimeScale > 0;
482
+
483
+ if (willRestoreVolume)
484
+ {
485
+ AudioListener.volume = Ads._savedVolume;
486
+ Ads._savedVolume = -1;
487
+ }
488
+
489
+ if (willRestoreTimeScale)
490
+ {
491
+ Time.timeScale = Ads._savedTimeScale;
492
+ Ads._savedTimeScale = -1;
493
+ }
494
+ }
495
+
418
496
  // Default implementation
419
497
  protected void OnAdClosed()
420
498
  {
@@ -485,6 +563,13 @@ namespace Amanotes.Core.Internal
485
563
  }
486
564
  }
487
565
 
566
+ private static readonly HashSet<AdShowReadyStatus> NotReadyStatuses = new HashSet<AdShowReadyStatus>
567
+ {
568
+ AdShowReadyStatus.NoInternet,
569
+ AdShowReadyStatus.TimeOut,
570
+ AdShowReadyStatus.Wifi3GDisabled
571
+ };
572
+
488
573
  protected void OnAdShowReadyStatus(bool isReady, AdShowReadyStatus status)
489
574
  {
490
575
  if (Ads.context == null)
@@ -495,17 +580,14 @@ namespace Amanotes.Core.Internal
495
580
 
496
581
  Ads.context.adCallback |= AdCallback.ShowReadyStatus;
497
582
  Ads.context.onAdShowReadyStatus?.Invoke(status);
583
+
498
584
  if (status == AdShowReadyStatus.Ready)
499
585
  {
500
- dispatcher.Dispatch(
501
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_READY
502
- );
503
- } else if (status == AdShowReadyStatus.NoInternet || status == AdShowReadyStatus.TimeOut || status == AdShowReadyStatus.Wifi3GDisabled)
586
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_READY);
587
+ }
588
+ else if (NotReadyStatuses.Contains(status))
504
589
  {
505
- dispatcher.Dispatch(
506
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY,
507
- status
508
- );
590
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY, status);
509
591
  }
510
592
  }
511
593
 
@@ -63,6 +63,8 @@ namespace Amanotes.Core.Internal
63
63
  return false;
64
64
  }
65
65
 
66
+ Log($"Registering Adapter<{id}>");
67
+
66
68
  var adapter = AmaGDK.Config.GetFieldValue<Adapter2>(id);
67
69
  if (adapter == null)
68
70
  {