> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kontext.so/llms.txt
> Use this file to discover all available pages before exploring further.

# React Native SDK

> 在你的 React Native iOS / Android 应用中接入 Kontext 广告 SDK。

<Info>
  我们正在准备 React Native SDK 的 v4 版本。下方文档对应当前正式版本——一旦 v4 发布，本页会同步更新。
</Info>

<Card title="React Native Demo 项目" icon="github" href="https://github.com/kontextso/sdk-react-native-demo">
  看看用我们轻量的 SDK 接入高性能广告有多简单。
</Card>

## 环境要求

* **React Native**：0.73.2 或更高版本

## 快速开始

### 1. 安装

<Note>
  在开始之前，你需要先建立一个 [发布方账号](/publishers#getting-started-is-easy) 来获取 `publisherToken` 和 `code`。
</Note>

```bash theme={null}
# 安装 SDK
npm install @kontextso/sdk-react-native

# 安装必需的 peer dependencies
npm install react-native-device-info react-native-webview @react-native-community/netinfo
```

### 2. 初始化 AdsProvider

`AdsProvider` 负责所有数据获取逻辑，必须能访问到聊天消息。请把它放在组件树的足够上层，以包含所有的广告位。

```tsx theme={null}
import * as React from 'react'
import { useState } from 'react'
import { View } from 'react-native'
import { AdsProvider } from '@kontextso/sdk-react-native'

interface Message {
  id: string
  role: 'user' | 'assistant'
  content: string
  createdAt: Date
}

function App() {
  const [messages, setMessages] = useState<Message[]>([])

  return (
    <AdsProvider
      publisherToken="<publisher-token>"
      messages={messages}
      userId='user-1234'
      conversationId='conv-5678'
      enabledPlacementCodes={['inlineAd']}
      character={{
        id: 'character-1234',
        name: 'John Doe',
        avatarUrl: 'https://example.com/avatar.png',
        greeting: 'Hello, how can I help you today?'
      }}
      regulatory={{
        coppa: 0,
        // ... 其他合规属性
      }}
      onEvent={({ name, code, payload }) => {
        // 处理事件
      }}
    >
      <TheRestOfYourApplication />
    </AdsProvider>
  )
}
```

### 3. 配置 IFA（广告标识符）

* **iOS：** 在 `ios/<YourApp>/Info.plist` 中加入 `NSUserTrackingUsageDescription`。SDK 会自动触发 ATT 弹窗并据此读取 IDFA。
* **Android：** SDK 通过 manifest merger 自动加入 `com.google.android.gms.permission.AD_ID`——你无需修改 `AndroidManifest.xml`。

完整设置见 [IFA 与 ATT](/guides/ifa)——必填 key、弹窗时机的坑，以及如何自己管理弹窗。

### 4. 配置 SKAdNetwork（仅 iOS）

请把 onboarding 时提供的 SKAdNetwork 标识符追加到 `ios/<YourApp>/Info.plist` 中。SDK 会读取它们，并在每次 `/init` 时一并转发，以便 DSP 衡量转化。

完整指南见 [SKAdNetwork](/guides/skadnetwork)。

### 5. 展示你的第一个广告

广告位（ad slot）是 UI 中专门用来渲染广告的区域，通常出现在聊天消息下方。Onboarding 时，你会拿到每个广告位的唯一 `code`。

把 `<InlineAd />` 放在希望广告出现的位置，并为 `messageId` 传入唯一标识。例如，在 `MessageList` 组件中，可以在每条消息后渲染一个广告（由于每条消息的 `messageId` 不同，展示的广告也会各自独立）。

```tsx theme={null}
function MessageList({ messages }: { messages: Message[] }) {
  return (
    <View>
      {messages.map((m) => (
        <View key={m.id}>
          <Message message={m} />
          <InlineAd code="<your-code>" messageId={m.id} />
        </View>
      ))}
    </View>
  )
}
```

## API 文档

### `AdsProvider` 属性

<ParamField path="publisherToken" type="string" required>
  你的 publisher token。
</ParamField>

<ParamField path="messages" type="array" required>
  用户和助手之间的消息列表。

  <Expandable title="字段">
    <ParamField path="id" type="string" required>
      消息的唯一 ID。
    </ParamField>

    <ParamField path="role" type="string" required>
      消息角色（`user` 或 `assistant`）。
    </ParamField>

    <ParamField path="content" type="string" required>
      消息文本。
    </ParamField>

    <ParamField path="createdAt" type="Date" required>
      消息创建时间戳。
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="userId" type="string" required>
  在用户整个生命周期内保持不变的唯一标识（用于再营销与奖励广告）。
</ParamField>

<ParamField path="userEmail" type="string">
  用户邮箱。
</ParamField>

<ParamField path="conversationId" type="string" required>
  对话的唯一 ID。
</ParamField>

<ParamField path="enabledPlacementCodes" type="array" required>
  本次对话启用的 placement code。例如：`['inlineAd']`。
</ParamField>

<ParamField path="character" type="object" optional>
  本次对话使用的 character 对象。

  <Expandable title="字段">
    <ParamField path="id" type="string" required>
      角色的唯一 ID。
    </ParamField>

    <ParamField path="name" type="string" required>
      角色名称。
    </ParamField>

    <ParamField path="avatarUrl" type="string" required>
      角色头像 URL。
    </ParamField>

    <ParamField path="isNsfw" type="boolean" optional>
      标识该角色是否面向成人受众。
    </ParamField>

    <ParamField path="greeting" type="string" optional>
      角色的问候语。
    </ParamField>

    <ParamField path="persona" type="string" optional>
      角色性格的简要描述。
    </ParamField>

    <ParamField path="tags" type="array" optional>
      描述角色的标签。
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="regulatory" type="object" optional>
  合规相关信息。

  如果你的应用集成了兼容 TCF 的 CMP（Consent Management Platform），SDK 会自动处理 **TCF（透明度与同意框架）** 信号（`gdpr` 与 `gdprConsent`）——你无需手动设置这两个字段。

  <Expandable title="字段">
    <ParamField path="gdpr" type="integer" optional>
      请求是否受 GDPR 约束。（0 = 否，1 = 是，null = 未知）
    </ParamField>

    <ParamField path="gdprConsent" type="string" optional>
      IAB 透明度与同意框架（TCF）的 consent 字符串。
    </ParamField>

    <ParamField path="coppa" type="integer" optional>
      请求是否受 COPPA 约束。（0 = 否，1 = 是，null = 未知）
    </ParamField>

    <ParamField path="gpp" type="string" optional>
      Global Privacy Platform (GPP) consent 字符串。
    </ParamField>

    <ParamField path="gppSid" type="array" optional>
      本次请求适用的 GPP section ID 列表。
    </ParamField>

    <ParamField path="usPrivacy" type="string" optional>
      美国隐私法规（如 CCPA、LSPA）相关的消费者信号。
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="variantId" type="string" optional>
  发布方提供的用户分群标识（用于 A/B 测试）。
</ParamField>

<ParamField path="onEvent" type="function" optional>
  事件发生时的回调。详见下方的支持的事件章节。
</ParamField>

<ParamField path="isDisabled" type="boolean" optional>
  是否禁用广告的标志位。

  注意：这并不会影响已展示的旧广告；旧广告的处理由 `staleAdsHandling` 控制。
</ParamField>

<ParamField path="staleAdsHandling" type="string" optional>
  决定如何处理"过期广告"（与最新消息不再关联的广告）。

  * `preserve` —— 继续展示最近锚定的广告，直到有新广告替换它
  * `hide`（默认）—— 一旦广告过期就隐藏
</ParamField>

### `InlineAd` 属性

<ParamField path="code" type="string" required>
  Onboarding 时提供的 placement code。
</ParamField>

<ParamField path="messageId" type="string" required>
  消息的唯一 ID。
</ParamField>

<ParamField path="theme" type="string" optional>
  广告主题，例如 `light` 或 `dark`。
</ParamField>

<ParamField path="wrapper" type="function" optional>
  用于包装广告内容的函数。
</ParamField>

### 支持的事件

#### `ad.clicked`

用户点击了广告。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>

  <ParamField path="content" type="string">
    生成的广告内容。
  </ParamField>

  <ParamField path="messageId" type="string">
    消息 ID。
  </ParamField>

  <ParamField path="url" type="string">
    点击跳转的 URL。
  </ParamField>

  <ParamField path="format" type="string">
    广告形式。
  </ParamField>
</Expandable>

#### `ad.viewed`

用户已查看广告。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>

  <ParamField path="content" type="string">
    生成的广告内容。
  </ParamField>

  <ParamField path="messageId" type="string">
    消息 ID。
  </ParamField>

  <ParamField path="format" type="string">
    广告形式。
  </ParamField>

  <ParamField path="revenue" type="number" optional>
    广告收入（美元计的 eCPM）。
  </ParamField>
</Expandable>

#### `ad.filled`

有可投放的广告。

<Expandable title="Payload">
  <ParamField path="revenue" type="number" optional>
    广告收入（美元计的 eCPM）。
  </ParamField>
</Expandable>

#### `ad.no-fill`

没有可投放的广告。

<Expandable title="Payload">
  <ParamField path="skipCode" type="string">
    指示广告被跳过原因的代码。
  </ParamField>
</Expandable>

#### `ad.render-started`

在第一个 token 到达之前触发。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>
</Expandable>

#### `ad.render-completed`

在最后一个 token 到达之后触发。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>
</Expandable>

#### `ad.error`

出现错误时触发。

<Expandable title="Payload">
  <ParamField path="message" type="string">
    错误信息。
  </ParamField>

  <ParamField path="errCode" type="string">
    错误代码。
  </ParamField>
</Expandable>

#### `reward.granted`

用户获得奖励时触发。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>
</Expandable>

#### `video.started`

视频开始播放时触发。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>
</Expandable>

#### `video.completed`

视频播放完成时触发。

<Expandable title="Payload">
  <ParamField path="id" type="string">
    广告 ID。
  </ParamField>
</Expandable>

## 实践指南

### 处理 no-fill 事件

可以通过 `onEvent` 回调感知广告何时不可用。

```tsx theme={null}
<AdsProvider
  // ...
  onEvent={({ name, payload }) => {
    if (name === 'ad.no-fill') {
      console.log('Ad is not available');
    }
  }}
/>
```

## 链接

* [NPM 包](https://www.npmjs.com/package/@kontextso/sdk-react-native)
* [React Native Demo 项目](https://github.com/kontextso/sdk-react-native-demo)
