# Cocos Rewarded Ads Kit

一个独立的、面向多个 Cocos Creator 项目的激励视频广告插件仓库。

推荐先看：

- [Quick Start](./docs/getting-started.md)
- [设计稿](./docs/superpowers/specs/2026-03-29-cocos-rewarded-ads-kit-design.md)
- [实现计划](./docs/superpowers/plans/2026-03-29-bootstrap-v1.md)

## v1 范围

- 只做激励视频
- 支持按平台按需接入
- 重点 provider / platform：
  - Android AdMob
  - iOS AdMob
  - Android MAX
  - iOS MAX
  - Android TopOn
  - iOS TopOn
  - 微信小游戏
  - 抖音小游戏

## 当前目录结构

```text
packages/
  core/
  runtime/
  adapter-wechat-mini-game/
  adapter-douyin-mini-game/
  adapter-android-admob/
  adapter-ios-admob/
  adapter-android-max/
  adapter-ios-max/
  adapter-android-topon/
  adapter-ios-topon/
  build-plugin/
examples/
  cocos-consumer/
```

## 业务侧目标用法

```ts
import { createPreparedRewardedAdsRuntime } from './build/rewarded-ads/generated/bootstrap-runtime.ts';

const rewardedAds = createPreparedRewardedAdsRuntime({
  platform: 'wechat-mini-game',
});

await rewardedAds.init();
await rewardedAds.preload('reward_revive');

const result = await rewardedAds.show('reward_revive');
if (result.earned) {
  // 发奖励
}
```

## 配置文件

每个接入项目维护一份 `ads.config.json`，按目标平台分别配置：

- 微信小游戏 / 抖音小游戏：`adUnitId`
- AdMob：`appId + adUnitId`
- MAX：`sdkKey + adUnitId`
- TopOn：`appId + appKey + adUnitId`

### v1 provider 约束

- 同一目标平台只允许一个 rewarded provider
- 同一平台可以有多个 placement
- 这些 placement 在 v1 中必须共用同一个 provider
- 如果同平台混用 MAX / TopOn，build-plugin 会直接校验失败

可参考：
- [consumer example](./examples/cocos-consumer/README.md)
- [android-admob example](./examples/android-admob/ads.config.json)
- [ios-admob example](./examples/ios-admob/ads.config.json)
- [wechat-mini-game example](./examples/wechat-mini-game/ads.config.json)
- [douyin-mini-game example](./examples/douyin-mini-game/ads.config.json)
- [android-max example](./examples/android-max/ads.config.json)
- [ios-max example](./examples/ios-max/ads.config.json)
- [android-topon example](./examples/android-topon/ads.config.json)
- [ios-topon example](./examples/ios-topon/ads.config.json)

## 当前实现进度

已完成：
- 核心类型与配置归一化
- 运行时 facade 与 generated binding registry
- provider 包入口与 runtime 工厂签名对齐
- 微信小游戏 / 抖音小游戏 adapter
- Android / iOS AdMob / MAX / TopOn native provider bridge 模板
- build-plugin 平台选择、prepare CLI、Cocos build extension、bootstrap-runtime 生成
- Android / iOS 宿主工程自动 patch
- Cocos 项目消费者示例与接入文档

仓库外仍需人工验收：
- 使用真实 MAX / TopOn 凭据做一次 Android / iOS 最终构建
- 在真实广告位上确认 preload / show / earned / cancelled 行为

## npm 安装

推荐在接入项目里直接安装发布包：

```bash
npm i -D cocos-rewarded-ads-kit@1.0.0
```

## 一键 prepare 命令

安装后可直接用 CLI 生成当前平台广告产物：

```bash
npx cocos-rewarded-ads prepare --config ./ads.config.json --platform wechatgame --output ./build/rewarded-ads
```

