> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/unity/add-features/advertising.md).

# 广告接入

说明 SDK 提供的三种广告展示位，以及各自的接入方式。

| 广告类型     | 入口 API                                          | 形式    | 何时使用                   |
| -------- | ----------------------------------------------- | ----- | ---------------------- |
| 全屏广告     | `AIT.LoadFullScreenAd` / `AIT.ShowFullScreenAd` | 插屏、激励 | 直接展示 Toss 广告网络的插屏·激励广告 |
| AdMob 广告 | `AIT.GoogleAdMobLoadAppsInTossAdMob` / `…Show…` | 插屏、激励 | 通过 Google AdMob 中介展示   |
| 横幅广告     | `AITBannerAd`, `AITBannerAdView`                | 横幅    | 常驻显示在屏幕上方·下方或任意区域      |

插屏广告和 AdMob 广告都支持 **插屏（Interstitial）** 和 **激励（Rewarded）** 。两者调用 API 相同，并通过 **`adGroupId`区分**，且激励广告会在用户获得奖励时额外触发 `userEarnedReward` 事件。

### 共同前提

* **`adGroupId`** 是从 Apps in Toss 控制台发放的广告组 ID。这个值决定广告类型（插屏·激励、横幅强调类型）和展示策略。
* **实际广告渲染只在 Toss App 内运行。** 在普通浏览器或 Unity Editor 中无法到达广告网络，因此初始化后 `FailedToRender`·`NoFill`（横幅）或错误回调都是正常的。 `AIT` > `Deploy (Test)`请部署后通过二维码在真机上确认。
* 在 Unity Editor 和非 WebGL 环境中，所有广告 API 都会 `[AIT Mock]` 只留下日志，不会真正触发事件。请在 WebGL 构建后、Toss App 中确认实际效果。
* 所有回调型 API 都会返回 **用于取消订阅的 `Action`** 。 `OnDestroy` 等处调用进行清理。

### 全屏广告

用于展示 Toss 广告网络的插屏·激励广告的原生路径。 **`Load` 之后 `Show`** 两步调用。

```csharp
using AppsInToss;

// adGroupId 是从控制台发放的值。插屏/激励通过 adGroupId 区分。
private const string AD_GROUP_ID = "your-ad-group-id";
private Action _unsubscribe;

// 第 1 步：预加载
void Load()
{
    _unsubscribe = AIT.LoadFullScreenAd(
        adGroupId: AD_GROUP_ID,
        onEvent: e =>
        {
            if (e.Type == "loaded") Show();   // 加载完成后展示
        },
        onError: err => Debug.LogError($"load 失败：{err.ErrorCode} {err.Message}")
    );
}

// 第 2 步：展示
void Show()
{
    AIT.ShowFullScreenAd(
        adGroupId: AD_GROUP_ID,
        onEvent: e =>
        {
            // 当激励广告中用户获得奖励时
            if (e.Type == "userEarnedReward" && e.Data != null)
                Debug.Log($"奖励：{e.Data.UnitAmount} {e.Data.UnitType}");

            if (e.Type == "dismissed")
                Debug.Log("广告关闭 — 需要再次 Load 才能下次展示");
        },
        onError: err => Debug.LogError($"show 失败：{err.ErrorCode} {err.Message}")
    );
}

void OnDestroy() => _unsubscribe?.Invoke();
```

| 阶段   | `e.Type`           | 含义                                                     |
| ---- | ------------------ | ------------------------------------------------------ |
| Load | `loaded`           | 广告加载完成 — 之后 `Show` 可                                   |
| Show | `userEarnedReward` | 仅激励广告使用。用户获得奖励（`e.Data.UnitType`, `e.Data.UnitAmount`) |
| Show | `dismissed`        | 广告关闭 — 下次展示前需重新 `Load` 需要                              |

