# Commercialization.tapadn 全局设计

## 目标

本模块把 TapADN / Dirichlet 聚合广告 SDK 接到 `CC-Framework.Commercialization` 抽象层后面，让业务项目继续只关心 `ADManager` 和 `ADConfig`。

当前实现对齐 `Commercialization.topon` 的分层：

* `CC-Framework.Commercialization`: `ADManager`、`IAdController`、`ADPlayer` 抽象。
* `Commercialization.tapadn`: 平台 controller、广告播放器、构建自动化。
* `DirichletMediation`: 官方 SDK 和平台桥。

## 目录

* `Assets/DirichletMediation`: 官方聚合 Unity SDK 基础层 `4.2.5.0`，已删除官方 Sample；Android native AAR 单独升级到 `4.2.7.3`。
* `Assets/Plugins/Android`: 官方 Android AAR、Manifest、ProGuard、本地微信 OpenSDK AAR。
* `Assets/Plugins/iOS`: iOS Objective-C++ bridge。
* `Assets/Tapadn_Adapter/Runtime/Scripts`: 商业化抽象层适配。
* `Assets/Tapadn_Adapter/Editor`: Android 构建后处理和依赖声明。
* `Assets/DirichletMediation/Editor`: Android Gradle 后处理与 iOS Xcode/CocoaPods 后处理。
* `Assets/Samples~`: 可选调试样例预留，不随主包自动进入业务项目。

## Runtime 设计

`TapadnAdController` 实现 `IAdController`：

* 从 `ADConfig` 和可选 `args` 解析 `TapadnControllerOptions`。
* 构造 `DirichletAdConfig` 并调用 `DirichletSdk.Init`。
* 根据 `AD_Type` 创建 `TapadnAwardVideoPlayer`、`TapadnInteractionPlayer`、`TapadnSplashPlayer`。

`TapadnCommercialization` 是便捷入口：

* `CreateController()` 隐藏 controller 创建细节。
* `InitADManager(...)` 由模块负责创建 controller 并交给 `ADManager`。
* `CreateConfig(...)` 用代码生成临时 `ADConfig`，适合游戏项目不想维护 TapADN SDK 细节时使用。

## 广告播放器

默认方案：优先手动 load/show，避免把 `ADManager.AsyncAdPlayer` 的时序语义与 TapADN auto 语义混用。

原因：

* TapADN auto-ad 是官方 Android 场景下的“加载 + 展示合并”调用，不等价于完整场景分发与实时 readiness 能力。
* `ADManager.AsyncAdPlayer` 先做 `IsReadly` 决策，未 ready 则调用 `LoadAD`，ready 后再 `ShowAD`，所以手动模式下生命周期和失败收口更稳定。

备选方案：手动 load/show。

* 已通过 `tapadn.rewarded_auto_load=false` 等 key 保留。
* 手动模式保存 SDK 返回的 ad handle，并在 `Closed` 时销毁。

不确定点：

* 官方文档说明 auto-ad 目前主要是 Android 能力。本模块在 iOS 对激励、插屏、开屏 auto API 做 load-then-show 兼容 fallback，但不承诺 Android native auto 缓存语义；真正 iOS 出包前需要用 TapADN iOS 账号和广告位做真机验证。
* `AD_Type` 抽象层没有 Banner 类型，所以本轮没有将 TapADN Banner 暴露到 `ADManager`。如果抽象层后续新增 Banner，可以直接复用官方 `ShowBannerAutoAd`。

## 配置设计

基础字段复用 `ADConfig`：

* `Id`: MediaId。
* `Key`: MediaKey。
* `Key2`: MediaName。
* `BaseAwardAdKeyValue.value`: 激励视频 SpaceId。
* `BaseInteractionAdKeyValue.value`: 插屏 SpaceId。
* `BaseSplashAdKeyValue.value`: 开屏 SpaceId。

高级配置通过 `CommonKeyValues` 或字典传入，使用 `tapadn.*` 前缀，避免和 TopOn 现有 key 冲突。

## Android 构建设计

保留官方 `DirichletGradlePostProcessor`，它负责 Dirichlet AAR 和 Maven 依赖注入。

新增 `TapadnBuildAndroidProcess`，只负责本模块集成层额外需求：

* TapADN Manifest 权限补齐。
* `com.tapsdk.tapad.internal.TapADFileProvider` 和 `@xml/tapad_ad_file_path`。
* 微信 OpenSDK 的 `com.tencent.mm` queries 与 `.wxapi.WXEntryActivity`。
* AndroidX / Jetifier 开关。

方案选择记录：

* 方案 A：只放 `WXDependencies.xml`，依赖宿主 EDM4U 下载微信 SDK。风险是业务项目没有 EDM4U 或未 resolve 时构建失败。
* 方案 B：只放本地微信 AAR。风险是宿主 EDM4U 依赖图不可见。
* 当前选择：本地 AAR + `WXDependencies.xml` 同时保留。这样最接近 TopOn 当前工程，也能覆盖无 EDM4U 的构建场景。

## iOS 构建设计

保留 iOS Objective-C++ bridge，并通过 `DirichletMediationIOSPostProcessor` 自动生成 Xcode 集成：

