4 Commits
1.0.4 ... 1.0.8

27 changed files with 322 additions and 77 deletions

View File

@@ -1,3 +1,34 @@
# [1.0.8]
### 修复
* 修复 Editor 广告位诊断在编译期触发 `CS0165` 未赋值变量错误的问题。
# [1.0.7]
### 修复
* 接入 `CC-Framework.Commercialization` 的 Editor 诊断接口Unity Editor 模拟点击广告时也会输出 TapADN 当前解析出的广告位 ID。
# [1.0.6]
### 修复
* 兼容 `CommonKeyValues` 中直接使用业务场景名作为 key、SpaceId 作为 value 的激励视频广告位配置,避免只识别 `tapadn.rewarded_scene_slot.<scene_id>` 时回退到默认激励广告位。
* 激励视频进入场景、加载和播放请求会输出当前解析到的 SpaceId 及来源,便于 Editor Console 和样例调试面板确认实际使用的广告位。
# [1.0.5]
### 调整
* Android native 聚合 SDK AAR 升级到 `4.2.7.3`
* Android Pangle 依赖升级到 `7.6.1.2`GDT 依赖升级到 `4.690.1560`,改由 Gradle 后处理注入 Maven 依赖。
* 移除旧本地 Pangle/GDT AAR避免与 Maven 依赖重复类。
### 文档
* 新增 `SDK_MAINTENANCE.md`记录官方源码改动清单、封装层职责、SDK 升级步骤和发布流程。
# [1.0.4] # [1.0.4]
### 新增 ### 新增

View File

@@ -23,6 +23,8 @@ namespace Dirichlet.Mediation.Editor
private const string DIRICHLET_DEPS_END = "// Dirichlet Mediation Dependencies End"; private const string DIRICHLET_DEPS_END = "// Dirichlet Mediation Dependencies End";
private const string DIRICHLET_REPOS_START = "// Dirichlet Mediation Repositories Start"; private const string DIRICHLET_REPOS_START = "// Dirichlet Mediation Repositories Start";
private const string DIRICHLET_REPOS_END = "// Dirichlet Mediation Repositories End"; private const string DIRICHLET_REPOS_END = "// Dirichlet Mediation Repositories End";
private const string PangleSdkVersion = "7.6.1.2";
private const string GdtSdkVersion = "4.690.1560";
public int callbackOrder => 100; // Run after EDM4U (which uses lower values) public int callbackOrder => 100; // Run after EDM4U (which uses lower values)
@@ -157,6 +159,16 @@ namespace Dirichlet.Mediation.Editor
} }
// Maven dependencies (required for SDK functionality) // Maven dependencies (required for SDK functionality)
if (enableCsj)
{
depsBlock.AppendLine($" implementation('com.pangle.cn:ads-sdk-pro:{PangleSdkVersion}') {{");
depsBlock.AppendLine(" exclude group: 'com.android.support'");
depsBlock.AppendLine(" }");
}
if (enableGdt)
{
depsBlock.AppendLine($" implementation 'com.qq.e.union:union:{GdtSdkVersion}'");
}
depsBlock.AppendLine(" implementation 'com.android.support:recyclerview-v7:28.0.0'"); depsBlock.AppendLine(" implementation 'com.android.support:recyclerview-v7:28.0.0'");
depsBlock.AppendLine(" implementation 'com.github.bumptech.glide:glide:4.9.0'"); depsBlock.AppendLine(" implementation 'com.github.bumptech.glide:glide:4.9.0'");
depsBlock.AppendLine(" implementation 'com.android.support:support-v4:28.0.0'"); depsBlock.AppendLine(" implementation 'com.android.support:support-v4:28.0.0'");

View File

@@ -1,33 +0,0 @@
fileFormatVersion: 2
guid: 90b3b17e0788494398662e729c344ee2
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,33 +0,0 @@
fileFormatVersion: 2
guid: 930136242e574a2b89110e6a25e49065
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

115
Assets/SDK_MAINTENANCE.md Normal file
View File

