You've already forked Commercialization.tapadn
Add iOS support for TapADN package
This commit is contained in:
@@ -366,6 +366,10 @@ namespace Dirichlet.Mediation
|
||||
private readonly IDirichletPlatformBridge bridge;
|
||||
private static readonly object RewardAutoSessionLock = new object();
|
||||
private static readonly Dictionary<string, AutoRewardVideoSession> RewardAutoSessions = new Dictionary<string, AutoRewardVideoSession>(StringComparer.Ordinal);
|
||||
private static readonly object InterstitialAutoSessionLock = new object();
|
||||
private static readonly Dictionary<string, AutoInterstitialSession> InterstitialAutoSessions = new Dictionary<string, AutoInterstitialSession>(StringComparer.Ordinal);
|
||||
private static readonly object SplashAutoSessionLock = new object();
|
||||
private static readonly Dictionary<string, AutoSplashSession> SplashAutoSessions = new Dictionary<string, AutoSplashSession>(StringComparer.Ordinal);
|
||||
|
||||
public static DirichletAdNative Create() => DirichletAdManager.CreateAdNative();
|
||||
|
||||
@@ -478,7 +482,7 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Shows an interstitial ad with automatic load-and-show logic.
|
||||
/// Android only - iOS receives OnError with not_supported.
|
||||
/// Android uses the native AutoAd API; iOS/editor use a load-then-show fallback without native cache.
|
||||
/// </summary>
|
||||
public void ShowInterstitialAutoAd(DirichletAdRequest request, IDirichletInterstitialAutoAdListener listener)
|
||||
{
|
||||
@@ -487,13 +491,17 @@ namespace Dirichlet.Mediation
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
bridge.ShowInterstitialAutoAd(request, listener);
|
||||
#else
|
||||
ShowInterstitialLoadAndShowInternal(request, listener);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a banner ad with automatic load + rotation logic. Container is created internally and
|
||||
/// anchored at the bottom of the screen by default. Use <see cref="DirichletAdRequest.Builder.WithSlideInterval"/>
|
||||
/// to control rotation interval. Android only - iOS receives OnError with not_supported.
|
||||
/// to control rotation interval. Native auto rotation is currently Android only.
|
||||
/// </summary>
|
||||
public void ShowBannerAutoAd(DirichletAdRequest request, IDirichletBannerAutoAdListener listener)
|
||||
{
|
||||
@@ -516,7 +524,7 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Shows a splash ad with automatic load logic. Container is a fullscreen overlay created internally.
|
||||
/// Android only - iOS receives OnError with not_supported.
|
||||
/// Android uses the native AutoAd API; iOS/editor use a load-then-show fallback without native cache.
|
||||
/// </summary>
|
||||
public void ShowSplashAutoAd(DirichletAdRequest request, IDirichletSplashAutoAdListener listener)
|
||||
{
|
||||
@@ -533,7 +541,11 @@ namespace Dirichlet.Mediation
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
bridge.ShowSplashAutoAd(request, options ?? new DirichletAdShowOptions(), listener);
|
||||
#else
|
||||
ShowSplashLoadAndShowInternal(request, options ?? new DirichletAdShowOptions(), listener);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -566,6 +578,7 @@ namespace Dirichlet.Mediation
|
||||
var session = new AutoRewardVideoSession(sessionId, ad, listener);
|
||||
RegisterRewardAutoSession(session);
|
||||
ad.SetInteractionListener(session);
|
||||
ad.ShowFailed += session.OnShowFailed;
|
||||
|
||||
// Load succeeded; show immediately.
|
||||
var shown = ad.Show();
|
||||
@@ -580,6 +593,66 @@ namespace Dirichlet.Mediation
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowInterstitialLoadAndShowInternal(DirichletAdRequest request, IDirichletInterstitialAutoAdListener listener)
|
||||
{
|
||||
LoadInterstitialAd(
|
||||
request,
|
||||
ad =>
|
||||
{
|
||||
if (ad == null)
|
||||
{
|
||||
listener?.OnError(new DirichletError("invalid_ad", "Load callback returned null ad"));
|
||||
return;
|
||||
}
|
||||
|
||||
var sessionId = Guid.NewGuid().ToString("N");
|
||||
var session = new AutoInterstitialSession(sessionId, ad, listener);
|
||||
RegisterInterstitialAutoSession(session);
|
||||
ad.SetInteractionListener(session);
|
||||
ad.ShowFailed += session.OnShowFailed;
|
||||
|
||||
var shown = ad.Show();
|
||||
if (!shown)
|
||||
{
|
||||
session.FailAndDispose(new DirichletError("show_failed", "ShowInterstitialAd returned false"));
|
||||
}
|
||||
},
|
||||
error =>
|
||||
{
|
||||
listener?.OnError(error ?? new DirichletError("load_failed", "LoadInterstitialAd failed"));
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowSplashLoadAndShowInternal(DirichletAdRequest request, DirichletAdShowOptions options, IDirichletSplashAutoAdListener listener)
|
||||
{
|
||||
LoadSplashAd(
|
||||
request,
|
||||
ad =>
|
||||
{
|
||||
if (ad == null)
|
||||
{
|
||||
listener?.OnError(new DirichletError("invalid_ad", "Load callback returned null ad"));
|
||||
return;
|
||||
}
|
||||
|
||||
var sessionId = Guid.NewGuid().ToString("N");
|
||||
var session = new AutoSplashSession(sessionId, ad, listener);
|
||||
RegisterSplashAutoSession(session);
|
||||
ad.SetInteractionListener(session);
|
||||
ad.ShowFailed += session.OnShowFailed;
|
||||
|
||||
var shown = ad.Show();
|
||||
if (!shown)
|
||||
{
|
||||
session.FailAndDispose(new DirichletError("show_failed", "ShowSplashAd returned false"));
|
||||
}
|
||||
},
|
||||
error =>
|
||||
{
|
||||
listener?.OnError(error ?? new DirichletError("load_failed", "LoadSplashAd failed"));
|
||||
});
|
||||
}
|
||||
|
||||
private static bool ValidateRequest(DirichletAdRequest request, Action<DirichletError> onFailure)
|
||||
{
|
||||
if (request == null)
|
||||
@@ -628,6 +701,58 @@ namespace Dirichlet.Mediation
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterInterstitialAutoSession(AutoInterstitialSession session)
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (InterstitialAutoSessionLock)
|
||||
{
|
||||
InterstitialAutoSessions[session.SessionId] = session;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnregisterInterstitialAutoSession(string sessionId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (InterstitialAutoSessionLock)
|
||||
{
|
||||
InterstitialAutoSessions.Remove(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterSplashAutoSession(AutoSplashSession session)
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (SplashAutoSessionLock)
|
||||
{
|
||||
SplashAutoSessions[session.SessionId] = session;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnregisterSplashAutoSession(string sessionId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (SplashAutoSessionLock)
|
||||
{
|
||||
SplashAutoSessions.Remove(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class AutoRewardVideoSession : IDirichletRewardAdInteractionListener
|
||||
{
|
||||
public string SessionId { get; }
|
||||
@@ -684,6 +809,11 @@ namespace Dirichlet.Mediation
|
||||
listener?.OnRewardVerify(args);
|
||||
}
|
||||
|
||||
public void OnShowFailed(DirichletError error)
|
||||
{
|
||||
FailAndDispose(error ?? new DirichletError("show_error", "Reward video ad failed to show"));
|
||||
}
|
||||
|
||||
public void FailAndDispose(DirichletError error)
|
||||
{
|
||||
if (disposed)
|
||||
@@ -707,6 +837,8 @@ namespace Dirichlet.Mediation
|
||||
|
||||
try
|
||||
{
|
||||
ad.ShowFailed -= OnShowFailed;
|
||||
ad.SetInteractionListener(null);
|
||||
ad?.Destroy();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -715,6 +847,176 @@ namespace Dirichlet.Mediation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class AutoInterstitialSession : IDirichletInterstitialAdInteractionListener
|
||||
{
|
||||
public string SessionId { get; }
|
||||
|
||||
private readonly DirichletInterstitialAd ad;
|
||||
private readonly IDirichletInterstitialAutoAdListener listener;
|
||||
private bool disposed;
|
||||
|
||||
public AutoInterstitialSession(string sessionId, DirichletInterstitialAd ad, IDirichletInterstitialAutoAdListener listener)
|
||||
{
|
||||
SessionId = string.IsNullOrEmpty(sessionId) ? Guid.NewGuid().ToString("N") : sessionId;
|
||||
this.ad = ad ?? throw new ArgumentNullException(nameof(ad));
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void OnAdShow()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdShow();
|
||||
}
|
||||
|
||||
public void OnAdClick()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdClick();
|
||||
}
|
||||
|
||||
public void OnAdClose()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdClose();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void OnShowFailed(DirichletError error)
|
||||
{
|
||||
FailAndDispose(error ?? new DirichletError("show_error", "Interstitial ad failed to show"));
|
||||
}
|
||||
|
||||
public void FailAndDispose(DirichletError error)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnError(error ?? new DirichletError("unknown_error", "Unknown error"));
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
UnregisterInterstitialAutoSession(SessionId);
|
||||
|
||||
try
|
||||
{
|
||||
ad.ShowFailed -= OnShowFailed;
|
||||
ad.SetInteractionListener(null);
|
||||
ad?.Destroy();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[Dirichlet] Auto interstitial ad Destroy failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class AutoSplashSession : IDirichletSplashAdInteractionListener
|
||||
{
|
||||
public string SessionId { get; }
|
||||
|
||||
private readonly DirichletSplashAd ad;
|
||||
private readonly IDirichletSplashAutoAdListener listener;
|
||||
private bool disposed;
|
||||
|
||||
public AutoSplashSession(string sessionId, DirichletSplashAd ad, IDirichletSplashAutoAdListener listener)
|
||||
{
|
||||
SessionId = string.IsNullOrEmpty(sessionId) ? Guid.NewGuid().ToString("N") : sessionId;
|
||||
this.ad = ad ?? throw new ArgumentNullException(nameof(ad));
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void OnAdShow()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdShow();
|
||||
}
|
||||
|
||||
public void OnAdClick()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdClick();
|
||||
}
|
||||
|
||||
public void OnAdClose()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnAdClose();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void OnShowFailed(DirichletError error)
|
||||
{
|
||||
FailAndDispose(error ?? new DirichletError("show_error", "Splash ad failed to show"));
|
||||
}
|
||||
|
||||
public void FailAndDispose(DirichletError error)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
listener?.OnError(error ?? new DirichletError("unknown_error", "Unknown error"));
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
UnregisterSplashAutoSession(SessionId);
|
||||
|
||||
try
|
||||
{
|
||||
ad.ShowFailed -= OnShowFailed;
|
||||
ad.SetInteractionListener(null);
|
||||
ad?.Destroy();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[Dirichlet] Auto splash ad Destroy failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1189,7 +1491,7 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Listener interface for auto interstitial ad callbacks.
|
||||
/// Android only - iOS will receive OnError with not_supported error.
|
||||
/// Android uses native auto cache; iOS/editor can emulate load-then-show.
|
||||
/// </summary>
|
||||
public interface IDirichletInterstitialAutoAdListener
|
||||
{
|
||||
@@ -1201,7 +1503,7 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Listener interface for auto banner ad callbacks.
|
||||
/// Android only - iOS will receive OnError with not_supported error.
|
||||
/// Native auto rotation is Android only.
|
||||
/// </summary>
|
||||
public interface IDirichletBannerAutoAdListener
|
||||
{
|
||||
@@ -1213,7 +1515,7 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Listener interface for auto splash ad callbacks.
|
||||
/// Android only - iOS will receive OnError with not_supported error.
|
||||
/// Android uses native auto cache; iOS/editor can emulate load-then-show.
|
||||
/// </summary>
|
||||
public interface IDirichletSplashAutoAdListener
|
||||
{
|
||||
@@ -1226,7 +1528,7 @@ namespace Dirichlet.Mediation
|
||||
/// <summary>
|
||||
/// Listener interface for auto reward video ad callbacks.
|
||||
/// Used with ShowRewardVideoAutoAd which combines load and show into one operation.
|
||||
/// Android only - iOS will receive OnError with not_supported error.
|
||||
/// Android uses native auto cache; iOS/editor can emulate load-then-show.
|
||||
/// </summary>
|
||||
public interface IDirichletRewardVideoAutoAdListener
|
||||
{
|
||||
|
||||
@@ -580,12 +580,12 @@ namespace Dirichlet.Mediation
|
||||
|
||||
/// <summary>
|
||||
/// Shows a reward video ad with automatic load-and-show logic.
|
||||
/// Android only - iOS will call onFailure with not_supported error.
|
||||
/// Android bridge maps to native auto cache; higher layers may emulate load-then-show elsewhere.
|
||||
/// </summary>
|
||||
void ShowRewardVideoAutoAd(DirichletAdRequest request, IDirichletRewardVideoAutoAdListener listener);
|
||||
|
||||
/// <summary>
|
||||
/// Shows an interstitial ad with automatic load-and-show logic. Android only.
|
||||
/// Shows an interstitial ad with automatic load-and-show logic. Android bridge maps to native auto cache.
|
||||
/// </summary>
|
||||
void ShowInterstitialAutoAd(DirichletAdRequest request, IDirichletInterstitialAutoAdListener listener);
|
||||
|
||||
@@ -595,7 +595,7 @@ namespace Dirichlet.Mediation
|
||||
void ShowBannerAutoAd(DirichletAdRequest request, DirichletAdShowOptions options, IDirichletBannerAutoAdListener listener);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a splash ad with automatic load logic. Android only.
|
||||
/// Shows a splash ad with automatic load logic. Android bridge maps to native auto cache.
|
||||
/// </summary>
|
||||
void ShowSplashAutoAd(DirichletAdRequest request, DirichletAdShowOptions options, IDirichletSplashAutoAdListener listener);
|
||||
|
||||
@@ -1563,20 +1563,9 @@ namespace Dirichlet.Mediation
|
||||
}
|
||||
first = false;
|
||||
|
||||
jsonBuilder.Append($"\"{kv.Key}\":");
|
||||
|
||||
if (kv.Value is string)
|
||||
{
|
||||
jsonBuilder.Append($"\"{kv.Value}\"");
|
||||
}
|
||||
else if (kv.Value is bool)
|
||||
{
|
||||
jsonBuilder.Append(((bool)kv.Value) ? "true" : "false");
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonBuilder.Append(kv.Value.ToString());
|
||||
}
|
||||
AppendJsonString(jsonBuilder, kv.Key);
|
||||
jsonBuilder.Append(":");
|
||||
AppendJsonValue(jsonBuilder, kv.Value);
|
||||
}
|
||||
|
||||
jsonBuilder.Append("}");
|
||||
@@ -1589,6 +1578,84 @@ namespace Dirichlet.Mediation
|
||||
}
|
||||
}
|
||||
|
||||
private static void AppendJsonValue(System.Text.StringBuilder builder, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
builder.Append("null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is string stringValue)
|
||||
{
|
||||
AppendJsonString(builder, stringValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is bool boolValue)
|
||||
{
|
||||
builder.Append(boolValue ? "true" : "false");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is IFormattable formattable)
|
||||
{
|
||||
builder.Append(formattable.ToString(null, CultureInfo.InvariantCulture));
|
||||
return;
|
||||
}
|
||||
|
||||
AppendJsonString(builder, value.ToString());
|
||||
}
|
||||
|
||||
private static void AppendJsonString(System.Text.StringBuilder builder, string value)
|
||||
{
|
||||
builder.Append('"');
|
||||
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
foreach (var c in value)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
builder.Append("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
builder.Append("\\\"");
|
||||
break;
|
||||
case '\b':
|
||||
builder.Append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
builder.Append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
builder.Append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.Append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
builder.Append("\\t");
|
||||
break;
|
||||
default:
|
||||
if (char.IsControl(c))
|
||||
{
|
||||
builder.Append("\\u");
|
||||
builder.Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.Append('"');
|
||||
}
|
||||
|
||||
private void RemoveLoadCallback(string handleId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(handleId))
|
||||
@@ -2032,5 +2099,3 @@ namespace Dirichlet.Mediation
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user