可选参数：
- `--extension-name`：指定生成的 Cocos 扩展插件名。

  > **注意（多项目场景）**：如果你同时在同一个 Cocos Creator 实例中打开多个接入了本组件的项目，
  > 每个项目必须使用不同的 `--extension-name`，否则扩展名冲突会导致其中一个项目的 hooks 不生效。
  > 例如：
  > ```bash
  > npx cocos-rewarded-ads prepare --config ./ads.config.json --platform android \
  >   --output ./build/android --extension-name my-game-rewarded-ads-build
  > ```

当前支持的平台参数：
- `android`
- `ios`
- `wechatgame`
- `bytedance-mini-game`

## prepare 输出内容

执行 `prepare:ads` 后，当前版本会生成这几类产物：

- `generated/`
  - `active-adapter.ts`
  - `generated-rewarded-config.ts`
  - `install-generated-bindings.ts`
  - `bootstrap-runtime.ts`
- `cocos-extension/`
  - `package.json`
  - `dist/main.js`
  - `dist/builder.js`
  - `dist/hooks.js`
- `native/`（仅 Android / iOS）
  - provider bridge 模板
  - `RewardedAdsInstaller`
  - provider config JSON
  - 依赖片段
  - AppActivity / AppDelegate 接入 snippet

## 当前 native 输出说明

Android / iOS 当前已经能生成：

- provider bridge 模板
- 统一 installer 入口
- provider 配置文件
- Gradle / Pod 依赖片段
- 原生接入 snippet
- 原生宿主工程 patch plan

并且当前版本已经会在检测到宿主工程文件存在时，自动 patch：

- Android
  - `native/engine/android/app/build.gradle`
  - `native/engine/android/app/src/**/AppActivity.java|kt`
- iOS
  - `native/engine/ios/Podfile.in`
  - `native/engine/ios/CMakeLists.txt`
  - `native/engine/ios/AppDelegate.mm`

这意味着：

- 微信小游戏 / 抖音小游戏已经接近可直接接入状态
- Android / iOS 已经具备“生成 + 自动 patch”的基础闭环
- provider SDK 的最终真机构建验收仍需要接入项目用真实凭据完成

## 推荐接入姿势

如果你是把这套能力接进一个新的 Cocos 项目，当前最稳的方式是：

1. 在项目根目录维护 `ads.config.json`
2. build 前执行 `cocos-rewarded-ads prepare`
3. 在业务代码里只引入 `generated/bootstrap-runtime.ts`
4. 用 placement 调用统一 runtime

参考：

- [Quick Start](./docs/getting-started.md)
- [Cocos 项目接入示例](./examples/cocos-consumer/README.md)

## 已知限制与注意事项

### Android：自定义 Activity 包名

本组件在自动 patch `AppActivity` 时，默认假定 Cocos 生成的 Activity 位于标准路径：

```
native/engine/android/app/src/com/cocos/game/AppActivity.java|kt
```

如果你修改过 Android 项目的包名（不再使用 `com.cocos.game`），自动注入会被跳过，并在构建日志中输出警告。此时需要**手动**在你的 `AppActivity` 中添加：

```kotlin
// onCreate
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    RewardedAdsInstaller.install(this)   // ← 添加这行
}

// onDestroy
override fun onDestroy() {
    super.onDestroy()
    RewardedAdsInstaller.reset()         // ← 添加这行
}
```

> `import com.tinivo.rewardedads.RewardedAdsInstaller` 也需要一并引入。

---

### 非 macOS 环境（Windows / Linux CI）：引擎路径

在 macOS 上，build-plugin 会自动从 `/Applications/Cocos/Creator/` 推断引擎路径。

在 **Windows** 上，它会尝试从 `%LOCALAPPDATA%\cocos\Creator\` 推断。

如果自动推断失败（引擎安装在非标准路径，或在 Linux CI 上），请显式设置环境变量：

```bash
export COCOS_ENGINE_PATH=/path/to/CocosCreator/resources/3d/engine/native
npx cocos-rewarded-ads prepare ...
```

或者将路径写入构建输出目录的 `proj/gradle.properties`：

```properties
COCOS_ENGINE_PATH=/path/to/engine/native
```
