diff --git a/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsConsentController.cs b/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsConsentController.cs index 1baf4be29..1a52bcf75 100644 --- a/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsConsentController.cs +++ b/samples/HelloWorld/Assets/Scripts/GoogleMobileAdsConsentController.cs @@ -12,6 +12,7 @@ namespace GoogleMobileAds.Samples public class GoogleMobileAdsConsentController : MonoBehaviour { /// + /// Test /// If true, it is safe to call MobileAds.Initialize() and load Ads. /// public bool CanRequestAds => ConsentInformation.CanRequestAds(); diff --git a/source/plugin/Assets/GoogleMobileAds/Common/CuiHandler.cs b/source/plugin/Assets/GoogleMobileAds/Common/CuiHandler.cs deleted file mode 100644 index 9c48fb74f..000000000 --- a/source/plugin/Assets/GoogleMobileAds/Common/CuiHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace GoogleMobileAds.Common -{ - [Serializable] - public struct CuiLoggablePayload - { - public Insight unity_gma_sdk_cui_message; - } -} diff --git a/source/plugin/Assets/GoogleMobileAds/Common/ProdInsightsEmitter.cs b/source/plugin/Assets/GoogleMobileAds/Common/ProdInsightsEmitter.cs index 7379697a7..9098f47c9 100644 --- a/source/plugin/Assets/GoogleMobileAds/Common/ProdInsightsEmitter.cs +++ b/source/plugin/Assets/GoogleMobileAds/Common/ProdInsightsEmitter.cs @@ -1,12 +1,94 @@ using System; +using System.Collections.Generic; +using UnityEngine; namespace GoogleMobileAds.Common { - public class InsightsEmitter : IInsightsEmitter - { - public void Emit(Insight insight) - { - // Intentionally left blank. - } - } + [Serializable] + public struct CuiLoggablePayload + { + public Insight unity_gma_sdk_cui_message; + } + + /// + /// A persistent singleton that captures all CUIs and sends them in batches to a backend + /// service (RCS) based on either a count or time threshold. + /// + public class InsightsEmitter : RcsClient, IInsightsEmitter + { + private static InsightsEmitter _instance; + public static InsightsEmitter Instance + { + get + { + if (_instance == null && Application.isPlaying) + { + _instance = FindObjectOfType(); + if (_instance == null) + { + _instance = new GameObject("InsightsEmitter") + .AddComponent(); + } + } + return _instance; + } + private set + { + _instance = value; + } + } + + #region Unity lifecycle methods + private void Awake() + { + if (_instance != null && _instance != this) + { + Destroy(gameObject); + return; + } + _instance = this; + DontDestroyOnLoad(gameObject); + } + #endregion + + /// + /// Call this to report a CUI. + /// This method is thread-safe and adds the CUI to the queue. + /// + public void Emit(Insight insight) + { + if (insight == null) return; + Enqueue(insight); + } + + /// + /// Builds and sends a batch of CUIs. + /// + protected override void SendBatch(List batch) + { + var payloads = new List(); + foreach (var insight in batch) + { + payloads.Add(new CuiLoggablePayload + { + unity_gma_sdk_cui_message = insight + }); + } + + var request = new LoggableRemoteCaptureRequest + { + payloads = payloads, + client_ping_metadata = new ClientPingMetadata + { + binary_name = 21, // UNITY_GMA_SDK + } + }; + + string jspbPayload = JspbConverter.ToJspb(request); + if (jspbPayload != null) + { + SendToRcs(jspbPayload); + } + } + } } diff --git a/source/plugin/Assets/GoogleMobileAds/Common/RcsClient.cs b/source/plugin/Assets/GoogleMobileAds/Common/RcsClient.cs index d567c12e8..7b8d8dfd7 100644 --- a/source/plugin/Assets/GoogleMobileAds/Common/RcsClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Common/RcsClient.cs @@ -36,8 +36,8 @@ protected override bool ValidateCertificate(byte[] certificateData) // Batching triggers can be overridden by subclasses. We don't need to expose them in Unity // Editor. If any trigger fires, a batch of items will get sent. - protected virtual int CountThreshold => 20; - protected virtual float TimeThresholdInSeconds => 120.0f; + protected virtual int CountThreshold => 2; + protected virtual float TimeThresholdInSeconds => 10.0f; // RCS endpoint for reporting. The `e=1` URL parameter defines JSPB encoding. private const string ProdRcsUrl = "https://pagead2.googlesyndication.com/pagead/ping?e=1"; diff --git a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs index cb5742b7d..d5b177a92 100644 --- a/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs +++ b/source/plugin/Assets/GoogleMobileAds/Platforms/Android/MobileAdsClient.cs @@ -28,14 +28,16 @@ public class MobileAdsClient : AndroidJavaProxy, IMobileAdsClient private readonly static MobileAdsClient _instance = new MobileAdsClient(); private readonly AndroidJavaClass _mobileAdsClass; - private readonly IInsightsEmitter _insightsEmitter = new InsightsEmitter(); + // Ensures InsightsEmitter is initialized from the main thread to handle CUIs. + private readonly IInsightsEmitter _insightsEmitter = InsightsEmitter.Instance; private readonly ITracer _tracer; private Action _initCompleteAction; private MobileAdsClient() : base(Utils.OnInitializationCompleteListenerClassName) { _mobileAdsClass = new AndroidJavaClass(Utils.UnityMobileAdsClassName); _tracer = new Tracer(_insightsEmitter); - // Ensures GlobalExceptionHandler is initialized to handle Android untrapped exceptions. + // Ensures GlobalExceptionHandler is initialized from the main thread to handle Android + // untrapped exceptions. var _ = GlobalExceptionHandler.Instance; }