* Pod 默认版本为官方 iOS 聚合 SDK `4.2.0.1`，可用 `DIRICHLET_IOS_SDK_VERSION` 或 `EditorPrefs("Dirichlet.iOS.SDKVersion")` 覆盖。
* 所有 Dirichlet iOS Pods 放到 Unity Framework target，保持 bridge、SDK、adapter 在同一二进制上下文。
* 自动补 `SKAdNetworkItems`、`NSUserTrackingUsageDescription`、`AppTrackingTransparency.framework`、`AdSupport.framework`。
* 构建后执行 `pod install`，缺失 CocoaPods 或 Pod 源异常时让 Unity 构建失败，避免产出半配置 Xcode 工程。
* GDT 动态 framework 在 `pod install` 后嵌入 App target。

iOS runtime 桥接负责：

* 初始化时传入 `MediaId`、`MediaKey`、`MediaName`、`gameChannel`、`shakeEnabled`、`allowIDFAAccess`、`aTags`。
* `RequestPermissionIfNecessary()` 在 iOS 14+ 请求 ATT。
* 加载/展示激励、插屏、开屏；展示前检查 root view controller 和 `isReady`，失败时回传 `show_error`。

## 编辑器可见性

本模块不提供默认可见面板。构建自动化通过 `IPostGenerateGradleAndroidProject` 静默执行；调试能力放入 `Samples~`，由业务项目显式导入。

若后续需要可视化配置面板，应使用宏包裹菜单入口，例如 `COMMERCIALIZATION_TAPADN_DEBUG_MENU`，默认不在业务项目菜单里出现。

## UPM 与本机验证约定

发布包入口是 `Assets/package.json`，其中 `com.foldcc.cc-framework.commercialization` 依赖保持为远程 Git URL：

```json
"com.foldcc.cc-framework.commercialization": "http://private.lightyears.ltd:18650/foldcc/CC-Framework.Commercialization.git#1.0.15"
```

当前仓库自身作为 Unity 验证工程时，可以在 `Packages/manifest.json` 使用本地 `file:` 引用：

```json
"com.foldcc.cc-framework.commercialization": "file:CC-Framework.Commercialization/Assets"
```

该路径以 `Packages/manifest.json` 所在目录为基准，符合 Unity 本地 UPM package 规则；`Packages/CC-Framework.Commercialization` 只是本机验证副本，已被 `.gitignore` 排除，不进入发布包。

如果 batchmode 出现 `Failed to resolve packages: The "path" argument must be of type string. Received undefined`，不把它直接归因为 manifest 路径错误，也不使用 `-noUpm` 绕过。处理顺序是保存 Unity Editor log 和 `%LOCALAPPDATA%\Unity\Editor\upm.log`，确认没有并发 Unity/UPM 进程，再用官方 `Unity.exe -batchmode -quit -projectPath <project> -logFile <log>` 做一次只解析 package 的验证；若仍复现，则用 Unity Hub/已打开 Editor 作为 GUI 对照入口继续看 Console 编译错误。

## 策略验收与可视化

模块内置智能预加载策略评估脚本已接入，默认次留验收目标为 `35%`，用于验证 `PreloadThreshold`、`CooldownSeconds` 在不同留存下的策略敏感度。

验收输出位于：

* `Tools/SmartLoadSensitivity/output/TapADN_智能预加载_敏感度验收报告.md`
* `Tools/SmartLoadSensitivity/output/smartload_sensitivity_summary.csv`
* `Tools/SmartLoadSensitivity/output/smartload_retention_rank.csv`
* `Tools/SmartLoadSensitivity/output/*.png`

推荐复现命令：

```bash
python Tools/SmartLoadSensitivity/smartload_sensitivity_simulation.py --users 5000 --out-dir Tools/SmartLoadSensitivity/output
```

核心对比维度（含 35%次留）：

* `threshold` 的下调会提升 `Immediate`，但会抬高 `Waste`。
* `cooldown` 拉长可压低 waste、降低重复预加载频次，但也会把 show 等待时延上抬。
* 默认策略建议先用 `threshold=0.20~0.40` 做高即时性验证，再通过 waste 上限（如 8%~12%）回退到 `0.35~0.55` 区间。

### 全局缓存归因

`CC-Framework.Commercialization` 当前是一类广告一个全局 `ADPlayer`，场景只是播放与策略标签，不是缓存隔离单位。因此 TapADN 智能预加载按两层口径统计：

* 策略触发层：哪个场景触发了真实 SDK load，记录 `preload_request/preload_success/preload_fail`。
* 播放消费层：哪个场景实际发起 `AsyncPlayAD` 并展示，记录 `immediate_hit/show_start/smart_cache_hit`。

如果 A 场景触发的全局缓存最终在 B 场景展示，A 会记录 `smart_preload_consumed_other_scene`，B 会记录 `smart_cache_cross_scene_hit`。这不会改变玩家实际体验，只用于避免把“全局缓存命中”误读成“同场景完全自消费”。

验收产物建议每周回放：用最近 7 天留存分布与 fill 成功率替换脚本默认参数，再做一次敏感度重算并对比排名变化。