@@ -0,0 +1,115 @@
# TapADN SDK 封装维护说明
本文记录 `Commercialization.tapadn` 对官方 Dirichlet/TapADN 聚合 SDK 的封装、改动和升级注意事项。维护或升级 SDK 时先读本文,再改文件。
## 当前 SDK 版本
官方链接:
* 资源下载页https://ssp.dirichlet.cn/docs/resource-download/
* 聚合 Unity 接入文档https://ssp.dirichlet.cn/docs/dirichlet-mediation-sdk/dirichlet-mediation-sdk-guide-unity/
* 聚合 Android 接入文档https://ssp.dirichlet.cn/docs/dirichlet-mediation-sdk/dirichlet-mediation-sdk-guide-android/
| 范围 | 当前版本 | 来源 | 说明 |
| --- | --- | --- | --- |
| Unity 聚合 SDK | 4.2.5.0 | 官方 `dirichlet_mediation_unity_4.2.5.0.unitypackage` | 官方资源页当前仍只提供 Unity 4.2.5.0。 |
| Android 聚合 native AAR | 4.2.7.3 | 官方 `dirichlet_ad_mediation_4.2.7.3.zip` | 已单独升级 Android native 侧。 |
| Android Pangle | 7.6.1.2 | 官方 Android 聚合接入文档 | 通过 Gradle 后处理注入 Maven 依赖。 |
| Android GDT | 4.690.1560 | 官方 Android 聚合接入文档 | 通过 Gradle 后处理注入 Maven 依赖。 |
| iOS 聚合 SDK Pod | 4.2.0.1 | 官方 iOS 聚合版本 | 默认值在 `DirichletMediationIOSPostProcessor`,可用环境变量覆盖。 |
## 模块结构
| 路径 | 归属 | 维护说明 |
| --- | --- | --- |
| `Assets/DirichletMediation` | 官方 Unity SDK 基础层 | 不再视为纯官方源码,部分文件已有本地改动。 |
| `Assets/Plugins/Android/DirichletMediation` | 官方 Android Unity bridge + native AAR | Java bridge 当前与官方 Unity 包一致AAR 已升级到 Android native 4.2.7.3。 |
| `Assets/Plugins/Android/libs` | Android 本地依赖 | 保留 `iadsdk-release-2.3.102.110.aar`Pangle/GDT 不再放本地 AAR改由 Maven 注入。 |
| `Assets/Tapadn_Adapter` | 本模块封装层 | 对接 `CC-Framework.Commercialization`,不要让业务层直接调用官方 SDK。 |
| `Assets/Samples~` | 可选调试样例 | 不是官方 sample是本模块验证 `ADManager` 流程的样例。 |
## 官方源码改动清单
以下文件来自官方 Unity SDK但本仓库已经修改过。升级官方 Unity SDK 时不能直接覆盖,必须三方合并:
| 文件 | 本地改动目的 |
| --- | --- |
| `Assets/DirichletMediation/Runtime/DirichletAdTypes.cs` | 补齐 Unity 侧 ad handle、auto-ad fallback、事件会话保活、`IsValid` / `Destroy` 包装等桥接行为。 |
| `Assets/DirichletMediation/Runtime/DirichletMediationSdk.cs` | 增强 Android/iOS/noop bridge、Unity 线程派发、iOS load/init callback receiver 和平台兼容逻辑。 |
| `Assets/DirichletMediation/Editor/DirichletGradlePostProcessor.cs` | 改为适配 Unity 导出的 Gradle 工程注入仓库、support/glide/okhttp、Pangle/GDT Maven 依赖,避免本地 AAR 重复类。 |
| `Assets/DirichletMediation/Editor/DirichletMediationIOSPostProcessor.cs` | 自动生成 Podfile处理 UnityFramework target、framework/header search paths、SKAdNetwork、ATT、GDT 动态 framework 嵌入和 CocoaPods 异常兜底。 |
以下官方文件当前与官方 Unity 4.2.5.0 包一致,升级时可优先直接替换后验证:
| 文件 | 说明 |
| --- | --- |
| `Assets/DirichletMediation/Editor/DirichletMediationDependencies.xml` | EDM4U 依赖声明。 |
| `Assets/Plugins/Android/DirichletMediation/src/main/java/com/dirichlet/unity/DirichletUnityBridge.java` | Android Java bridge。 |
| `Assets/Plugins/Android/AndroidManifest.xml` | 官方基础 Manifest。 |
| `Assets/Plugins/Android/proguard-user.txt` | 当前为空文件。 |
## 封装层做了什么
`Tapadn_Adapter` 的目标是让业务项目只面对 `ADManager` / `ADConfig` / `AD_Type`
1. `TapadnAdController``ADConfig``CommonKeyValues` 解析媒体 ID、MediaKey、广告位、渠道、debug、权限、预加载和展示超时配置。
2. `TapadnCommercialization` 提供创建 controller、初始化 `ADManager`、创建默认 `ADConfig`、批量写入激励场景广告位映射的便捷入口。
3. `TapadnAdRequestFactory` 统一构建 `DirichletAdRequest`,保证 SpaceId 是正整数,并注入 UserId、奖励名、奖励数量、展示尺寸。
4. `TapadnAwardVideoPlayer` 对接激励视频。手动 load/show 模式下,按 SpaceId 隔离缓存;展示关闭、展示失败、`IsValid == false`、或默认 600 秒未消费都会销毁缓存。
5. `TapadnInteractionPlayer` 对接插屏;`TapadnSplashPlayer` 对接开屏。两者保持单默认广告位语义。
6. `TapadnSmartLoadOrchestrator` 维护场景学习数据和智能预加载归因。当前是保守策略:默认不开启;开启后先观察用户点击广告的概率,达到阈值才自动预加载。
## 场景广告位规则
激励视频支持游戏场景映射不同 SpaceId
| 配置 key | 示例 |
| --- | --- |
| `tapadn.rewarded_scene_slot.<scene_id>` | `tapadn.rewarded_scene_slot.level_clear = 200101` |
| `tapadn.rewarded_scene_slots` | `level_clear=200101,daily_bonus=200102` |
| `tapadn.rewarded_scene_slots_json` | `{ "Mappings": [ { "Scene": "level_clear", "SlotId": "200101" } ] }` |
回退规则:
1. 未传场景、场景为空、场景未配置、配置 SpaceId 非法时,使用 `BaseAwardAdKeyValue.value`
2. 如果两个场景配置到同一个 SpaceId它们共享同一个广告位缓存。
3. 如果 A 场景 SpaceId 已加载但没展示,用户去 B 场景展示 B SpaceIdA 缓存不会被 B 消费A 会等回到 A 时复用,或超时/失效后销毁。
## Android 升级步骤
1. 查官方资源页和聚合 Android 发布记录,确认最新 Android 聚合版本、Pangle 版本、GDT 版本。
2. 下载 `dirichlet_ad_mediation_<version>.zip`,校验官方 MD5。
3. 替换 `Assets/Plugins/Android/DirichletMediation/libs/DirichletAD_*_<version>.aar`
4. 检查官方 Android 接入文档中的 Maven 依赖,更新 `DirichletGradlePostProcessor` 里的 `PangleSdkVersion``GdtSdkVersion`
5. 不要同时保留 Pangle/GDT 本地 AAR 和 Maven 依赖,否则容易出现 duplicate classes。当前策略是 Pangle/GDT 走 Maven。
6. 搜索旧版本号,更新 `GLOBAL_DESIGN.md``README.md``CHANGELOG.md``Assets/package.json`
7. 至少执行 `dotnet build Commercialization.tapadn.sln --no-restore``git diff --check`
8. Android 真机构建仍需在消费项目里跑项目自带构建流程验证 Manifest merge、Gradle dependency resolution 和广告展示回调。
## Unity SDK 升级步骤
1. 下载官方新的 `dirichlet_mediation_unity_<version>.unitypackage` 并校验 MD5。
2. 解包到临时目录,对比 `Assets/DirichletMediation``Assets/Plugins/Android`
3. 对“官方源码改动清单”里的 4 个文件做三方合并,不允许直接覆盖。
4. 官方 sample 不进入默认包;如需要保留调试能力,继续放到 `Samples~`
5. 检查 Android Java bridge API 是否和当前 C# bridge 匹配,重点是 load/show/destroy/isValid/auto-ad callback。
6. 检查 iOS Pod 名称和版本是否变化,同步 `DirichletMediationIOSPostProcessor` 的默认版本和 search path 规则。
7. 重新验证 Android/iOS editor compile真机展示验证至少覆盖初始化、激励 load/show/close/reward、插屏、开屏、无填充失败。
## 发布步骤
包根是 `Assets/package.json`,消费者应使用:
```json
"com.commercialization.tapadn": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn.git?path=/Assets#<version>"
```
发布命令:
```bash
git subtree split --prefix=Assets --branch upm
git tag <version>
git push origin master upm <version>
```
注意:当前版本 tag 打在完整仓库 `master` 上,因此消费者必须带 `?path=/Assets`

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dcf571baef764df0aa6789990d47c36a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -162,6 +162,7 @@ public sealed class TapadnIAAAdDebugSampleGui : MonoBehaviour
GUILayout.Label($"Last EventLog: {_lastEventLog}", _textStyle); GUILayout.Label($"Last EventLog: {_lastEventLog}", _textStyle);
GUILayout.Label($"Last SDK Version: {DisplayValue(TapadnAdController.LastSdkVersion)}", _textStyle); GUILayout.Label($"Last SDK Version: {DisplayValue(TapadnAdController.LastSdkVersion)}", _textStyle);
GUILayout.Label($"Last Init Error: {DisplayValue(TapadnAdController.LastInitError)}", _textStyle); GUILayout.Label($"Last Init Error: {DisplayValue(TapadnAdController.LastInitError)}", _textStyle);
GUILayout.Label($"Rewarded Selected SpaceId: {GetResolvedRewardedSlotForDisplay(rewardedScenario)}", _textStyle);
} }
else else
{ {
@@ -250,6 +251,7 @@ public sealed class TapadnIAAAdDebugSampleGui : MonoBehaviour
if (EnsureInitialized(label)) if (EnsureInitialized(label))
{ {
LogRewardedResolvedSlot(adType, scenario, "Enter scenario");
ADManager.Instance.EnterAdScenario(adType, scenario); ADManager.Instance.EnterAdScenario(adType, scenario);
AppendLog($"Enter scenario requested. type={adType}, scenario={scenario}"); AppendLog($"Enter scenario requested. type={adType}, scenario={scenario}");
} }
@@ -278,6 +280,7 @@ public sealed class TapadnIAAAdDebugSampleGui : MonoBehaviour
if (EnsureInitialized(label)) if (EnsureInitialized(label))
{ {
LogRewardedResolvedSlot(adType, scenario, "AsyncPlayAD");
ADManager.Instance.AsyncPlayAD(adType, scenario, result => ADManager.Instance.AsyncPlayAD(adType, scenario, result =>
{ {
AppendLog($"{adType} callback: {result}"); AppendLog($"{adType} callback: {result}");
@@ -424,6 +427,30 @@ public sealed class TapadnIAAAdDebugSampleGui : MonoBehaviour
} }
AppendLog($"Options => mediaId={options.MediaId}, channel={options.Channel}, sub={options.SubChannel}, debug={options.Debug}, rewardAuto={options.RewardedAutoLoad}, interAuto={options.InterstitialAutoLoad}, splashAuto={options.SplashAutoLoad}"); AppendLog($"Options => mediaId={options.MediaId}, channel={options.Channel}, sub={options.SubChannel}, debug={options.Debug}, rewardAuto={options.RewardedAutoLoad}, interAuto={options.InterstitialAutoLoad}, splashAuto={options.SplashAutoLoad}");
AppendLog($"Rewarded selected slot => {GetResolvedRewardedSlotForDisplay(rewardedScenario)}, configuredSceneSlots={options.RewardedSceneSlotIds?.Count ?? 0}");
}
private void LogRewardedResolvedSlot(AD_Type adType, string scenario, string actionName)
{
if (adType != AD_Type.AwardVideo)
{
return;
}
AppendLog($"{actionName} rewarded slot => {GetResolvedRewardedSlotForDisplay(scenario)}");
}
private string GetResolvedRewardedSlotForDisplay(string scenario)
{
var defaultSlotId = adConfig?.BaseAwardAdKeyValue?.value;
var options = TapadnAdController.CurrentOptions;
if (options == null)
{
return $"{DisplayValue(defaultSlotId)} (source=default, scenario={DisplayValue(scenario)})";
}
var slotId = options.ResolveRewardedSlotId(defaultSlotId, scenario, out var mapped);
return $"{DisplayValue(slotId)} (source={(mapped ? "scene" : "default")}, scenario={DisplayValue(scenario)})";
} }
private void OnRewardedBefore(string placementId, string scenario) private void OnRewardedBefore(string placementId, string scenario)

View File

@@ -3,7 +3,7 @@ using Dirichlet.Mediation;
using Runtime.ADAggregator; using Runtime.ADAggregator;
using UnityEngine; using UnityEngine;
public sealed class TapadnAdController : IAdController public sealed class TapadnAdController : IAdController, IAdEditorDiagnostics
{ {
public static TapadnControllerOptions CurrentOptions { get; private set; } public static TapadnControllerOptions CurrentOptions { get; private set; }
public static string LastSdkVersion { get; private set; } public static string LastSdkVersion { get; private set; }
@@ -73,4 +73,41 @@ public sealed class TapadnAdController : IAdController
{ {
_maskAction?.Invoke(isOpen); _maskAction?.Invoke(isOpen);
} }
public void LogEditorAdPlacement(ADConfig adConfig, AD_Type adType, string adScene, string action, object[] args)
{
var options = TapadnControllerOptions.Resolve(adConfig, args);
var normalizedScene = string.IsNullOrWhiteSpace(adScene) ? "__default__" : adScene.Trim();
var slotSource = "default";
var slotId = ResolveEditorSlotId(adConfig, options, adType, normalizedScene, out slotSource);
Debug.Log($"[TapADN] Editor ad {action}. type={adType}, scene={normalizedScene}, slot={DisplayEditorValue(slotId)}, source={slotSource}");
}
private static string ResolveEditorSlotId(ADConfig adConfig, TapadnControllerOptions options, AD_Type adType, string adScene, out string slotSource)
{
slotSource = "default";
switch (adType)
{
case AD_Type.AwardVideo:
var defaultRewardedSlotId = adConfig?.BaseAwardAdKeyValue?.value;
var mapped = false;
var rewardedSlotId = options == null
? defaultRewardedSlotId
: options.ResolveRewardedSlotId(defaultRewardedSlotId, adScene, out mapped);
slotSource = mapped ? "scene" : "default";
return rewardedSlotId;
case AD_Type.Interaction:
return adConfig?.BaseInteractionAdKeyValue?.value;
case AD_Type.Splash:
return adConfig?.BaseSplashAdKeyValue?.value;
default:
slotSource = "unsupported";
return null;
}
}
private static string DisplayEditorValue(string value)
{
return string.IsNullOrWhiteSpace(value) ? "<empty>" : value.Trim();
}
} }

View File

@@ -62,7 +62,8 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
public override void LoadAD() public override void LoadAD()
{ {
var slotId = ResolveCurrentSlotId(); var slotId = ResolveCurrentSlotId(out var mapped);
Debug.Log($"[TapADN] Rewarded load requested. scene={NormalizeScenario(AdScene)}, slot={slotId}, source={GetSlotSource(mapped)}, auto={UseAutoLoad()}");
if (!TapadnAdRequestFactory.TryParseSlotId(slotId, out _)) if (!TapadnAdRequestFactory.TryParseSlotId(slotId, out _))
{ {
Debug.LogError($"[TapADN] Invalid rewarded slot id: {slotId}"); Debug.LogError($"[TapADN] Invalid rewarded slot id: {slotId}");
@@ -128,9 +129,10 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
_showSettled = false; _showSettled = false;
_rewardCloseSettleHandler?.Kill(); _rewardCloseSettleHandler?.Kill();
_rewardCloseSettleHandler = null; _rewardCloseSettleHandler = null;
_activeSlotId = ResolveCurrentSlotId(); _activeSlotId = ResolveCurrentSlotId(out var mapped);
Key = _activeSlotId; Key = _activeSlotId;
curState = 0; curState = 0;
Debug.Log($"[TapADN] Rewarded show requested. scene={NormalizeScenario(AdScene)}, slot={_activeSlotId}, source={GetSlotSource(mapped)}, auto={UseAutoLoad()}");
if (UseAutoLoad()) if (UseAutoLoad())
{ {
@@ -203,25 +205,43 @@ public sealed class TapadnAwardVideoPlayer : ADPlayer, IDirichletRewardVideoAuto
public override void OnPlayRequestStarted() public override void OnPlayRequestStarted()
{ {
var slotId = ResolveCurrentSlotId(); var slotId = ResolveCurrentSlotId(out var mapped);
Key = slotId; Key = slotId;
Debug.Log($"[TapADN] Rewarded play request. scene={NormalizeScenario(AdScene)}, slot={slotId}, source={GetSlotSource(mapped)}, auto={UseAutoLoad()}");
TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.AwardVideo, AdScene, !UseAutoLoad() && IsReadly(), slotId); TapadnSmartLoadOrchestrator.OnPlayRequestStarted(AD_Type.AwardVideo, AdScene, !UseAutoLoad() && IsReadly(), slotId);
} }
public override void EnterAdScenario(string scenario) public override void EnterAdScenario(string scenario)
{ {
AdScene = NormalizeScenario(scenario); AdScene = NormalizeScenario(scenario);
var slotId = ResolveCurrentSlotId(); var slotId = ResolveCurrentSlotId(out var mapped);
Key = slotId; Key = slotId;
Debug.Log($"[TapADN] Rewarded enter scene. scene={AdScene}, slot={slotId}, source={GetSlotSource(mapped)}");
TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.AwardVideo, AdScene, slotId); TapadnSmartLoadOrchestrator.OnEnterAdScenario(AD_Type.AwardVideo, AdScene, slotId);
} }
private string ResolveCurrentSlotId() private string ResolveCurrentSlotId()
{ {
var slotId = TapadnAdController.CurrentOptions?.ResolveRewardedSlotId(_defaultSlotId, AdScene) ?? _defaultSlotId; return ResolveCurrentSlotId(out _);
}
private string ResolveCurrentSlotId(out bool mapped)
{
if (TapadnAdController.CurrentOptions == null)
{
mapped = false;
return string.IsNullOrWhiteSpace(_defaultSlotId) ? _defaultSlotId : _defaultSlotId.Trim();
}
var slotId = TapadnAdController.CurrentOptions.ResolveRewardedSlotId(_defaultSlotId, AdScene, out mapped);
return string.IsNullOrWhiteSpace(slotId) ? _defaultSlotId : slotId.Trim(); return string.IsNullOrWhiteSpace(slotId) ? _defaultSlotId : slotId.Trim();
} }
private static string GetSlotSource(bool mapped)
{
return mapped ? "scene" : "default";
}
private bool UseAutoLoad() private bool UseAutoLoad()
{ {
return TapadnAdController.CurrentOptions?.RewardedAutoLoad ?? true; return TapadnAdController.CurrentOptions?.RewardedAutoLoad ?? true;

View File

@@ -9,6 +9,8 @@ using UnityEngine;
public sealed class TapadnControllerOptions public sealed class TapadnControllerOptions
{ {
private const string TapadnKeyPrefix = "tapadn.";
public const string MediaNameKey = "tapadn.media_name"; public const string MediaNameKey = "tapadn.media_name";
public const string MediaIdKey = "tapadn.media_id"; public const string MediaIdKey = "tapadn.media_id";
public const string MediaKeyKey = "tapadn.media_key"; public const string MediaKeyKey = "tapadn.media_key";
@@ -300,20 +302,29 @@ public sealed class TapadnControllerOptions
} }
public string ResolveRewardedSlotId(string defaultSlotId, string scenario) public string ResolveRewardedSlotId(string defaultSlotId, string scenario)
{
return ResolveRewardedSlotId(defaultSlotId, scenario, out _);
}
public string ResolveRewardedSlotId(string defaultSlotId, string scenario, out bool mapped)
{ {
var normalizedScenario = NormalizeScenario(scenario); var normalizedScenario = NormalizeScenario(scenario);
if (RewardedSceneSlotIds != null && if (RewardedSceneSlotIds != null &&
RewardedSceneSlotIds.TryGetValue(normalizedScenario, out var mappedSlotId) && RewardedSceneSlotIds.TryGetValue(normalizedScenario, out var mappedSlotId) &&
TapadnAdRequestFactory.TryParseSlotId(mappedSlotId, out _)) TapadnAdRequestFactory.TryParseSlotId(mappedSlotId, out _))
{ {
mapped = true;
return mappedSlotId; return mappedSlotId;
} }
mapped = false;
return defaultSlotId; return defaultSlotId;
} }
private void ApplyRewardedSceneSlots(IDictionary<string, string> map) private void ApplyRewardedSceneSlots(IDictionary<string, string> map)
{ {
ApplyLegacyRewardedSceneSlots(map);
foreach (var entry in map) foreach (var entry in map)
{ {
if (entry.Key == null || !entry.Key.StartsWith(RewardedSceneSlotPrefix, StringComparison.OrdinalIgnoreCase)) if (entry.Key == null || !entry.Key.StartsWith(RewardedSceneSlotPrefix, StringComparison.OrdinalIgnoreCase))
@@ -329,6 +340,19 @@ public sealed class TapadnControllerOptions
ParseSceneSlotJson(GetString(map, RewardedSceneSlotsJsonKey), AddRewardedSceneSlot); ParseSceneSlotJson(GetString(map, RewardedSceneSlotsJsonKey), AddRewardedSceneSlot);
} }
private void ApplyLegacyRewardedSceneSlots(IDictionary<string, string> map)
{
foreach (var entry in map)
{
if (!IsLegacyRewardedSceneSlotEntry(entry.Key, entry.Value))
{
continue;
}
AddRewardedSceneSlot(entry.Key, entry.Value);
}
}
private void AddRewardedSceneSlot(string scene, string slotId) private void AddRewardedSceneSlot(string scene, string slotId)
{ {
scene = NormalizeScenario(scene); scene = NormalizeScenario(scene);
@@ -341,6 +365,30 @@ public sealed class TapadnControllerOptions
RewardedSceneSlotIds[scene] = slotId.Trim(); RewardedSceneSlotIds[scene] = slotId.Trim();
} }
private static bool IsLegacyRewardedSceneSlotEntry(string key, string value)
{
var normalizedKey = key?.Trim();
if (string.IsNullOrWhiteSpace(normalizedKey) ||
string.IsNullOrWhiteSpace(value) ||
normalizedKey.StartsWith(TapadnKeyPrefix, StringComparison.OrdinalIgnoreCase))
{
return false;
}
switch (normalizedKey.ToLowerInvariant())
{
case "media_id":
case "media_name":
case "media_key":
case "channel":
case "sub_channel":
case "debug":
return false;
}
return TapadnAdRequestFactory.TryParseSlotId(value.Trim(), out _);
}
private static void ParseSceneSlotPairs(string value, Action<string, string> add) private static void ParseSceneSlotPairs(string value, Action<string, string> add)
{ {
if (string.IsNullOrWhiteSpace(value) || add == null) if (string.IsNullOrWhiteSpace(value) || add == null)

View File

@@ -2,7 +2,7 @@
"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.4", "version": "1.0.8",
"unity": "2022.3", "unity": "2022.3",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@@ -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.15" "com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.16"
}, },
"samples": [ "samples": [
{ {

View File

@@ -12,7 +12,7 @@
## 目录 ## 目录
* `Assets/DirichletMediation`: 官方聚合 Unity SDK `4.2.5.0`,已删除官方 Sample。 * `Assets/DirichletMediation`: 官方聚合 Unity SDK 基础层 `4.2.5.0`,已删除官方 SampleAndroid native AAR 单独升级到 `4.2.7.3`
* `Assets/Plugins/Android`: 官方 Android AAR、Manifest、ProGuard、本地微信 OpenSDK AAR。 * `Assets/Plugins/Android`: 官方 Android AAR、Manifest、ProGuard、本地微信 OpenSDK AAR。
* `Assets/Plugins/iOS`: iOS Objective-C++ bridge。 * `Assets/Plugins/iOS`: iOS Objective-C++ bridge。
* `Assets/Tapadn_Adapter/Runtime/Scripts`: 商业化抽象层适配。 * `Assets/Tapadn_Adapter/Runtime/Scripts`: 商业化抽象层适配。

View File

@@ -9,7 +9,7 @@
```json ```json
{ {
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.15", "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?path=/Assets#1.0.4" "com.commercialization.tapadn": "http://private.lightyears.ltd:18650/foldcc/Commercialization.tapadn.git?path=/Assets#1.0.5"
} }
``` ```
@@ -100,9 +100,10 @@ ADManager.Instance.Init(callback, userId, adConfig, new TapadnAdController());
激励视频支持按游戏场景路由不同 TapADN SpaceId。项目层继续调用 `ADManager.EnterAdScenario(AD_Type.AwardVideo, sceneId)``ADManager.AsyncPlayAD(AD_Type.AwardVideo, sceneId, callback)`TapADN adapter 会按 `sceneId` 查表: 激励视频支持按游戏场景路由不同 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。 * 命中 `tapadn.rewarded_scene_slot.<scene_id>`、批量配置,或 `CommonKeyValues``scene_id=SpaceId` 的兼容配置时,使用该场景 SpaceId。
* 未传场景、场景为空、场景未配置、配置的 SpaceId 非法时,回退到 `BaseAwardAdKeyValue.value` 默认激励视频广告位。 * 未传场景、场景为空、场景未配置、配置的 SpaceId 非法时,回退到 `BaseAwardAdKeyValue.value` 默认激励视频广告位。
* 手动 load/show 模式下,缓存按 SpaceId 隔离A 场景加载的激励视频不会被 B 场景误认为 ready。 * 手动 load/show 模式下,缓存按 SpaceId 隔离A 场景加载的激励视频不会被 B 场景误认为 ready。
* Editor/样例调试时,进入场景、加载和播放请求会在 Console 输出当前解析到的 SpaceId 及来源,格式类似 `slot=200101, source=scene`
单项配置示例: 单项配置示例:
@@ -114,6 +115,16 @@ adConfig.CommonKeyValues.Add(new AdKeyValue
}); });
``` ```
兼容已有业务配置示例:
```csharp
adConfig.CommonKeyValues.Add(new AdKeyValue
{
key = "PlantUnlock",
value = "200101"
});
```
批量字符串配置示例: 批量字符串配置示例:
```csharp ```csharp
@@ -188,11 +199,14 @@ JSON 配置示例:
包内包含官方 `DirichletMediation` SDK、Android AAR、iOS bridge、EDM4U 依赖声明和构建后处理。 包内包含官方 `DirichletMediation` SDK、Android AAR、iOS bridge、EDM4U 依赖声明和构建后处理。
维护和升级说明见 `SDK_MAINTENANCE.md`其中记录了官方源码改动清单、Android/iOS/Unity SDK 升级步骤和发布流程。
构建后处理会自动补齐: 构建后处理会自动补齐:
* TapADN 所需权限。 * TapADN 所需权限。
* TapADN `TapADFileProvider``tapad_ad_file_path.xml` * TapADN `TapADFileProvider``tapad_ad_file_path.xml`
* 微信 OpenSDK `WXEntryActivity``queries`、本地 `wechat-sdk-android-6.8.34.aar` * 微信 OpenSDK `WXEntryActivity``queries`、本地 `wechat-sdk-android-6.8.34.aar`
* Pangle `com.pangle.cn:ads-sdk-pro:7.6.1.2` 和 GDT `com.qq.e.union:union:4.690.1560` Maven 依赖。
* `android.useAndroidX=true``android.enableJetifier=true` * `android.useAndroidX=true``android.enableJetifier=true`
包内不默认暴露可视化编辑面板;调试样例通过 `Samples~` 作为可选导入内容。 包内不默认暴露可视化编辑面板;调试样例通过 `Samples~` 作为可选导入内容。