You've already forked Commercialization.tapadn
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5810501618 | |||
| 894178a4c7 | |||
| f615580729 | |||
| ef5e5073a4 |
@@ -1,3 +1,30 @@
|
|||||||
|
# [1.0.4]
|
||||||
|
|
||||||
|
### 新增
|
||||||
|
|
||||||
|
* 激励视频支持按游戏场景映射不同 TapADN SpaceId,并在未配置或配置非法时回退默认激励广告位。
|
||||||
|
* 手动加载模式下激励视频缓存按 SpaceId 隔离,避免不同场景广告位串用 ready 缓存。
|
||||||
|
* 激励视频缓存默认 10 分钟未消费自动销毁,可通过 `tapadn.rewarded_cache_max_age_seconds` 覆盖。
|
||||||
|
|
||||||
|
### 调整
|
||||||
|
|
||||||
|
* 智能预加载归因缓存增加 SpaceId 维度,避免多广告位场景下 ready/归因状态混用。
|
||||||
|
|
||||||
|
# [1.0.3]
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
|
||||||
|
* iOS 导出后自动修复 `UnityFramework` target 的广告 SDK `FRAMEWORK_SEARCH_PATHS` / `HEADER_SEARCH_PATHS`,覆盖 Dirichlet、CSJ、GDT、DRA、GDTMobSDK、Tquic、BUAdSDK 的真实 xcframework slice。
|
||||||
|
* iOS 导出后清理 CocoaPods `Pods-UnityFramework*.xcconfig` 中的 `XCFrameworkIntermediates` 搜索路径,避免 Xcode 真机 Play 时出现 framework not found 或 search path not found。
|
||||||
|
* 保持签名配置由业务工程负责,广告模块不写入 Team、provisioning profile 或 code signing 设置。
|
||||||
|
|
||||||
|
# [1.0.1]
|
||||||
|
|
||||||
|
### 调整
|
||||||
|
|
||||||
|
* 包声明升级到 Unity `2022.3`,项目版本固定为 `2022.3.62f2c1`。
|
||||||
|
* 依赖的 `CC-Framework.Commercialization` 升级到 `1.0.15`,对齐源头商业化框架发布包。
|
||||||
|
|
||||||
# [1.0.0]
|
# [1.0.0]
|
||||||
|
|
||||||
### 新增
|
### 新增
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "Dirichlet.Mediation.Editor",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ffd2503194414b5e8b8e687a6a70a19f
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -149,28 +149,10 @@ namespace Dirichlet.Mediation.Editor
|
|||||||
var depsBlock = new StringBuilder();
|
var depsBlock = new StringBuilder();
|
||||||
depsBlock.AppendLine(DIRICHLET_DEPS_START);
|
depsBlock.AppendLine(DIRICHLET_DEPS_START);
|
||||||
|
|
||||||
// Core Mediation AAR
|
// Local AAR files are imported by Unity's PluginImporter from Assets/Plugins/Android.
|
||||||
depsBlock.AppendLine(" implementation(name: 'DirichletAD_Mediation_4.2.5.0', ext: 'aar')");
|
// Do not declare them here again, otherwise exported Gradle projects can get duplicate classes.
|
||||||
|
|
||||||
// CSJ (穿山甲) Adapter and SDK
|
|
||||||
if (enableCsj)
|
|
||||||
{
|
|
||||||
depsBlock.AppendLine(" implementation(name: 'DirichletAD_CSJ_Adapter_4.2.5.0', ext: 'aar')");
|
|
||||||
depsBlock.AppendLine(" implementation(name: 'open_ad_sdk_7.4.2.2', ext: 'aar')");
|
|
||||||
}
|
|
||||||
|
|
||||||
// GDT (广点通) Adapter and SDK
|
|
||||||
if (enableGdt)
|
|
||||||
{
|
|
||||||
depsBlock.AppendLine(" implementation(name: 'DirichletAD_GDT_Adapter_4.2.5.0', ext: 'aar')");
|
|
||||||
depsBlock.AppendLine(" implementation(name: 'GDTSDK.unionNormal.4.671.1541', ext: 'aar')");
|
|
||||||
}
|
|
||||||
|
|
||||||
// IQY (爱奇艺) Adapter and SDK
|
|
||||||
if (enableIqy)
|
if (enableIqy)
|
||||||
{
|
{
|
||||||
depsBlock.AppendLine(" implementation(name: 'DirichletAD_IQY_Adapter_4.2.5.0', ext: 'aar')");
|
|
||||||
depsBlock.AppendLine(" implementation(name: 'iadsdk-release-2.3.102.110', ext: 'aar')");
|
|
||||||
depsBlock.AppendLine(" implementation 'com.android.support.constraint:constraint-layout:1.1.3'");
|
depsBlock.AppendLine(" implementation 'com.android.support.constraint:constraint-layout:1.1.3'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ namespace Dirichlet.Mediation.Editor
|
|||||||
private const string ENV_ATT_DESCRIPTION = "DIRICHLET_IOS_ATT_DESCRIPTION";
|
private const string ENV_ATT_DESCRIPTION = "DIRICHLET_IOS_ATT_DESCRIPTION";
|
||||||
private const string PrefKeyIOSSDKVersion = "Dirichlet.iOS.SDKVersion";
|
private const string PrefKeyIOSSDKVersion = "Dirichlet.iOS.SDKVersion";
|
||||||
private const string PrefKeyATTDescription = "Dirichlet.iOS.TrackingUsageDescription";
|
private const string PrefKeyATTDescription = "Dirichlet.iOS.TrackingUsageDescription";
|
||||||
|
private const string IOSDeviceSlice = "ios-arm64";
|
||||||
|
private const string TquicIOSDeviceSlice = "ios-arm64_armv7";
|
||||||
|
private static readonly string[] GDTDynamicFrameworkNames = { "GDTMobSDK.framework", "Tquic.framework" };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析出的 target 信息
|
/// 解析出的 target 信息
|
||||||
@@ -78,8 +81,8 @@ namespace Dirichlet.Mediation.Editor
|
|||||||
// 4. Run pod install
|
// 4. Run pod install
|
||||||
RunPodInstall(pathToBuiltProject);
|
RunPodInstall(pathToBuiltProject);
|
||||||
|
|
||||||
// 5. Embed GDT dynamic frameworks into app target (must run after pod install)
|
// 5. Fix ad SDK framework/header search paths and embed GDT dynamic frameworks (must run after pod install)
|
||||||
EmbedGDTDynamicFrameworks(pathToBuiltProject, targetInfo);
|
FixAdSDKIOSFrameworkConfiguration(pathToBuiltProject, targetInfo);
|
||||||
|
|
||||||
Debug.Log("[DirichletMediation] iOS post-process completed successfully.");
|
Debug.Log("[DirichletMediation] iOS post-process completed successfully.");
|
||||||
}
|
}
|
||||||
@@ -517,20 +520,16 @@ namespace Dirichlet.Mediation.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GDTMobSDK 提供的是预编译动态库(GDTMobSDK.framework, Tquic.framework),
|
/// UnityFramework 链接阶段需要显式搜索广告 SDK xcframework 内部的真机 slice,
|
||||||
/// 必须 embed 到 app bundle 中才能在运行时加载。
|
/// 否则 Xcode 可能报 ld: framework 'GDTMobSDK' not found 或 XCFrameworkIntermediates 搜索路径缺失。
|
||||||
/// 由于所有 pods 都在 Framework target 上,CocoaPods 不会自动 embed 到 app target,
|
/// 同时 GDTMobSDK 提供的是预编译动态库(GDTMobSDK.framework, Tquic.framework),
|
||||||
/// 需要在 pod install 之后手动处理。
|
/// 必须 embed 到 app bundle 中才能在运行时加载。由于所有 pods 都在 Framework target 上,
|
||||||
|
/// CocoaPods 不会自动 embed 到 app target,需要在 pod install 之后手动处理。
|
||||||
/// 依赖 UnityEditor.iOS.Xcode.Extensions 中的 AddFileToEmbedFrameworks 扩展方法。
|
/// 依赖 UnityEditor.iOS.Xcode.Extensions 中的 AddFileToEmbedFrameworks 扩展方法。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void EmbedGDTDynamicFrameworks(string projectPath, TargetInfo targetInfo)
|
private static void FixAdSDKIOSFrameworkConfiguration(string projectPath, TargetInfo targetInfo)
|
||||||
{
|
{
|
||||||
var enableGdt = EditorPrefs.GetBool("Dirichlet.iOS.EnableGDT", true);
|
var enableGdt = EditorPrefs.GetBool("Dirichlet.iOS.EnableGDT", true);
|
||||||
if (!enableGdt)
|
|
||||||
{
|
|
||||||
Debug.Log("[DirichletMediation] GDT adapter disabled, skipping dynamic framework embedding");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xcodeProjectName = DetectXcodeProjectName(projectPath);
|
var xcodeProjectName = DetectXcodeProjectName(projectPath);
|
||||||
var projectFilePath = Path.Combine(projectPath, $"{xcodeProjectName}.xcodeproj/project.pbxproj");
|
var projectFilePath = Path.Combine(projectPath, $"{xcodeProjectName}.xcodeproj/project.pbxproj");
|
||||||
@@ -543,35 +542,281 @@ namespace Dirichlet.Mediation.Editor
|
|||||||
mainTargetGuid = pbxProject.TargetGuidByName(targetInfo.AppTargetName);
|
mainTargetGuid = pbxProject.TargetGuidByName(targetInfo.AppTargetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GDTMobSDK 的动态框架列表
|
var targetGuid = ResolveUnityFrameworkTargetGuid(pbxProject, targetInfo);
|
||||||
var dynamicFrameworkNames = new[] { "GDTMobSDK.framework", "Tquic.framework" };
|
var frameworkSearchPaths = GetAdSDKFrameworkSearchPaths();
|
||||||
|
var headerSearchPaths = GetAdSDKHeaderSearchPaths(frameworkSearchPaths);
|
||||||
|
|
||||||
|
var searchPathsAdded = AddAdSDKSearchPaths(pbxProject, targetGuid, frameworkSearchPaths, headerSearchPaths);
|
||||||
|
PatchPodsXCConfigSearchPaths(projectPath, targetInfo, frameworkSearchPaths, headerSearchPaths);
|
||||||
|
|
||||||
var podsDir = Path.Combine(projectPath, "Pods");
|
var podsDir = Path.Combine(projectPath, "Pods");
|
||||||
var embedded = 0;
|
var embedded = 0;
|
||||||
|
|
||||||
foreach (var frameworkName in dynamicFrameworkNames)
|
if (enableGdt)
|
||||||
{
|
{
|
||||||
var frameworkPath = FindDynamicFramework(podsDir, frameworkName);
|
foreach (var frameworkName in GDTDynamicFrameworkNames)
|
||||||
if (string.IsNullOrEmpty(frameworkPath))
|
{
|
||||||
|
var frameworkPath = FindDynamicFramework(podsDir, frameworkName);
|
||||||
|
if (string.IsNullOrEmpty(frameworkPath))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[DirichletMediation] Dynamic framework not found: {frameworkName}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var relativePath = frameworkPath.StartsWith(projectPath)
|
||||||
|
? frameworkPath.Substring(projectPath.Length + 1)
|
||||||
|
: frameworkPath;
|
||||||
|
|
||||||
|
var fileGuid = pbxProject.AddFile(relativePath, "Frameworks/" + frameworkName);
|
||||||
|
PBXProjectExtensions.AddFileToEmbedFrameworks(pbxProject, mainTargetGuid, fileGuid);
|
||||||
|
embedded++;
|
||||||
|
Debug.Log($"[DirichletMediation] Embedded dynamic framework: {frameworkName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Log("[DirichletMediation] GDT adapter disabled, skipping dynamic framework embedding");
|
||||||
|
}
|
||||||
|
|
||||||
|
pbxProject.WriteToFile(projectFilePath);
|
||||||
|
if (searchPathsAdded)
|
||||||
|
{
|
||||||
|
Debug.Log($"[DirichletMediation] Added ad SDK framework/header search paths to {targetInfo.FrameworkTargetName}");
|
||||||
|
}
|
||||||
|
Debug.Log($"[DirichletMediation] Embedded {embedded} GDT dynamic frameworks into {targetInfo.AppTargetName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveUnityFrameworkTargetGuid(PBXProject pbxProject, TargetInfo targetInfo)
|
||||||
|
{
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
var targetGuid = pbxProject.GetUnityFrameworkTargetGuid();
|
||||||
|
#else
|
||||||
|
var targetGuid = targetInfo.FrameworkTargetGuid;
|
||||||
|
#endif
|
||||||
|
if (string.IsNullOrEmpty(targetGuid))
|
||||||
|
{
|
||||||
|
targetGuid = targetInfo.FrameworkTargetGuid;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(targetGuid))
|
||||||
|
{
|
||||||
|
targetGuid = pbxProject.TargetGuidByName(targetInfo.FrameworkTargetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetGuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AddAdSDKSearchPaths(PBXProject pbxProject, string targetGuid, string[] frameworkSearchPaths, string[] headerSearchPaths)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(targetGuid))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[DirichletMediation] UnityFramework target GUID is empty, skipping ad SDK search paths");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbxProject.AddBuildProperty(targetGuid, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
|
||||||
|
foreach (var searchPath in frameworkSearchPaths)
|
||||||
|
{
|
||||||
|
pbxProject.AddBuildProperty(targetGuid, "FRAMEWORK_SEARCH_PATHS", searchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbxProject.AddBuildProperty(targetGuid, "HEADER_SEARCH_PATHS", "$(inherited)");
|
||||||
|
foreach (var searchPath in headerSearchPaths)
|
||||||
|
{
|
||||||
|
pbxProject.AddBuildProperty(targetGuid, "HEADER_SEARCH_PATHS", searchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PatchPodsXCConfigSearchPaths(
|
||||||
|
string projectPath,
|
||||||
|
TargetInfo targetInfo,
|
||||||
|
string[] frameworkSearchPaths,
|
||||||
|
string[] headerSearchPaths)
|
||||||
|
{
|
||||||
|
var targetSupportRoot = Path.Combine(projectPath, "Pods", "Target Support Files");
|
||||||
|
if (!Directory.Exists(targetSupportRoot))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[DirichletMediation] CocoaPods target support files not found, skipping xcconfig search path patch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetPrefix = "Pods-" + targetInfo.FrameworkTargetName;
|
||||||
|
var xcconfigFiles = Directory.GetFiles(targetSupportRoot, "*.xcconfig", SearchOption.AllDirectories)
|
||||||
|
.Where(path => Path.GetFileNameWithoutExtension(path).StartsWith(targetPrefix, System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (xcconfigFiles.Length == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[DirichletMediation] No CocoaPods xcconfig found for {targetInfo.FrameworkTargetName}, skipping search path patch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var patched = 0;
|
||||||
|
foreach (var xcconfigPath in xcconfigFiles)
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(xcconfigPath).ToList();
|
||||||
|
var changed = UpsertXCConfigBuildSetting(lines, "FRAMEWORK_SEARCH_PATHS", frameworkSearchPaths);
|
||||||
|
changed |= UpsertXCConfigBuildSetting(lines, "HEADER_SEARCH_PATHS", headerSearchPaths);
|
||||||
|
|
||||||
|
if (!changed)
|
||||||
{
|
{
|
||||||
Debug.LogWarning($"[DirichletMediation] Dynamic framework not found: {frameworkName}");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var relativePath = frameworkPath.StartsWith(projectPath)
|
File.WriteAllLines(xcconfigPath, lines);
|
||||||
? frameworkPath.Substring(projectPath.Length + 1)
|
patched++;
|
||||||
: frameworkPath;
|
|
||||||
|
|
||||||
var fileGuid = pbxProject.AddFile(relativePath, "Frameworks/" + frameworkName);
|
|
||||||
PBXProjectExtensions.AddFileToEmbedFrameworks(pbxProject, mainTargetGuid, fileGuid);
|
|
||||||
embedded++;
|
|
||||||
Debug.Log($"[DirichletMediation] Embedded dynamic framework: {frameworkName}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (embedded > 0)
|
Debug.Log($"[DirichletMediation] Patched {patched} CocoaPods xcconfig search path file(s) for {targetInfo.FrameworkTargetName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool UpsertXCConfigBuildSetting(System.Collections.Generic.List<string> lines, string propertyName, string[] searchPaths)
|
||||||
|
{
|
||||||
|
var insertIndex = -1;
|
||||||
|
var originalLines = new System.Collections.Generic.List<string>();
|
||||||
|
var tokens = new System.Collections.Generic.List<string>();
|
||||||
|
|
||||||
|
for (var i = lines.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
pbxProject.WriteToFile(projectFilePath);
|
if (!IsXCConfigBuildSettingLine(lines[i], propertyName))
|
||||||
Debug.Log($"[DirichletMediation] Embedded {embedded} GDT dynamic frameworks into {targetInfo.AppTargetName}");
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertIndex = i;
|
||||||
|
originalLines.Add(lines[i]);
|
||||||
|
CollectXCConfigBuildSettingTokens(lines[i], tokens);
|
||||||
|
lines.RemoveAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ContainsXCConfigToken(tokens, "$(inherited)"))
|
||||||
|
{
|
||||||
|
tokens.Insert(0, "$(inherited)");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var searchPath in searchPaths)
|
||||||
|
{
|
||||||
|
AddXCConfigTokenIfMissing(tokens, searchPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newLine = $"{propertyName} = {string.Join(" ", tokens)}";
|
||||||
|
|
||||||
|
if (insertIndex < 0)
|
||||||
|
{
|
||||||
|
lines.Add(newLine);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.Insert(insertIndex, newLine);
|
||||||
|
return originalLines.Count != 1 || originalLines[0] != newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CollectXCConfigBuildSettingTokens(string line, System.Collections.Generic.List<string> tokens)
|
||||||
|
{
|
||||||
|
var separatorIndex = line.IndexOf('=');
|
||||||
|
if (separatorIndex < 0 || separatorIndex >= line.Length - 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = line.Substring(separatorIndex + 1).Trim();
|
||||||
|
var lineTokens = value.Split(new[] { ' ', '\t' }, System.StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var token in lineTokens)
|
||||||
|
{
|
||||||
|
if (token.IndexOf("XCFrameworkIntermediates", System.StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddXCConfigTokenIfMissing(tokens, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ContainsXCConfigToken(System.Collections.Generic.List<string> tokens, string value)
|
||||||
|
{
|
||||||
|
var normalizedValue = NormalizeXCConfigToken(value);
|
||||||
|
return tokens.Any(token => NormalizeXCConfigToken(token) == normalizedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddXCConfigTokenIfMissing(System.Collections.Generic.List<string> tokens, string value)
|
||||||
|
{
|
||||||
|
if (!ContainsXCConfigToken(tokens, value))
|
||||||
|
{
|
||||||
|
tokens.Add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeXCConfigToken(string token)
|
||||||
|
{
|
||||||
|
return (token ?? string.Empty).Trim().Trim('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsXCConfigBuildSettingLine(string line, string propertyName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var trimmed = line.TrimStart();
|
||||||
|
return trimmed.StartsWith(propertyName + " =", System.StringComparison.Ordinal)
|
||||||
|
|| trimmed.StartsWith(propertyName + "=", System.StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] GetAdSDKFrameworkSearchPaths()
|
||||||
|
{
|
||||||
|
var sdkVersion = ResolveIOSSDKVersion();
|
||||||
|
var enableCsj = EditorPrefs.GetBool("Dirichlet.iOS.EnableCSJ", true);
|
||||||
|
var enableGdt = EditorPrefs.GetBool("Dirichlet.iOS.EnableGDT", true);
|
||||||
|
var paths = new System.Collections.Generic.List<string>
|
||||||
|
{
|
||||||
|
VersionedDirichletFrameworkSearchPath("DirichletAdSDK", sdkVersion),
|
||||||
|
VersionedDirichletFrameworkSearchPath("DirichletCoreSDK", sdkVersion),
|
||||||
|
VersionedDirichletFrameworkSearchPath("DirichletMediationSDK", sdkVersion),
|
||||||
|
VersionedDirichletFrameworkSearchPath("DirichletMediationAdapterDRA", sdkVersion)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (enableCsj)
|
||||||
|
{
|
||||||
|
paths.Add(VersionedDirichletFrameworkSearchPath("DirichletMediationAdapterCSJ", sdkVersion));
|
||||||
|
paths.Add("$(PODS_ROOT)/Ads-CN/SDK/BUAdSDK.xcframework/" + IOSDeviceSlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableGdt)
|
||||||
|
{
|
||||||
|
paths.Add(VersionedDirichletFrameworkSearchPath("DirichletMediationAdapterGDT", sdkVersion));
|
||||||
|
paths.Add("$(PODS_ROOT)/GDTMobSDK/GDTFramework/GDTMobSDK.xcframework/" + IOSDeviceSlice);
|
||||||
|
paths.Add("$(PODS_ROOT)/GDTMobSDK/GDTFramework/Tquic.xcframework/" + TquicIOSDeviceSlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] GetAdSDKHeaderSearchPaths(string[] frameworkSearchPaths)
|
||||||
|
{
|
||||||
|
return frameworkSearchPaths
|
||||||
|
.Select(ToFrameworkHeaderSearchPath)
|
||||||
|
.Where(path => !string.IsNullOrEmpty(path))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string VersionedDirichletFrameworkSearchPath(string frameworkName, string sdkVersion)
|
||||||
|
{
|
||||||
|
return $"$(PODS_ROOT)/{frameworkName}/{frameworkName}-{sdkVersion}/{frameworkName}.xcframework/{IOSDeviceSlice}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToFrameworkHeaderSearchPath(string frameworkSearchPath)
|
||||||
|
{
|
||||||
|
var parts = frameworkSearchPath.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var xcframeworkPart = parts.LastOrDefault(part => part.EndsWith(".xcframework", System.StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (string.IsNullOrEmpty(xcframeworkPart))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frameworkName = xcframeworkPart.Substring(0, xcframeworkPart.Length - ".xcframework".Length);
|
||||||
|
return $"{frameworkSearchPath}/{frameworkName}.framework/Headers";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<androidPackages>
|
<!-- WeChat OpenSDK is shipped as a local AAR under Assets/Plugins/Android. -->
|
||||||
<androidPackage spec="com.tencent.mm.opensdk:wechat-sdk-android:6.8.34">
|
|
||||||
<repositories>
|
|
||||||
<repository>https://maven.aliyun.com/repository/public</repository>
|
|
||||||
<repository>https://repo.maven.apache.org/maven2</repository>
|
|
||||||
</repositories>
|
|
||||||
</androidPackage>
|
|
||||||
</androidPackages>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Dirichlet.Mediation;
|
using Dirichlet.Mediation;
|
||||||
using Runtime.ADAggregator;
|
using Runtime.ADAggregator;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -7,8 +8,11 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
{
|
{
|
||||||
private const float RewardCloseSettleDelaySeconds = 0.25f;
|
private const float RewardCloseSettleDelaySeconds = 0.25f;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, RewardedSlotCache> _slotCaches = new Dictionary<string, RewardedSlotCache>(StringComparer.Ordinal);
|
||||||
|
|
||||||
private DirichletAdNative _adNative;
|
private DirichletAdNative _adNative;
|
||||||
private DirichletRewardVideoAd _loadedAd;
|
private string _defaultSlotId;
|
||||||
|
private string _activeSlotId;
|
||||||
private bool _rewardVerified;
|
private bool _rewardVerified;
|
||||||
private bool _rewardVerifyReceived;
|
private bool _rewardVerifyReceived;
|
||||||
private bool _closePendingRewardVerify;
|
private bool _closePendingRewardVerify;
|
||||||
@@ -22,30 +26,46 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
|
|
||||||
public override void OnInit()
|
public override void OnInit()
|
||||||
{
|
{
|
||||||
|
_defaultSlotId = Key;
|
||||||
_adNative = DirichletAdManager.CreateAdNative();
|
_adNative = DirichletAdManager.CreateAdNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsReadly()
|
public override bool IsReadly()
|
||||||
{
|
{
|
||||||
|
var slotId = ResolveCurrentSlotId();
|
||||||
if (UseAutoLoad())
|
if (UseAutoLoad())
|
||||||
{
|
{
|
||||||
return TapadnAdRequestFactory.TryParseSlotId(Key, out _);
|
return TapadnAdRequestFactory.TryParseSlotId(slotId, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_loadedAd != null && _loadedAd.IsLoaded && _loadedAd.IsValid)
|
var cache = GetCache(slotId);
|
||||||
|
if (IsCacheReady(cache))
|
||||||
{
|
{
|
||||||
curState = 2;
|
curState = 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cache != null && cache.Loading)
|
||||||
|
{
|
||||||
|
curState = 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache != null)
|
||||||
|
{
|
||||||
|
RemoveCache(slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
curState = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LoadAD()
|
public override void LoadAD()
|
||||||
{
|
{
|
||||||
if (!TapadnAdRequestFactory.TryParseSlotId(Key, out _))
|
var slotId = ResolveCurrentSlotId();
|
||||||
|
if (!TapadnAdRequestFactory.TryParseSlotId(slotId, out _))
|
||||||
{
|
{
|
||||||
Debug.LogError($"[TapADN] Invalid rewarded slot id: {Key}");
|
Debug.LogError($"[TapADN] Invalid rewarded slot id: {slotId}");
|
||||||
curState = 0;
|
curState = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -55,7 +75,7 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
curState = 2;
|
curState = 2;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_adNative.PreLoad(TapadnAdRequestFactory.BuildRewarded(Key, TapadnAdController.CurrentOptions), 3);
|
_adNative.PreLoad(TapadnAdRequestFactory.BuildRewarded(slotId, TapadnAdController.CurrentOptions), 3);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
@@ -64,33 +84,37 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curState == 1 || IsReadly())
|
var cache = GetCache(slotId);
|
||||||
|
if (cache != null && (cache.Loading || IsCacheReady(cache)))
|
||||||
{
|
{
|
||||||
|
curState = cache.Loading ? 1 : 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache = new RewardedSlotCache { Loading = true };
|
||||||
|
_slotCaches[slotId] = cache;
|
||||||
curState = 1;
|
curState = 1;
|
||||||
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.AwardVideo, AdScene);
|
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.AwardVideo, AdScene, slotId);
|
||||||
_adNative.LoadRewardVideoAd(
|
_adNative.LoadRewardVideoAd(
|
||||||
TapadnAdRequestFactory.BuildRewarded(Key, TapadnAdController.CurrentOptions),
|
TapadnAdRequestFactory.BuildRewarded(slotId, TapadnAdController.CurrentOptions),
|
||||||
ad =>
|
ad =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.AwardVideo, AdScene, true);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.AwardVideo, AdScene, true, slotId);
|
||||||
_loadedAd?.Destroy();
|
DestroyCachedAd(cache);
|
||||||
_loadedAd = ad;
|
cache.Ad = ad;
|
||||||
_loadedAd.Shown += OnManualShown;
|
cache.Loading = false;
|
||||||
_loadedAd.Clicked += OnManualClicked;
|
cache.LoadedUnix = GetNowUnixSeconds();
|
||||||
_loadedAd.ShowFailed += OnManualShowFailed;
|
RegisterManualEvents(slotId, cache.Ad);
|
||||||
_loadedAd.RewardVerified += OnManualRewardVerify;
|
ScheduleCacheExpiration(slotId, cache);
|
||||||
_loadedAd.Closed += OnManualClosed;
|
curState = string.Equals(slotId, ResolveCurrentSlotId(), StringComparison.Ordinal) ? 2 : curState;
|
||||||
curState = 2;
|
Debug.Log($"[TapADN] Rewarded loaded. scene={NormalizeScenario(AdScene)}, slot={slotId}");
|
||||||
Debug.Log($"[TapADN] Rewarded loaded. slot={Key}");
|
|
||||||
},
|
},
|
||||||
error =>
|
error =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.AwardVideo, AdScene, false);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.AwardVideo, AdScene, false, slotId);
|
||||||
curState = 0;
|
RemoveCache(slotId);
|
||||||
Debug.LogError($"[TapADN] Rewarded load failed. code={error.Code}, message={error.Message}");
|
curState = string.Equals(slotId, ResolveCurrentSlotId(), StringComparison.Ordinal) ? 0 : curState;
|
||||||
|
Debug.LogError($"[TapADN] Rewarded load failed. slot={slotId}, code={error.Code}, message={error.Message}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,16 +128,20 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
_showSettled = false;
|
_showSettled = false;
|
||||||
_rewardCloseSettleHandler?.Kill();
|
_rewardCloseSettleHandler?.Kill();
|
||||||
_rewardCloseSettleHandler = null;
|
_rewardCloseSettleHandler = null;
|
||||||
|
_activeSlotId = ResolveCurrentSlotId();
|
||||||
|
Key = _activeSlotId;
|
||||||
curState = 0;
|
curState = 0;
|
||||||
|
|
||||||
if (UseAutoLoad())
|
if (UseAutoLoad())
|
||||||
{
|
{
|
||||||
_adNative.ShowRewardVideoAutoAd(TapadnAdRequestFactory.BuildRewarded(Key, TapadnAdController.CurrentOptions), this);
|
_adNative.ShowRewardVideoAutoAd(TapadnAdRequestFactory.BuildRewarded(_activeSlotId, TapadnAdController.CurrentOptions), this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_loadedAd == null || !_loadedAd.Show())
|
var cache = GetCache(_activeSlotId);
|
||||||
|
if (!IsCacheReady(cache) || cache.Ad == null || !cache.Ad.Show())
|
||||||
{
|
{
|
||||||
|
RemoveCache(_activeSlotId);
|
||||||
OnError(new DirichletError("show_failed", "ShowRewardVideoAd returned false"));
|
OnError(new DirichletError("show_failed", "ShowRewardVideoAd returned false"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -130,14 +158,14 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
_rewardCloseSettleHandler?.Kill();
|
_rewardCloseSettleHandler?.Kill();
|
||||||
_rewardCloseSettleHandler = null;
|
_rewardCloseSettleHandler = null;
|
||||||
curState = 0;
|
curState = 0;
|
||||||
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.AwardVideo, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.AwardVideo, AdScene, _activeSlotId);
|
||||||
Debug.LogError($"[TapADN] Rewarded show failed. code={error?.Code}, message={error?.Message}");
|
Debug.LogError($"[TapADN] Rewarded show failed. slot={_activeSlotId}, code={error?.Code}, message={error?.Message}");
|
||||||
adListener.OnShowError();
|
adListener.OnShowError();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnAdShow()
|
public void OnAdShow()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.AwardVideo, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.AwardVideo, AdScene, _activeSlotId);
|
||||||
NotifyShowStarted();
|
NotifyShowStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,12 +203,23 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
|
|
||||||
public override void OnPlayRequestStarted()
|
public override void OnPlayRequestStarted()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.AwardVideo, AdScene, !UseAutoLoad() && IsReadly());
|
var slotId = ResolveCurrentSlotId();
|
||||||
|
Key = slotId;
|
||||||
|
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.AwardVideo, AdScene, !UseAutoLoad() && IsReadly(), slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterAdScenario(string scenario)
|
public override void EnterAdScenario(string scenario)
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.AwardVideo, scenario, Key);
|
AdScene = NormalizeScenario(scenario);
|
||||||
|
var slotId = ResolveCurrentSlotId();
|
||||||
|
Key = slotId;
|
||||||
|
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.AwardVideo, AdScene, slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ResolveCurrentSlotId()
|
||||||
|
{
|
||||||
|
var slotId = TapadnAdController.CurrentOptions?.ResolveRewardedSlotId(_defaultSlotId, AdScene) ?? _defaultSlotId;
|
||||||
|
return string.IsNullOrWhiteSpace(slotId) ? _defaultSlotId : slotId.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UseAutoLoad()
|
private bool UseAutoLoad()
|
||||||
@@ -188,8 +227,66 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
return TapadnAdController.CurrentOptions?.RewardedAutoLoad ?? true;
|
return TapadnAdController.CurrentOptions?.RewardedAutoLoad ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnManualShown()
|
private RewardedSlotCache GetCache(string slotId)
|
||||||
{
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(slotId) && _slotCaches.TryGetValue(slotId, out var cache) ? cache : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsCacheReady(RewardedSlotCache cache)
|
||||||
|
{
|
||||||
|
if (cache == null || cache.Loading || cache.Ad == null || !cache.Ad.IsLoaded || !cache.Ad.IsValid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxAgeSeconds = TapadnAdController.CurrentOptions?.RewardedCacheMaxAgeSeconds ?? 0;
|
||||||
|
return maxAgeSeconds <= 0 || GetNowUnixSeconds() - cache.LoadedUnix <= maxAgeSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterManualEvents(string slotId, DirichletRewardVideoAd ad)
|
||||||
|
{
|
||||||
|
if (ad == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ad.Shown += () => OnManualShown(slotId);
|
||||||
|
ad.Clicked += OnManualClicked;
|
||||||
|
ad.ShowFailed += error => OnManualShowFailed(slotId, error);
|
||||||
|
ad.RewardVerified += OnManualRewardVerify;
|
||||||
|
ad.Closed += () => OnManualClosed(slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScheduleCacheExpiration(string slotId, RewardedSlotCache cache)
|
||||||
|
{
|
||||||
|
cache.ExpireHandler?.Kill();
|
||||||
|
cache.ExpireHandler = null;
|
||||||
|
|
||||||
|
var maxAgeSeconds = TapadnAdController.CurrentOptions?.RewardedCacheMaxAgeSeconds ?? 600;
|
||||||
|
if (maxAgeSeconds <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.ExpireHandler = ADManager.Instance.CreateTimer(maxAgeSeconds, () =>
|
||||||
|
{
|
||||||
|
if (!ReferenceEquals(GetCache(slotId), cache))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[TapADN] Rewarded cache expired. slot={slotId}, maxAgeSeconds={maxAgeSeconds}");
|
||||||
|
RemoveCache(slotId);
|
||||||
|
if (string.Equals(slotId, ResolveCurrentSlotId(), StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
curState = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnManualShown(string slotId)
|
||||||
|
{
|
||||||
|
_activeSlotId = slotId;
|
||||||
OnAdShow();
|
OnAdShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +294,9 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnManualShowFailed(DirichletError error)
|
private void OnManualShowFailed(string slotId, DirichletError error)
|
||||||
{
|
{
|
||||||
|
RemoveCache(slotId);
|
||||||
OnError(error);
|
OnError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,13 +305,49 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
OnRewardVerify(args);
|
OnRewardVerify(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnManualClosed()
|
private void OnManualClosed(string slotId)
|
||||||
{
|
{
|
||||||
_loadedAd?.Destroy();
|
RemoveCache(slotId);
|
||||||
_loadedAd = null;
|
|
||||||
OnAdClose();
|
OnAdClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RemoveCache(string slotId)
|
||||||
|
{
|
||||||
|
var cache = GetCache(slotId);
|
||||||
|
if (cache == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DestroyCachedAd(cache);
|
||||||
|
_slotCaches.Remove(slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DestroyCachedAd(RewardedSlotCache cache)
|
||||||
|
{
|
||||||
|
if (cache?.Ad == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cache.ExpireHandler?.Kill();
|
||||||
|
cache.ExpireHandler = null;
|
||||||
|
cache.Ad.Destroy();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TapADN] Rewarded Destroy failed: {exception.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
cache.Ad = null;
|
||||||
|
cache.Loading = false;
|
||||||
|
cache.LoadedUnix = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CompleteRewardedClose()
|
private void CompleteRewardedClose()
|
||||||
{
|
{
|
||||||
if (_showSettled)
|
if (_showSettled)
|
||||||
@@ -228,4 +362,22 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
|
|||||||
adListener.OnRewardVerify(_rewardVerified, TapadnAdController.CurrentOptions?.RewardAmount ?? 1, TapadnAdController.CurrentOptions?.RewardName ?? string.Empty);
|
adListener.OnRewardVerify(_rewardVerified, TapadnAdController.CurrentOptions?.RewardAmount ?? 1, TapadnAdController.CurrentOptions?.RewardName ?? string.Empty);
|
||||||
adListener.OnAdClose();
|
adListener.OnAdClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string NormalizeScenario(string scenario)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(scenario) ? "__default__" : scenario.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long GetNowUnixSeconds()
|
||||||
|
{
|
||||||
|
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class RewardedSlotCache
|
||||||
|
{
|
||||||
|
public DirichletRewardVideoAd Ad;
|
||||||
|
public bool Loading;
|
||||||
|
public long LoadedUnix;
|
||||||
|
public AdTimeHandler ExpireHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Runtime.ADAggregator;
|
using Runtime.ADAggregator;
|
||||||
|
|
||||||
public static class TapadnCommercialization
|
public static class TapadnCommercialization
|
||||||
@@ -31,4 +32,31 @@ public static class TapadnCommercialization
|
|||||||
config.BaseSplashAdKeyValue = new AdKeyValue { key = "splash", value = splashSlotId };
|
config.BaseSplashAdKeyValue = new AdKeyValue { key = "splash", value = splashSlotId };
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetRewardedSceneSlots(ADConfig config, IDictionary<string, string> sceneSlotIds)
|
||||||
|
{
|
||||||
|
if (config == null || sceneSlotIds == null || sceneSlotIds.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.CommonKeyValues == null)
|
||||||
|
{
|
||||||
|
config.CommonKeyValues = new List<AdKeyValue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in sceneSlotIds)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(entry.Key) || string.IsNullOrWhiteSpace(entry.Value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.CommonKeyValues.Add(new AdKeyValue
|
||||||
|
{
|
||||||
|
key = TapadnControllerOptions.RewardedSceneSlotPrefix + entry.Key.Trim(),
|
||||||
|
value = entry.Value.Trim()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ public sealed class TapadnControllerOptions
|
|||||||
public const string RewardedMaxLoadAttemptsKey = "tapadn.rewarded_max_load_attempts";
|
public const string RewardedMaxLoadAttemptsKey = "tapadn.rewarded_max_load_attempts";
|
||||||
public const string RewardedLoadRetryDelayMsKey = "tapadn.rewarded_load_retry_delay_ms";
|
public const string RewardedLoadRetryDelayMsKey = "tapadn.rewarded_load_retry_delay_ms";
|
||||||
public const string RewardedShowTimeoutMsKey = "tapadn.rewarded_show_timeout_ms";
|
public const string RewardedShowTimeoutMsKey = "tapadn.rewarded_show_timeout_ms";
|
||||||
|
public const string RewardedSceneSlotPrefix = "tapadn.rewarded_scene_slot.";
|
||||||
|
public const string RewardedSceneSlotsKey = "tapadn.rewarded_scene_slots";
|
||||||
|
public const string RewardedSceneSlotsJsonKey = "tapadn.rewarded_scene_slots_json";
|
||||||
|
public const string RewardedCacheMaxAgeSecondsKey = "tapadn.rewarded_cache_max_age_seconds";
|
||||||
public const string RewardNameKey = "tapadn.reward_name";
|
public const string RewardNameKey = "tapadn.reward_name";
|
||||||
public const string RewardAmountKey = "tapadn.reward_amount";
|
public const string RewardAmountKey = "tapadn.reward_amount";
|
||||||
public const string InterstitialAutoLoadKey = "tapadn.interstitial_auto_load";
|
public const string InterstitialAutoLoadKey = "tapadn.interstitial_auto_load";
|
||||||
@@ -64,6 +68,8 @@ public sealed class TapadnControllerOptions
|
|||||||
public int RewardedMaxLoadAttempts { get; set; } = 1;
|
public int RewardedMaxLoadAttempts { get; set; } = 1;
|
||||||
public int RewardedLoadRetryDelayMs { get; set; } = 500;
|
public int RewardedLoadRetryDelayMs { get; set; } = 500;
|
||||||
public int RewardedShowTimeoutMs { get; set; } = 20000;
|
public int RewardedShowTimeoutMs { get; set; } = 20000;
|
||||||
|
public int RewardedCacheMaxAgeSeconds { get; set; } = 600;
|
||||||
|
public Dictionary<string, string> RewardedSceneSlotIds { get; private set; } = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
public string RewardName { get; set; } = "reward";
|
public string RewardName { get; set; } = "reward";
|
||||||
public int RewardAmount { get; set; } = 1;
|
public int RewardAmount { get; set; } = 1;
|
||||||
public bool InterstitialAutoLoad { get; set; } = false;
|
public bool InterstitialAutoLoad { get; set; } = false;
|
||||||
@@ -205,6 +211,11 @@ public sealed class TapadnControllerOptions
|
|||||||
RewardedMaxLoadAttempts = incoming.RewardedMaxLoadAttempts;
|
RewardedMaxLoadAttempts = incoming.RewardedMaxLoadAttempts;
|
||||||
RewardedLoadRetryDelayMs = incoming.RewardedLoadRetryDelayMs;
|
RewardedLoadRetryDelayMs = incoming.RewardedLoadRetryDelayMs;
|
||||||
RewardedShowTimeoutMs = incoming.RewardedShowTimeoutMs;
|
RewardedShowTimeoutMs = incoming.RewardedShowTimeoutMs;
|
||||||
|
RewardedCacheMaxAgeSeconds = incoming.RewardedCacheMaxAgeSeconds;
|
||||||
|
if (incoming.RewardedSceneSlotIds != null && incoming.RewardedSceneSlotIds.Count > 0)
|
||||||
|
{
|
||||||
|
RewardedSceneSlotIds = CloneSceneSlotMap(incoming.RewardedSceneSlotIds);
|
||||||
|
}
|
||||||
RewardName = incoming.RewardName ?? RewardName;
|
RewardName = incoming.RewardName ?? RewardName;
|
||||||
RewardAmount = incoming.RewardAmount;
|
RewardAmount = incoming.RewardAmount;
|
||||||
InterstitialAutoLoad = incoming.InterstitialAutoLoad;
|
InterstitialAutoLoad = incoming.InterstitialAutoLoad;
|
||||||
@@ -266,6 +277,8 @@ public sealed class TapadnControllerOptions
|
|||||||
RewardedMaxLoadAttempts = GetInt(map, RewardedMaxLoadAttemptsKey) ?? RewardedMaxLoadAttempts;
|
RewardedMaxLoadAttempts = GetInt(map, RewardedMaxLoadAttemptsKey) ?? RewardedMaxLoadAttempts;
|
||||||
RewardedLoadRetryDelayMs = GetInt(map, RewardedLoadRetryDelayMsKey) ?? RewardedLoadRetryDelayMs;
|
RewardedLoadRetryDelayMs = GetInt(map, RewardedLoadRetryDelayMsKey) ?? RewardedLoadRetryDelayMs;
|
||||||
RewardedShowTimeoutMs = GetInt(map, RewardedShowTimeoutMsKey) ?? RewardedShowTimeoutMs;
|
RewardedShowTimeoutMs = GetInt(map, RewardedShowTimeoutMsKey) ?? RewardedShowTimeoutMs;
|
||||||
|
RewardedCacheMaxAgeSeconds = Math.Max(0, GetInt(map, RewardedCacheMaxAgeSecondsKey) ?? RewardedCacheMaxAgeSeconds);
|
||||||
|
ApplyRewardedSceneSlots(map);
|
||||||
RewardName = GetString(map, RewardNameKey) ?? RewardName;
|
RewardName = GetString(map, RewardNameKey) ?? RewardName;
|
||||||
RewardAmount = GetInt(map, RewardAmountKey) ?? RewardAmount;
|
RewardAmount = GetInt(map, RewardAmountKey) ?? RewardAmount;
|
||||||
InterstitialAutoLoad = GetBool(map, InterstitialAutoLoadKey) ?? InterstitialAutoLoad;
|
InterstitialAutoLoad = GetBool(map, InterstitialAutoLoadKey) ?? InterstitialAutoLoad;
|
||||||
@@ -286,6 +299,116 @@ public sealed class TapadnControllerOptions
|
|||||||
ExpressHeight = GetInt(map, ExpressHeightKey) ?? ExpressHeight;
|
ExpressHeight = GetInt(map, ExpressHeightKey) ?? ExpressHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ResolveRewardedSlotId(string defaultSlotId, string scenario)
|
||||||
|
{
|
||||||
|
var normalizedScenario = NormalizeScenario(scenario);
|
||||||
|
if (RewardedSceneSlotIds != null &&
|
||||||
|
RewardedSceneSlotIds.TryGetValue(normalizedScenario, out var mappedSlotId) &&
|
||||||
|
TapadnAdRequestFactory.TryParseSlotId(mappedSlotId, out _))
|
||||||
|
{
|
||||||
|
return mappedSlotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultSlotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyRewardedSceneSlots(IDictionary<string, string> map)
|
||||||
|
{
|
||||||
|
foreach (var entry in map)
|
||||||
|
{
|
||||||
|
if (entry.Key == null || !entry.Key.StartsWith(RewardedSceneSlotPrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var scene = entry.Key.Substring(RewardedSceneSlotPrefix.Length);
|
||||||
|
AddRewardedSceneSlot(scene, entry.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseSceneSlotPairs(GetString(map, RewardedSceneSlotsKey), AddRewardedSceneSlot);
|
||||||
|
ParseSceneSlotJson(GetString(map, RewardedSceneSlotsJsonKey), AddRewardedSceneSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddRewardedSceneSlot(string scene, string slotId)
|
||||||
|
{
|
||||||
|
scene = NormalizeScenario(scene);
|
||||||
|
if (string.IsNullOrWhiteSpace(slotId) || !TapadnAdRequestFactory.TryParseSlotId(slotId.Trim(), out _))
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogWarning($"[TapADN] Ignore invalid rewarded scene slot. scene={scene}, slot={slotId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RewardedSceneSlotIds[scene] = slotId.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParseSceneSlotPairs(string value, Action<string, string> add)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value) || add == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pairs = value.Split(new[] { ',', ';', '\n', '\r', '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var pair in pairs)
|
||||||
|
{
|
||||||
|
var separatorIndex = pair.IndexOf('=');
|
||||||
|
if (separatorIndex < 0)
|
||||||
|
{
|
||||||
|
separatorIndex = pair.IndexOf(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separatorIndex <= 0 || separatorIndex >= pair.Length - 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(pair.Substring(0, separatorIndex), pair.Substring(separatorIndex + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ParseSceneSlotJson(string json, Action<string, string> add)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json) || add == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parsed = JsonUtility.FromJson<TapadnSceneSlotMapConfig>(json);
|
||||||
|
if (parsed?.Mappings == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mapping in parsed.Mappings)
|
||||||
|
{
|
||||||
|
if (mapping == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(mapping.Scene, mapping.SlotId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogWarning($"[TapADN] Parse rewarded scene slot JSON failed: {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> CloneSceneSlotMap(Dictionary<string, string> source)
|
||||||
|
{
|
||||||
|
return source == null
|
||||||
|
? new Dictionary<string, string>(StringComparer.Ordinal)
|
||||||
|
: new Dictionary<string, string>(source, StringComparer.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeScenario(string scenario)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(scenario) ? "__default__" : scenario.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(IDictionary<string, string> map, params string[] keys)
|
private static string GetString(IDictionary<string, string> map, params string[] keys)
|
||||||
{
|
{
|
||||||
foreach (var key in keys)
|
foreach (var key in keys)
|
||||||
@@ -383,4 +506,17 @@ public sealed class TapadnControllerOptions
|
|||||||
|
|
||||||
return value.ToString();
|
return value.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
private sealed class TapadnSceneSlotMapConfig
|
||||||
|
{
|
||||||
|
public List<TapadnSceneSlotMapping> Mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
private sealed class TapadnSceneSlotMapping
|
||||||
|
{
|
||||||
|
public string Scene;
|
||||||
|
public string SlotId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
}
|
}
|
||||||
|
|
||||||
curState = 1;
|
curState = 1;
|
||||||
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.Interaction, AdScene);
|
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.Interaction, AdScene, Key);
|
||||||
_adNative.LoadInterstitialAd(
|
_adNative.LoadInterstitialAd(
|
||||||
TapadnAdRequestFactory.BuildInterstitial(Key, TapadnAdController.CurrentOptions),
|
TapadnAdRequestFactory.BuildInterstitial(Key, TapadnAdController.CurrentOptions),
|
||||||
ad =>
|
ad =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Interaction, AdScene, true);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Interaction, AdScene, true, Key);
|
||||||
_loadedAd?.Destroy();
|
_loadedAd?.Destroy();
|
||||||
_loadedAd = ad;
|
_loadedAd = ad;
|
||||||
_loadedAd.Shown += OnManualShown;
|
_loadedAd.Shown += OnManualShown;
|
||||||
@@ -73,7 +73,7 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
},
|
},
|
||||||
error =>
|
error =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Interaction, AdScene, false);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Interaction, AdScene, false, Key);
|
||||||
curState = 0;
|
curState = 0;
|
||||||
Debug.LogError($"[TapADN] Interstitial load failed. code={error.Code}, message={error.Message}");
|
Debug.LogError($"[TapADN] Interstitial load failed. code={error.Code}, message={error.Message}");
|
||||||
});
|
});
|
||||||
@@ -106,7 +106,7 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
}
|
}
|
||||||
|
|
||||||
_showSettled = true;
|
_showSettled = true;
|
||||||
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.Interaction, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.Interaction, AdScene, Key);
|
||||||
curState = 0;
|
curState = 0;
|
||||||
Debug.LogError($"[TapADN] Interstitial show failed. code={error?.Code}, message={error?.Message}");
|
Debug.LogError($"[TapADN] Interstitial show failed. code={error?.Code}, message={error?.Message}");
|
||||||
adListener.OnShowError();
|
adListener.OnShowError();
|
||||||
@@ -114,7 +114,7 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
|
|
||||||
public void OnAdShow()
|
public void OnAdShow()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Interaction, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Interaction, AdScene, Key);
|
||||||
NotifyShowStarted();
|
NotifyShowStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +136,13 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
|
|
||||||
public override void OnPlayRequestStarted()
|
public override void OnPlayRequestStarted()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.Interaction, AdScene, !UseAutoLoad() && IsReadly());
|
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.Interaction, AdScene, !UseAutoLoad() && IsReadly(), Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterAdScenario(string scenario)
|
public override void EnterAdScenario(string scenario)
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.Interaction, scenario, Key);
|
AdScene = string.IsNullOrWhiteSpace(scenario) ? "__default__" : scenario.Trim();
|
||||||
|
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.Interaction, AdScene, Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UseAutoLoad()
|
private bool UseAutoLoad()
|
||||||
@@ -151,7 +152,7 @@ public sealed class TapadnInteractionPlayer : ADPlayer, IDirichletInterstitialAu
|
|||||||
|
|
||||||
private void OnManualShown()
|
private void OnManualShown()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Interaction, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Interaction, AdScene, Key);
|
||||||
NotifyShowStarted();
|
NotifyShowStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
private static TapadnSmartLoadConfig _runtimeConfig;
|
private static TapadnSmartLoadConfig _runtimeConfig;
|
||||||
private static Dictionary<string, TapadnSmartLoadSceneState> _states = new Dictionary<string, TapadnSmartLoadSceneState>(StringComparer.Ordinal);
|
private static Dictionary<string, TapadnSmartLoadSceneState> _states = new Dictionary<string, TapadnSmartLoadSceneState>(StringComparer.Ordinal);
|
||||||
private static Dictionary<string, TapadnSmartLoadPolicyItem> _policies = new Dictionary<string, TapadnSmartLoadPolicyItem>(StringComparer.Ordinal);
|
private static Dictionary<string, TapadnSmartLoadPolicyItem> _policies = new Dictionary<string, TapadnSmartLoadPolicyItem>(StringComparer.Ordinal);
|
||||||
private static Dictionary<int, TapadnSmartLoadCacheState> _cacheStates = new Dictionary<int, TapadnSmartLoadCacheState>();
|
private static Dictionary<string, TapadnSmartLoadCacheState> _cacheStates = new Dictionary<string, TapadnSmartLoadCacheState>(StringComparer.Ordinal);
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
private static bool _enabled;
|
private static bool _enabled;
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
_enabled = options?.SmartPreloadEnabled ?? false;
|
_enabled = options?.SmartPreloadEnabled ?? false;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
_states = new Dictionary<string, TapadnSmartLoadSceneState>(StringComparer.Ordinal);
|
_states = new Dictionary<string, TapadnSmartLoadSceneState>(StringComparer.Ordinal);
|
||||||
_cacheStates = new Dictionary<int, TapadnSmartLoadCacheState>();
|
_cacheStates = new Dictionary<string, TapadnSmartLoadCacheState>(StringComparer.Ordinal);
|
||||||
LoadStates();
|
LoadStates();
|
||||||
EnsureDefaultPolicies(_runtimeConfig);
|
EnsureDefaultPolicies(_runtimeConfig);
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,10 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
record.ShowRequestCount = Math.Max(0, record.ShowRequestCount);
|
record.ShowRequestCount = Math.Max(0, record.ShowRequestCount);
|
||||||
SaveStates();
|
SaveStates();
|
||||||
|
|
||||||
TryPreload(adType, normalizedScenario);
|
TryPreload(adType, normalizedScenario, _slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnPlayRequestStarted(AD_Type adType, string scenario, bool cacheReadyAtRequest)
|
public static void OnPlayRequestStarted(AD_Type adType, string scenario, bool cacheReadyAtRequest, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
@@ -152,49 +152,49 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
record.LastUpdatedUnix = GetNowUnixSeconds();
|
record.LastUpdatedUnix = GetNowUnixSeconds();
|
||||||
if (cacheReadyAtRequest)
|
if (cacheReadyAtRequest)
|
||||||
{
|
{
|
||||||
MarkImmediateHit(adType, normalizedScenario);
|
MarkImmediateHit(adType, normalizedScenario, slotId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MarkCacheExpiredIfStale(adType);
|
MarkCacheExpiredIfStale(adType, slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveStates();
|
SaveStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnLoadRequested(AD_Type adType, string scenario)
|
public static void OnLoadRequested(AD_Type adType, string scenario, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrepareSmartLoadRequest(adType, scenario);
|
PrepareSmartLoadRequest(adType, scenario, slotId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnLoadStarted(AD_Type adType, string scenario)
|
public static void OnLoadStarted(AD_Type adType, string scenario, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BeginLoadRequest(adType, scenario);
|
BeginLoadRequest(adType, scenario, slotId);
|
||||||
SaveStates();
|
SaveStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnLoadResult(AD_Type adType, string scenario, bool success)
|
public static void OnLoadResult(AD_Type adType, string scenario, bool success, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompleteLoadRequest(adType, scenario, success);
|
CompleteLoadRequest(adType, scenario, success, slotId);
|
||||||
SaveStates();
|
SaveStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnShowStart(AD_Type adType, string scenario)
|
public static void OnShowStart(AD_Type adType, string scenario, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
@@ -204,11 +204,11 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
var record = GetOrCreateState(adType, NormalizeScenario(scenario));
|
var record = GetOrCreateState(adType, NormalizeScenario(scenario));
|
||||||
record.ShowStartCount = Math.Max(0, record.ShowStartCount) + 1;
|
record.ShowStartCount = Math.Max(0, record.ShowStartCount) + 1;
|
||||||
record.LastUpdatedUnix = GetNowUnixSeconds();
|
record.LastUpdatedUnix = GetNowUnixSeconds();
|
||||||
MarkCacheConsumed(adType, scenario);
|
MarkCacheConsumed(adType, scenario, slotId);
|
||||||
SaveStates();
|
SaveStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnShowError(AD_Type adType, string scenario)
|
public static void OnShowError(AD_Type adType, string scenario, string slotId = null)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
@@ -218,11 +218,11 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
var record = GetOrCreateState(adType, NormalizeScenario(scenario));
|
var record = GetOrCreateState(adType, NormalizeScenario(scenario));
|
||||||
record.ShowFailureCount = Math.Max(0, record.ShowFailureCount) + 1;
|
record.ShowFailureCount = Math.Max(0, record.ShowFailureCount) + 1;
|
||||||
record.LastUpdatedUnix = GetNowUnixSeconds();
|
record.LastUpdatedUnix = GetNowUnixSeconds();
|
||||||
MarkCacheShowFailed(adType, scenario);
|
MarkCacheShowFailed(adType, scenario, slotId);
|
||||||
SaveStates();
|
SaveStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TryPreload(AD_Type adType, string scenario)
|
private static void TryPreload(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
if (!_initialized || !_enabled)
|
if (!_initialized || !_enabled)
|
||||||
{
|
{
|
||||||
@@ -257,11 +257,11 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkCacheExpiredIfStale(adType);
|
MarkCacheExpiredIfStale(adType, slotId);
|
||||||
OnLoadRequested(adType, scenario);
|
OnLoadRequested(adType, scenario, slotId);
|
||||||
ADManager.Instance.LoadAD(adType);
|
ADManager.Instance.LoadAD(adType);
|
||||||
var smartLoadStarted = HasPendingSmartLoadForScene(adType, scenario);
|
var smartLoadStarted = HasPendingSmartLoadForScene(adType, scenario, slotId);
|
||||||
ClearPreparedLoadIfNotStarted(adType);
|
ClearPreparedLoadIfNotStarted(adType, slotId);
|
||||||
if (!smartLoadStarted)
|
if (!smartLoadStarted)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -302,9 +302,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
return Mathf.Lerp(policy.BaseProbability, observedRate, trust);
|
return Mathf.Lerp(policy.BaseProbability, observedRate, trust);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrepareSmartLoadRequest(AD_Type adType, string scenario)
|
private static void PrepareSmartLoadRequest(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var state = GetOrCreateCacheState(adType);
|
var state = GetOrCreateCacheState(adType, slotId);
|
||||||
if (state.PendingSmartLoad)
|
if (state.PendingSmartLoad)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -316,9 +316,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
state.PreparedRequestUnix = GetNowUnixSeconds();
|
state.PreparedRequestUnix = GetNowUnixSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BeginLoadRequest(AD_Type adType, string scenario)
|
private static void BeginLoadRequest(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var state = GetOrCreateCacheState(adType);
|
var state = GetOrCreateCacheState(adType, slotId);
|
||||||
var now = GetNowUnixSeconds();
|
var now = GetNowUnixSeconds();
|
||||||
if (state.PreparedSmartLoad)
|
if (state.PreparedSmartLoad)
|
||||||
{
|
{
|
||||||
@@ -346,9 +346,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
state.PreparedRequestUnix = 0;
|
state.PreparedRequestUnix = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ClearPreparedLoadIfNotStarted(AD_Type adType)
|
private static void ClearPreparedLoadIfNotStarted(AD_Type adType, string slotId)
|
||||||
{
|
{
|
||||||
var state = GetOrCreateCacheState(adType);
|
var state = GetOrCreateCacheState(adType, slotId);
|
||||||
if (state.PendingSmartLoad)
|
if (state.PendingSmartLoad)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -360,16 +360,16 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
state.PreparedRequestUnix = 0;
|
state.PreparedRequestUnix = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasPendingSmartLoadForScene(AD_Type adType, string scenario)
|
private static bool HasPendingSmartLoadForScene(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var state = GetOrCreateCacheState(adType);
|
var state = GetOrCreateCacheState(adType, slotId);
|
||||||
return state.PendingSmartLoad &&
|
return state.PendingSmartLoad &&
|
||||||
string.Equals(NormalizeScenario(state.PendingOriginScene), NormalizeScenario(scenario), StringComparison.Ordinal);
|
string.Equals(NormalizeScenario(state.PendingOriginScene), NormalizeScenario(scenario), StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CompleteLoadRequest(AD_Type adType, string scenario, bool success)
|
private static void CompleteLoadRequest(AD_Type adType, string scenario, bool success, string slotId)
|
||||||
{
|
{
|
||||||
var cacheState = GetOrCreateCacheState(adType);
|
var cacheState = GetOrCreateCacheState(adType, slotId);
|
||||||
var normalizedScenario = NormalizeScenario(scenario);
|
var normalizedScenario = NormalizeScenario(scenario);
|
||||||
var originScene = cacheState.PendingSmartLoad ? NormalizeScenario(cacheState.PendingOriginScene) : normalizedScenario;
|
var originScene = cacheState.PendingSmartLoad ? NormalizeScenario(cacheState.PendingOriginScene) : normalizedScenario;
|
||||||
var originRecord = GetOrCreateState(adType, originScene);
|
var originRecord = GetOrCreateState(adType, originScene);
|
||||||
@@ -408,23 +408,23 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
cacheState.PendingRequestUnix = 0;
|
cacheState.PendingRequestUnix = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MarkImmediateHit(AD_Type adType, string scenario)
|
private static void MarkImmediateHit(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var consumedScene = NormalizeScenario(scenario);
|
var consumedScene = NormalizeScenario(scenario);
|
||||||
var currentSceneRecord = GetOrCreateState(adType, consumedScene);
|
var currentSceneRecord = GetOrCreateState(adType, consumedScene);
|
||||||
currentSceneRecord.ImmediateHitCount = Math.Max(0, currentSceneRecord.ImmediateHitCount) + 1;
|
currentSceneRecord.ImmediateHitCount = Math.Max(0, currentSceneRecord.ImmediateHitCount) + 1;
|
||||||
currentSceneRecord.LastUpdatedUnix = GetNowUnixSeconds();
|
currentSceneRecord.LastUpdatedUnix = GetNowUnixSeconds();
|
||||||
|
|
||||||
var cacheState = GetOrCreateCacheState(adType);
|
var cacheState = GetOrCreateCacheState(adType, slotId);
|
||||||
if (!cacheState.HasReadyCache)
|
if (!cacheState.HasReadyCache)
|
||||||
{
|
{
|
||||||
currentSceneRecord.UnattributedCacheHitCount = Math.Max(0, currentSceneRecord.UnattributedCacheHitCount) + 1;
|
currentSceneRecord.UnattributedCacheHitCount = Math.Max(0, currentSceneRecord.UnattributedCacheHitCount) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MarkCacheConsumed(AD_Type adType, string scenario)
|
private static void MarkCacheConsumed(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var cacheState = GetOrCreateCacheState(adType);
|
var cacheState = GetOrCreateCacheState(adType, slotId);
|
||||||
if (!cacheState.HasReadyCache || cacheState.Consumed)
|
if (!cacheState.HasReadyCache || cacheState.Consumed)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -458,9 +458,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
ClearReadyCache(cacheState);
|
ClearReadyCache(cacheState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MarkCacheShowFailed(AD_Type adType, string scenario)
|
private static void MarkCacheShowFailed(AD_Type adType, string scenario, string slotId)
|
||||||
{
|
{
|
||||||
var cacheState = GetOrCreateCacheState(adType);
|
var cacheState = GetOrCreateCacheState(adType, slotId);
|
||||||
if (!cacheState.HasReadyCache)
|
if (!cacheState.HasReadyCache)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -479,9 +479,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
ClearReadyCache(cacheState);
|
ClearReadyCache(cacheState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MarkCacheExpiredIfStale(AD_Type adType)
|
private static void MarkCacheExpiredIfStale(AD_Type adType, string slotId)
|
||||||
{
|
{
|
||||||
var cacheState = GetOrCreateCacheState(adType);
|
var cacheState = GetOrCreateCacheState(adType, slotId);
|
||||||
if (!cacheState.HasReadyCache)
|
if (!cacheState.HasReadyCache)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -502,9 +502,9 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
ClearReadyCache(cacheState);
|
ClearReadyCache(cacheState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TapadnSmartLoadCacheState GetOrCreateCacheState(AD_Type adType)
|
private static TapadnSmartLoadCacheState GetOrCreateCacheState(AD_Type adType, string slotId)
|
||||||
{
|
{
|
||||||
var key = (int)adType;
|
var key = ComposeCacheKey(adType, slotId);
|
||||||
if (_cacheStates.TryGetValue(key, out var state) && state != null)
|
if (_cacheStates.TryGetValue(key, out var state) && state != null)
|
||||||
{
|
{
|
||||||
return state;
|
return state;
|
||||||
@@ -879,6 +879,16 @@ public static class TapadnSmartLoadOrchestrator
|
|||||||
return ((int)adType) + "|" + NormalizeScenario(scenario);
|
return ((int)adType) + "|" + NormalizeScenario(scenario);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ComposeCacheKey(AD_Type adType, string slotId)
|
||||||
|
{
|
||||||
|
return ((int)adType) + "|" + NormalizeSlotId(slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeSlotId(string slotId)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(slotId) ? "__default_slot__" : slotId.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
private static string NormalizeScenario(string scenario)
|
private static string NormalizeScenario(string scenario)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(scenario))
|
if (string.IsNullOrWhiteSpace(scenario))
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
curState = 1;
|
curState = 1;
|
||||||
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.Splash, AdScene);
|
TapadnSmartLoadOrchestrator.OnLoadStarted(AD_Type.Splash, AdScene, Key);
|
||||||
_adNative.LoadSplashAd(
|
_adNative.LoadSplashAd(
|
||||||
TapadnAdRequestFactory.BuildSplash(Key, TapadnAdController.CurrentOptions),
|
TapadnAdRequestFactory.BuildSplash(Key, TapadnAdController.CurrentOptions),
|
||||||
ad =>
|
ad =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Splash, AdScene, true);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Splash, AdScene, true, Key);
|
||||||
_loadedAd?.Destroy();
|
_loadedAd?.Destroy();
|
||||||
_loadedAd = ad;
|
_loadedAd = ad;
|
||||||
_loadedAd.Shown += OnManualShown;
|
_loadedAd.Shown += OnManualShown;
|
||||||
@@ -73,7 +73,7 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
},
|
},
|
||||||
error =>
|
error =>
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Splash, AdScene, false);
|
TapadnSmartLoadOrchestrator.OnLoadResult(AD_Type.Splash, AdScene, false, Key);
|
||||||
curState = 0;
|
curState = 0;
|
||||||
Debug.LogError($"[TapADN] Splash load failed. code={error.Code}, message={error.Message}");
|
Debug.LogError($"[TapADN] Splash load failed. code={error.Code}, message={error.Message}");
|
||||||
});
|
});
|
||||||
@@ -106,7 +106,7 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
_showSettled = true;
|
_showSettled = true;
|
||||||
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.Splash, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowError(AD_Type.Splash, AdScene, Key);
|
||||||
curState = 0;
|
curState = 0;
|
||||||
Debug.LogError($"[TapADN] Splash show failed. code={error?.Code}, message={error?.Message}");
|
Debug.LogError($"[TapADN] Splash show failed. code={error?.Code}, message={error?.Message}");
|
||||||
adListener.OnShowError();
|
adListener.OnShowError();
|
||||||
@@ -114,7 +114,7 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
|
|
||||||
public void OnAdShow()
|
public void OnAdShow()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Splash, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Splash, AdScene, Key);
|
||||||
NotifyShowStarted();
|
NotifyShowStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +136,13 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
|
|
||||||
public override void OnPlayRequestStarted()
|
public override void OnPlayRequestStarted()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.Splash, AdScene, !UseAutoLoad() && IsReadly());
|
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.Splash, AdScene, !UseAutoLoad() && IsReadly(), Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterAdScenario(string scenario)
|
public override void EnterAdScenario(string scenario)
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.Splash, scenario, Key);
|
AdScene = string.IsNullOrWhiteSpace(scenario) ? "__default__" : scenario.Trim();
|
||||||
|
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.Splash, AdScene, Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UseAutoLoad()
|
private bool UseAutoLoad()
|
||||||
@@ -151,7 +152,7 @@ public sealed class TapadnSplashPlayer : ADPlayer, IDirichletSplashAutoAdListene
|
|||||||
|
|
||||||
private void OnManualShown()
|
private void OnManualShown()
|
||||||
{
|
{
|
||||||
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Splash, AdScene);
|
TapadnSmartLoadOrchestrator.OnShowStart(AD_Type.Splash, AdScene, Key);
|
||||||
NotifyShowStarted();
|
NotifyShowStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
"name": "com.commercialization.tapadn",
|
"name": "com.commercialization.tapadn",
|
||||||
"displayName": "Commercialization.tapadn",
|
"displayName": "Commercialization.tapadn",
|
||||||
"description": "TapADN / Dirichlet mediation implementation for CC-Framework.Commercialization.",
|
"description": "TapADN / Dirichlet mediation implementation for CC-Framework.Commercialization.",
|
||||||
"version": "1.0.0",
|
"version": "1.0.4",
|
||||||
"unity": "2021.1",
|
"unity": "2022.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn"
|
"url": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn.git"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "foldcc",
|
"name": "foldcc",
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"url": "https://gitee.com/foldcc"
|
"url": "https://gitee.com/foldcc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.14"
|
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.15"
|
||||||
},
|
},
|
||||||
"samples": [
|
"samples": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ iOS runtime 桥接负责:
|
|||||||
发布包入口是 `Assets/package.json`,其中 `com.foldcc.cc-framework.commercialization` 依赖保持为远程 Git URL:
|
发布包入口是 `Assets/package.json`,其中 `com.foldcc.cc-framework.commercialization` 依赖保持为远程 Git URL:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.14"
|
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.15"
|
||||||
```
|
```
|
||||||
|
|
||||||
当前仓库自身作为 Unity 验证工程时,可以在 `Packages/manifest.json` 使用本地 `file:` 引用:
|
当前仓库自身作为 Unity 验证工程时,可以在 `Packages/manifest.json` 使用本地 `file:` 引用:
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
m_EditorVersion: 2022.3.62f3c1
|
m_EditorVersion: 2022.3.62f2c1
|
||||||
m_EditorVersionWithRevision: 2022.3.62f3c1 (1623fc0bbb97)
|
m_EditorVersionWithRevision: 2022.3.62f2c1 (92e6e6be66dc)
|
||||||
|
|||||||
54
README.md
54
README.md
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.14",
|
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.15",
|
||||||
"com.commercialization.tapadn": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn.git#1.0.0"
|
"com.commercialization.tapadn": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn.git?path=/Assets#1.0.4"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -73,6 +73,10 @@ ADManager.Instance.Init(callback, userId, adConfig, new TapadnAdController());
|
|||||||
* `tapadn.rewarded_max_load_attempts`
|
* `tapadn.rewarded_max_load_attempts`
|
||||||
* `tapadn.rewarded_load_retry_delay_ms`
|
* `tapadn.rewarded_load_retry_delay_ms`
|
||||||
* `tapadn.rewarded_show_timeout_ms`
|
* `tapadn.rewarded_show_timeout_ms`
|
||||||
|
* `tapadn.rewarded_scene_slot.<scene_id>`(激励视频场景广告位映射,值为对应 SpaceId)
|
||||||
|
* `tapadn.rewarded_scene_slots`(激励视频场景广告位批量映射,格式 `scene_a=10001,scene_b=10002`)
|
||||||
|
* `tapadn.rewarded_scene_slots_json`(激励视频场景广告位 JSON,格式见下方)
|
||||||
|
* `tapadn.rewarded_cache_max_age_seconds`(可选本地缓存年龄上限;默认 `600` 秒,设为 `0` 表示只使用 SDK `IsValid` 判断)
|
||||||
* `tapadn.interstitial_auto_load`
|
* `tapadn.interstitial_auto_load`
|
||||||
* `tapadn.interstitial_prewarm_on_init`
|
* `tapadn.interstitial_prewarm_on_init`
|
||||||
* `tapadn.interstitial_max_load_attempts`
|
* `tapadn.interstitial_max_load_attempts`
|
||||||
@@ -92,6 +96,52 @@ ADManager.Instance.Init(callback, userId, adConfig, new TapadnAdController());
|
|||||||
|
|
||||||
默认激励、插屏、开屏都使用手动 load/show;如无特殊策略验证需求,不建议开启 auto-ad。若要做 auto-ad AB 测试,再将对应 `*_auto_load` 设为 `true`。
|
默认激励、插屏、开屏都使用手动 load/show;如无特殊策略验证需求,不建议开启 auto-ad。若要做 auto-ad AB 测试,再将对应 `*_auto_load` 设为 `true`。
|
||||||
|
|
||||||
|
### 激励视频场景广告位
|
||||||
|
|
||||||
|
激励视频支持按游戏场景路由不同 TapADN SpaceId。项目层继续调用 `ADManager.EnterAdScenario(AD_Type.AwardVideo, sceneId)` 和 `ADManager.AsyncPlayAD(AD_Type.AwardVideo, sceneId, callback)`;TapADN adapter 会按 `sceneId` 查表:
|
||||||
|
|
||||||
|
* 命中 `tapadn.rewarded_scene_slot.<scene_id>` 或批量配置时,使用该场景 SpaceId。
|
||||||
|
* 未传场景、场景为空、场景未配置、配置的 SpaceId 非法时,回退到 `BaseAwardAdKeyValue.value` 默认激励视频广告位。
|
||||||
|
* 手动 load/show 模式下,缓存按 SpaceId 隔离;A 场景加载的激励视频不会被 B 场景误认为 ready。
|
||||||
|
|
||||||
|
单项配置示例:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
adConfig.CommonKeyValues.Add(new AdKeyValue
|
||||||
|
{
|
||||||
|
key = "tapadn.rewarded_scene_slot.level_clear",
|
||||||
|
value = "200101"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
批量字符串配置示例:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
adConfig.CommonKeyValues.Add(new AdKeyValue
|
||||||
|
{
|
||||||
|
key = "tapadn.rewarded_scene_slots",
|
||||||
|
value = "level_clear=200101,daily_bonus=200102"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON 配置示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Mappings": [
|
||||||
|
{ "Scene": "level_clear", "SlotId": "200101" },
|
||||||
|
{ "Scene": "daily_bonus", "SlotId": "200102" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
生命周期策略按官方文档保持保守:
|
||||||
|
|
||||||
|
* `DirichletAdNative` 仍由每个 TapADN player 统一持有,不在每个场景重复创建。
|
||||||
|
* 手动加载返回的 `DirichletRewardVideoAd` 按 SpaceId 缓存;展示关闭、展示失败、SDK `IsValid == false` 或超过 `tapadn.rewarded_cache_max_age_seconds` 后销毁。
|
||||||
|
* 官方文档没有给出固定过期秒数;本模块默认 10 分钟未消费主动销毁,同时每次 ready/show 前仍调用 SDK `IsValid`。
|
||||||
|
* Android auto-ad 仍交给官方 `ShowRewardVideoAutoAd` / `PreLoad` 的 native 缓存管理;iOS/Editor fallback 仍是 load 成功后立即 show,不承诺 native 缓存语义。
|
||||||
|
|
||||||
### 智能预加载(实验)
|
### 智能预加载(实验)
|
||||||
|
|
||||||
默认会按“场景进入次数 + 场景播放请求次数”维护一个小样本统计:
|
默认会按“场景进入次数 + 场景播放请求次数”维护一个小样本统计:
|
||||||
|
|||||||
Reference in New Issue
Block a user