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;
}