com.amanotes.gdk 0.2.86 → 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 (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/Editor/Extra/GDKCIBuildCommand.cs +19 -2
  3. package/Editor/Extra/GDKLocalBuild.cs +25 -1
  4. package/Editor/Utils/AmaGDKEditor.ExtractVersion.Max.cs +7 -0
  5. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  6. package/Extra/AutoEventQC.unitypackage +0 -0
  7. package/Extra/CheckDiskSpace.unitypackage +0 -0
  8. package/Extra/Consent.unitypackage +0 -0
  9. package/Extra/CrashlyticHook.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.PurchaseConnector.unitypackage +0 -0
  17. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  18. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  19. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  20. package/Packages/IronSourceAdapter.AdQuality.unitypackage +0 -0
  21. package/Packages/IronSourceAdapter.unitypackage +0 -0
  22. package/Packages/MaxAdNetworkAdapter.unitypackage +0 -0
  23. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  24. package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
  25. package/Runtime/Ad/AdLogic.cs +222 -147
  26. package/Runtime/AmaGDK.Analytics.cs +105 -65
  27. package/Runtime/AmaGDK.RemoteConfig.cs +50 -40
  28. package/Runtime/AmaGDK.cs +1 -1
  29. package/Runtime/AnalyticQualityAsset.cs +69 -38
  30. package/Runtime/AudioToolkit/Plugins/AudioDeviceDetector.cs +31 -17
  31. package/Runtime/Core/GDKSemVer.cs +23 -26
  32. package/Runtime/Fps/AmaFPSVisualizer.cs +48 -26
  33. package/Runtime/Internal/AmaGDK.Utils.cs +90 -46
  34. package/Runtime/Internal/ForceQuitMonitor.cs +43 -31
  35. package/Runtime/Klavar/Attributes/MinMaxAttribute.cs +12 -3
  36. package/Runtime/UI/ScrollView/GDKScrollView.cs +83 -48
  37. package/Runtime/Utils/GDKFileUtils.cs +2 -7
  38. package/Runtime/Utils/GDKUtils.cs +20 -8
  39. 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,18 +405,27 @@ 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
- // Fix: https://amanotes.sentry.io/issues/6366233489/events/0f3f58d81f0848b9bdbf1fd3e4a8161f/
411
+ private AdShowContext ProcessAdContext(bool isSuccess)
412
+ {
351
413
  var currentContext = Ads.context;
352
414
  Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{(currentContext != null ? JsonUtility.ToJson(currentContext) : "Context is null")}");
353
415
 
354
- Action<bool> resultCallback = null;
416
+ // Fix: https://amanotes.sentry.io/issues/6366233489/events/0f3f58d81f0848b9bdbf1fd3e4a8161f/
355
417
  if (currentContext != null)
356
418
  {
357
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
+ {
358
429
  resultCallback = currentContext.onAdResult;
359
430
  }
360
431
 
@@ -368,60 +439,60 @@ namespace Amanotes.Core.Internal
368
439
  {
369
440
  if (Application.platform == RuntimePlatform.IPhonePlayer)
370
441
  {
371
- bool willSaveVolume = Config.ad.autoMute
372
- && AudioListener.volume > 0
373
- && Ads._savedVolume < 0;
442
+ HandleVolumeAndTimeScale();
443
+ }
374
444
 
375
- bool willSaveTimeScale = Config.ad.autoTimeScale
376
- && Time.timeScale > 0
377
- && Ads._savedTimeScale < 0;
445
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
446
+ Ads.context.onBeforeAdOpen?.Invoke();
447
+ }
378
448
 
379
- if (willSaveVolume)
380
- {
381
- Ads._savedVolume = AudioListener.volume;
382
- AudioListener.volume = 0;
383
- }
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;
384
453
 
385
- if (willSaveTimeScale)
386
- {
387
- Ads._savedTimeScale = Time.timeScale;
388
- Time.timeScale = 0;
389
- }
454
+ if (willSaveVolume)
455
+ {
456
+ Ads._savedVolume = AudioListener.volume;
457
+ AudioListener.volume = 0;
390
458
  }
391
459
 
392
- dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
393
- Ads.context.onBeforeAdOpen?.Invoke();
460
+ if (willSaveTimeScale)
461
+ {
462
+ Ads._savedTimeScale = Time.timeScale;
463
+ Time.timeScale = 0;
464
+ }
394
465
  }
395
466
 
396
467
  private void TriggerOnAfterAdShow()
397
468
  {
398
469
  if (Application.platform == RuntimePlatform.IPhonePlayer)
399
470
  {
400
- bool willRestoreVolume = Config.ad.autoMute
401
- && Mathf.Approximately(AudioListener.volume, 0)
402
- && Ads._savedVolume > 0;
403
-
404
- bool willRestoreTimeScale = Config.ad.autoTimeScale
405
- && Mathf.Approximately(Time.timeScale, 0)
406
- && Ads._savedTimeScale > 0;
407
-
408
- if (willRestoreVolume)
409
- {
410
- AudioListener.volume = Ads._savedVolume;
411
- Ads._savedVolume = -1;
412
- }
413
-
414
- if (willRestoreTimeScale)
415
- {
416
- Time.timeScale = Ads._savedTimeScale;
417
- Ads._savedTimeScale = -1;
418
- }
471
+ RestoreVolumeAndTimeScale();
419
472
  }
420
473
 
421
474
  bool isSuccess = _showState == ShowAdsState.ShowSuccess;
422
475
  dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_END : AmaGDK.Event.REWARD_VIDEO_SHOW_END, isSuccess);
423
476
  }
424
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
+
425
496
  // Default implementation
426
497
  protected void OnAdClosed()
427
498
  {
@@ -492,6 +563,13 @@ namespace Amanotes.Core.Internal
492
563
  }
493
564
  }
494
565
 
566
+ private static readonly HashSet<AdShowReadyStatus> NotReadyStatuses = new HashSet<AdShowReadyStatus>
567
+ {
568
+ AdShowReadyStatus.NoInternet,
569
+ AdShowReadyStatus.TimeOut,
570
+ AdShowReadyStatus.Wifi3GDisabled
571
+ };
572
+
495
573
  protected void OnAdShowReadyStatus(bool isReady, AdShowReadyStatus status)
496
574
  {
497
575
  if (Ads.context == null)
@@ -502,17 +580,14 @@ namespace Amanotes.Core.Internal
502
580
 
503
581
  Ads.context.adCallback |= AdCallback.ShowReadyStatus;
504
582
  Ads.context.onAdShowReadyStatus?.Invoke(status);
583
+
505
584
  if (status == AdShowReadyStatus.Ready)
506
585
  {
507
- dispatcher.Dispatch(
508
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_READY
509
- );
510
- } 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))
511
589
  {
512
- dispatcher.Dispatch(
513
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY,
514
- status
515
- );
590
+ dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY, status);
516
591
  }
517
592
  }
518
593