Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions source/plugin/Assets/GoogleMobileAds/Common/DevInsightsEmitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.IO;
using System.Threading;
using UnityEngine;

namespace GoogleMobileAds.Common
{
// Emits insights when the SDK compiles in dev build mode.
// TODO: b/431227569 - We should add tracing to the Unity plugin, like for the Decagon SDK:
// http://google3/java/com/google/android/libraries/ads/mobile/sdk/internal/tracing/ExportingDebugTraceMonitor.kt.
public class InsightsEmitter : IInsightsEmitter
{
// LINT.IfChange
private const string _DEFAULT_INSIGHTS_FILE_NAME = "unity_insights.jsonl";
// LINT.ThenChange(//depot/google3/javatests/com/google/android/apps/internal/admobsdk/mediumtest/unityplugin/UnityTestUtils.java)

private readonly string _filePath;
private readonly bool _canWrite = true;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

/**
* Creates a new InsightsEmitter.
*
* @param filePath The file path to write the insights to. If null, the file will be written
* to the external storage directory.
*/
public InsightsEmitter(string filePath = null)
{
_filePath = filePath ?? Path.Combine(Application.persistentDataPath,
_DEFAULT_INSIGHTS_FILE_NAME);
Debug.Log("Unity insights will be written to: " + _filePath);

try
{
// No-op if the directory and subdirectories already exist.
Directory.CreateDirectory(Path.GetDirectoryName(_filePath));
} catch (Exception e) {
Debug.LogError("Failed to create directory for Unity insights (no insights will be " +
"written): " + e.Message);
_canWrite = false;
}
}

public void Emit(Insight insight)
{
if (!_canWrite)
{
return;
}

_lock.EnterWriteLock();
try
{
Debug.Log("Writing insight: " + insight.ToString());

// Writing needs to be synchronous for the read cursor to consume insights in order.
File.AppendAllText(_filePath, insight.ToJson() + Environment.NewLine);
}
finally
{
_lock.ExitWriteLock();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace GoogleMobileAds.Common
{
public interface IInsightsEmitter
{
void Emit(Insight insight);
}
}
112 changes: 112 additions & 0 deletions source/plugin/Assets/GoogleMobileAds/Common/Insight.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using UnityEngine;

// LINT.IfChange
namespace GoogleMobileAds.Common
{
// Protos are not supported in g3 for C#: http://yaqs/6221611834537934848. Instead, we use
// JSON Lines (http://jsonlines.org) to serialize the insights.
[Serializable]
public class Insight
{
public Insight()
{
StartTimeMillis = (long)DateTime.UtcNow
.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
.TotalMilliseconds;
}

public enum CuiName
{
Unknown = 0,
SdkInitialized = 1,
AdRequested = 2,
AdLoaded = 3,
AdFailedToLoad = 4,
AdShown = 5,
AdClosed = 6,
AdClicked = 7,
}

public enum AdFormat
{
Unknown = 0,
Banner = 1,
Interstitial = 2,
Rewarded = 3,
RewardedInterstitial = 4,
AppOpen = 5,
Native = 6,
}

public enum AdPlatform
{
Unknown = 0,
Android = 1,
Ios = 2,
Unity = 3,
}

// The name of the insight, commonly referred as a CUI (Critical User Interaction).
public CuiName Name;

// If the event associated with the insight succeeded or failed.
public bool Success;

// The Epoch time in milliseconds when the CUI started.
public long StartTimeMillis;

// How long the operation took to complete in milliseconds.
public long LatencyMillis;

// The GMA SDK version.
public string SdkVersion;

// The AdMob / Google Ad Manager app id.
public string AppId;

// The ad unit ID.
public string AdUnitId;

// The format of the ad.
public AdFormat Format;

// The platform on which the CUI was performed.
public AdPlatform Platform;

// The keywords associated with the insight. They are used to group insights together for
// analysis.
public List<string> Tags;

// Any additional details about the insight.
public string Details;

// Returns a string representation of the insight.
public override string ToString()
{
return string.Format(
"Insight[Name={0}, Success={1}, StartTimeMillis={2}, LatencyMillis={3}, " +
"SdkVersion='{4}', AppId='{5}', AdUnitId='{6}', Format={7}, Platform={8}, " +
"Tags='{9}', Details='{10}']",
Name,
Success,
StartTimeMillis,
LatencyMillis,
SdkVersion,
AppId,
AdUnitId,
Format,
Platform,
string.Join(",", Tags),
Details);
}

// Returns a JSON string representation of the insight.
public string ToJson()
{
return JsonUtility.ToJson(this, prettyPrint: true);
}
}
}
// LINT.ThenChange(//depot/google3/javatests/com/google/android/apps/internal/admobsdk/mediumtest/unityplugin/Insight.java)
11 changes: 11 additions & 0 deletions source/plugin/Assets/GoogleMobileAds/Common/ProdInsightsEmitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace GoogleMobileAds.Common
{
public class InsightsEmitter : IInsightsEmitter
{
public void Emit(Insight insight) {
// Intentionally left blank.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class MobileAdsClient : AndroidJavaProxy, IMobileAdsClient
{
private readonly static MobileAdsClient _instance = new MobileAdsClient();
private readonly AndroidJavaClass _mobileAdsClass;
private readonly IInsightsEmitter _insightsEmitter = new InsightsEmitter();
private Action<IInitializationStatusClient> _initCompleteAction;

private MobileAdsClient() : base(Utils.OnInitializationCompleteListenerClassName) {
Expand All @@ -52,6 +53,12 @@ public void Initialize(Action<IInitializationStatusClient> initCompleteAction)
try {
_mobileAdsClass.CallStatic("initialize", Utils.GetCurrentActivityAndroidJavaObject(),
this);
_insightsEmitter.Emit(new Insight()
{
Name = Insight.CuiName.SdkInitialized,
Platform = Insight.AdPlatform.Android,
Success = true
});
} finally {
AndroidJNI.DetachCurrentThread();
}
Expand Down