示例： [FullScreenAdTester.cs](https://github.com/toss/apps-in-toss-unity-sdk/blob/main/Tests~/E2E/SharedScripts/Runtime/FullScreenAdTester.cs) — 可交互地确认插屏·激励的选择，以及 Load → Show 流程和事件日志。

### AdMob 广告

通过 Google AdMob 中介展示插屏·激励广告。与全屏广告相同， **`Load` 之后 `Show`** 是同样的流程，另外还提供查询是否已加载的 API。

```csharp
using AppsInToss;

private const string AD_GROUP_ID = "your-admob-ad-group-id";
private Action _unsubscribe;

void Load()
{
    _unsubscribe = AIT.GoogleAdMobLoadAppsInTossAdMob(
        options: new LoadAdMobOptions { AdGroupId = AD_GROUP_ID },
        onEvent: e =>
        {
            if (e.Type == "loaded" && e.Data != null)
                Debug.Log($"loaded: adUnitId={e.Data.AdUnitId}");
        },
        onError: err => Debug.LogError($"{err.ErrorCode} {err.Message}")
    );
}

void Show()
{
    AIT.GoogleAdMobShowAppsInTossAdMob(
        options: new ShowAdMobOptions { AdGroupId = AD_GROUP_ID },
        onEvent: e =>
        {
            if (e.Type == "userEarnedReward" && e.Data != null)
                Debug.Log($"奖励：{e.Data.UnitAmount} {e.Data.UnitType}");
            if (e.Type == "dismissed")
                Debug.Log("广告关闭 — 需要重新 Load");
        },
        onError: err => Debug.LogError($"{err.ErrorCode} {err.Message}")
    );
}

// 查询是否已加载
async void CheckLoaded()
{
    bool loaded = await AIT.GoogleAdMobIsAppsInTossAdMobLoaded(
        new IsAdMobLoadedOptions { AdGroupId = AD_GROUP_ID });
    Debug.Log($"loaded = {loaded}");
}

void OnDestroy() => _unsubscribe?.Invoke();
```

在加载事件的 `e.Data`中 `AdGroupId`, `AdUnitId`, `ResponseInfo`会包含这些信息，可以确认是哪一个广告单元响应。全屏广告侧没有这些信息。

示例： [AdV2Tester.cs](https://github.com/toss/apps-in-toss-unity-sdk/blob/main/Tests~/E2E/SharedScripts/Runtime/AdV2Tester.cs) — AdMob 插屏·激励的 Load、Show、IsLoaded 调用，以及奖励事件处理示例。

### 横幅广告

横幅由 SDK 直接创建并管理 DOM 容器，因此无需了解 HTML 或 CSS。有两种方式。

* **`AITBannerAd`** — 静态 helper。通过一行代码在屏幕上方·下方预设位置显示。只保留一个槽位，再次调用时会替换现有横幅。
* **`AITBannerAdView`** — MonoBehaviour 组件。将 Canvas 下的 RectTransform 像平时的 uGUI 一样布局后，横幅会覆盖在该区域之上。会自动跟踪移动·缩放·屏幕旋转，并且每个实例都是独立槽位，因此 **可同时** 显示多个。

横幅的 **强调类型**（文案强调约 90px 固定、图片强调为 16:9 可变高度）由控制台中的广告组设置决定，而不是代码决定。可变高度会通过 `Resized` 事件通知。

#### 用 AITBannerAd 在预设位置显示

```csharp
using AppsInToss;

AITBannerAd.OnAdEvent += evt => Debug.Log($"横幅事件：{evt}");
AITBannerAd.OnError += msg => Debug.LogWarning($"横幅错误：{msg}");

// 显示在屏幕底部（默认：Bottom / Auto 主题 / 黑白色调 / 扩展型）
AITBannerAd.Show("your-banner-ad-group-id", AITBannerPosition.Bottom);

// 隐藏
AITBannerAd.Hide();
```

`Show`通过选择参数调整外观。

| 参数         | 值                                 | 默认值             |
| ---------- | --------------------------------- | --------------- |
| `position` | `Top`, `Bottom` （两者都应用 safe area） | `Bottom`        |
| `theme`    | `Auto`, `Light`, `Dark`           | `Auto`          |
| `tone`     | `BlackAndWhite`, `Grey`           | `BlackAndWhite` |
| `variant`  | `Card`, `Expanded`                | `Expanded`      |

当前是否显示可通过 `AITBannerAd.IsShowing`确认。 `adGroupId`如果为空， `Show`不会请求广告，而是 `OnError`通知后返回。

#### 用 AITBannerAdView 显示在 RectTransform 区域内

在 Inspector 中 `Ad Group Id`, `Placement`、主题·色调·变体， `On Ad Event`（UnityEvent）进行设置，或通过代码附加。

```csharp
using AppsInToss;

// 横幅会跟随用于展示横幅的 RectTransform（此 GameObject）区域并覆盖显示。
var view = gameObject.AddComponent<AITBannerAdView>();
view.AdGroupId = "your-banner-ad-group-id";
view.Placement = AITBannerAdPlacement.FollowRectTransform; // 或 ScreenTop / ScreenBottom

// 会同时传递给 C# 事件和 Inspector UnityEvent。
view.OnAdEvent += evt =>
{
    if (evt.Kind == AITBannerAdEventKind.Resized)
        Debug.Log($"渲染高度 {evt.Height}px（比例 {evt.HeightFraction:F3}）");
};

view.Show();   // 当 showOnEnable 为 true（默认）且 AdGroupId 已填写时，会在 OnEnable 中自动调用
// view.Hide();
```

#### 横幅事件

两种方式都会接收同一个 `AITBannerAdEvent`。

| `Kind`                                | 含义              |
| ------------------------------------- | --------------- |
| `Initialized`, `InitializationFailed` | 广告 SDK 初始化完成、失败 |
| `Rendered`                            | 横幅渲染完成          |
| `Viewable`, `Impression`              | 屏幕可见、展示计数       |
| `Clicked`                             | 横幅点击            |
| `Resized`                             | 渲染后的横幅尺寸变更      |
| `FailedToRender`, `NoFill`            | 渲染失败，无可填充广告     |

事件对象中还包含 `AdGroupId`, `SlotId`, `CreativeId`, `RequestId`。在咨询展示问题时， `RequestId`可加上以便更快追踪。

`Resized`中 `Width`·`Height`（CSS px）和 `HeightFraction`（相对于画布的比例） `FailedToRender`·`NoFill`中 `ErrorCode`·`ErrorMessage`会被填充。

> **注意**: `FollowRectTransform` 模式下 `AutoResizeHeight`（默认 `true`）会将 RectTransform 高度调整为实际横幅高度。放在布局组下时，请将该值 `false`设为 `Resized` ，并在 `view.RenderedHeightLocal`事件中读取 `LayoutElement.preferredHeight`并直接应用。否则布局组与自动调整会互相覆盖高度。

示例： [BannerAdTester.cs](https://github.com/toss/apps-in-toss-unity-sdk/blob/main/Tests~/E2E/SharedScripts/Runtime/BannerAdTester.cs) — 可同时显示两个组件（文案强调·图片强调）和静态 helper，以确认多槽位和自动高度的行为。

### 当广告不显示时

1. **是否在 Toss App 内运行？** 实际渲染只在 Toss App 内进行。在普通浏览器和 Editor 中，初始化后出现失败·无填充事件是正常的。 `Deploy (Test)`请部署后在真机上确认。
2. **`adGroupId`是否与控制台发放值一致？** 错误的 ID 会因格式·参数错误（例如 `code 1002`）而被拒绝。
3. **插屏和 AdMob 广告 `loaded` 之后 `Show` 是否进行了** `dismissed` 之后需要再次 `Load` 。
4. **`onError`和事件回调是否已订阅？** 横幅的 `FailedToRender`·`NoFill`的 `ErrorCode`和 `ErrorMessage`中包含原因。

### 示例项目

三个广告的交互式测试器已包含在仓库示例中。

* 共享脚本： [`Tests~/E2E/SharedScripts/Runtime/`](https://github.com/toss/apps-in-toss-unity-sdk/tree/main/Tests~/E2E/SharedScripts/Runtime)
* 各版本示例 Unity 项目： [`Tests~/E2E/`](https://github.com/toss/apps-in-toss-unity-sdk/tree/main/Tests~/E2E)

### 相关文档

* [API 使用模式](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/api-usage-patterns) — 回调型 API、取消订阅与错误处理
* [构建配置文件](https://developers-apps-in-toss.toss.im/documentation/unity/build/build-profiles) — 关闭 devtools 后确认真实广告流程
* [问题排查](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/faq) — 其他问题排查


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/unity/add-features/advertising.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
