> 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)`请构建并发布，通过 QR 在真机上确认。
* 在 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` | `顶部`, `底部` （两者都反映 safe area） | `底部` |
| `theme`    | `自动`, `浅色`, `深色`             | `自动` |
| `tone`     | `黑白`, `灰色`                   | `黑白` |
| `variant`  | `卡片`, `展开`                   | `展开` |

当前是否显示可通过 `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`（相对于 Canvas 的比例） `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.
