> 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/common/growth/share/reward.md).

# 分享奖励

服务介绍和控制台设置方法是 [共享奖励介绍文档](https://developers-apps-in-toss.toss.im/guide/marketing/share-reward)请参考。

`contactsViral`在 **一种共享奖励功能，允许用户把迷你应用分享给好友，并根据结果发放奖励**。当用户完成分享后，会通过应用桥接传递事件，并基于该事件 **可以确认是否发放奖励以及发放信息**。

共享奖励可用于以下用途。

* 基于好友邀请 **病毒式引流**
* 推荐人奖励 / 邀请奖励
* 迷你应用增长活动
* **游戏** · `非游戏迷你应用通用促销`

{% hint style="info" %}
**请注意**

* 此功能 **仅支持 Toss应用 5.223.0 及以上版本**。在较低版本中， `undefined`会返回。
* 为了使用该功能， **迷你应用审批**是必需的。在未获审批状态下， `Internal Server Error`会发生。
* 共享奖励 **基于控制台中注册的奖励 ID** 运行。
* 奖励发放条件、数量、单位由 **Apps in Toss 控制台**进行设置。
  {% endhint %}

{% hint style="info" %}
**测试环境说明**

* 在沙箱应用中，不会显示实际的分享 UI， **空白页面**会显示为。
* 在沙箱中不会真正发生奖励发放。
* 必须 **使用控制台提供的 QR 代码**在 Toss应用 中进行测试。
* 好友列表可能会因以下条件而不同。
  * 是否同意接收营销
  * 是否同意夜间接收营销
  * 是否注册推送令牌
  * 是否屏蔽联系人通知
    {% endhint %}

***

### 流程

**游戏**

**非游戏**

***

**签名**

```ts
function contactsViral(params: ContactsViralParams): () => void;
```

**参数**

* **params** · 必填

  这是在执行联系人分享功能时使用的参数。包括选项设置和事件处理器。详细类型请参考 `ContactsViralParams` 。

**返回值**

* () => void

  会返回应用桥接 cleanup 函数。分享功能结束后，必须调用此函数以释放资源。

**示例：分享并领取奖励**

下面的示例展示了执行共享奖励，并处理分享完成或模块结束事件的基本流程。

{% tabs %}
{% tab title="js" %}

```js
import { contactsViral } from '@apps-in-toss/web-framework';

function handleContactsViral(moduleId) {
  const cleanup = contactsViral({
    options: { moduleId: moduleId.trim() },
    onEvent: (event) => {
      if (event.type === 'sendViral') {
        console.log('奖励发放：', event.data.rewardAmount, event.data.rewardUnit);
      } else if (event.type === 'close') {
        console.log('模块结束：', event.data.closeReason);
        cleanup();
      }
    },
    onError: (error) => {
      console.error('发生错误：', error);
      cleanup?.();
    },
  });
}
```

{% endtab %}

{% tab title="React" %}

```tsx
import { contactsViral } from '@apps-in-toss/web-framework';
import { Button } from '@toss/tds-mobile';
import { useCallback } from 'react';

function ContactsViralButton({ moduleId }: { moduleId: string }) {
  const handleContactsViral = useCallback(() => {
    try {
      const cleanup = contactsViral({
        options: { moduleId: moduleId.trim() },
        onEvent: (event) => {
          if (event.type === 'sendViral') {
            console.log('奖励发放：', event.data.rewardAmount, event.data.rewardUnit);
          } else if (event.type === 'close') {
            console.log('模块结束：', event.data.closeReason);
            cleanup();
          }
        },
        onError: (error) => {
          console.error('发生错误：', error);
          cleanup?.();
        },
      });
    } catch (error) {
      console.error('执行中出错：', error);
    }
  }, [moduleId]);

  return <Button onClick={handleContactsViral}>分享给好友并领取奖励</Button>;
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { contactsViral } from '@apps-in-toss/framework';
import { Button } from '@toss/tds-react-native';
import { useCallback } from 'react';

function ContactsViralButton({ moduleId }: { moduleId: string }) {
  const handleContactsViral = useCallback(() => {
    try {
      const cleanup = contactsViral({
        options: { moduleId: moduleId.trim() },
        onEvent: (event) => {
          if (event.type === 'sendViral') {
            console.log('奖励发放：', event.data.rewardAmount, event.data.rewardUnit);
          } else if (event.type === 'close') {
            console.log('模块结束：', event.data.closeReason);
            cleanup();
          }
        },
        onError: (error) => {
          console.error('发生错误：', error);
          cleanup?.();
        },
      });
    } catch (error) {
      console.error('执行中出错：', error);
    }
  }, [moduleId]);

  return <Button onPress={handleContactsViral}>分享给好友并领取奖励</Button>;
}
```

{% endtab %}
{% endtabs %}

**体验示例应用**

[apps-in-toss-examples](https://github.com/toss/apps-in-toss-examples) 在仓库中 [with-contacts-viral](https://github.com/toss/apps-in-toss-examples/tree/main/with-contacts-viral) 下载代码，或扫描下方二维码亲自体验。

QR 代码链接：intoss\://with-contacts-viral

***

**类型定义： `ContactsViralOption`**

**签名**

```ts
type ContactsViralOption = {
  moduleId: string;
};
```

**属性**

* **moduleId** · 必填

  用于区分共享奖励的 UUID 格式唯一 ID。可在 Apps in Toss 控制台的 **迷你应用 > 共享奖励** 菜单中查看。

**`ContactsViralParams`**

`ContactsViralParams` 是 `contactsViral` 这是在执行函数时使用的参数类型。可以设置选项，并指定事件和错误处理回调。

**签名**

```ts
interface ContactsViralParams {
  options: ContactsViralOption;
  onEvent: (event: ContactsViralEvent) => void;
  onError: (error: unknown) => void;
}
```

**属性**

* **options** · 必填

  用于共享功能的选项对象。详细类型请参考 \[ContactsViralOption]\(/pages/jNMtkgvrarYfZ4oqNamT) 文档。
* **onEvent** · 必填

  当发生共享事件时执行的函数。会传入 \[RewardFromContactsViralEvent]\(/pages/jNMtkgvrarYfZ4oqNamT) 或 \[ContactsViralSuccessEvent]\(/pages/jNMtkgvrarYfZ4oqNamT) 类型的事件对象。
* **onError** · 必填

  当发生意外错误时执行的函数。错误对象的类型是 `unknown`。

**`ContactsViralSuccessEvent`**

`ContactsViralSuccessEvent` 是指联系人分享模块正常结束时传递的事件对象。会连同结束原因一起提供奖励状态和剩余好友数等相关信息。

**签名**

```ts
type ContactsViralSuccessEvent = {
  type: 'close';
  data: {
    closeReason: 'clickBackButton' | 'noReward';
    sentRewardAmount?: number;
    sendableRewardsCount?: number;
    sentRewardsCount: number;
    rewardUnit?: string;
  };
};
```

**属性**

* **类型** · 必填

  这是事件的类型。共享模块结束时 `close` 会带着该值返回。
* **数据** · 必填

  包含与模块结束相关的详细信息。

  * **data.closeReason** · 必填

    是模块结束的原因。

    `clickBackButton`：用户点击返回按钮后结束的情况

    `noReward`：因没有可领取奖励而结束的情况
  * **data.sentRewardAmount**

    是用户收到的奖励总数量。可选传递。
  * **data.sendableRewardsCount**

    是当前仍可分享的好友数量。可选传递。
  * **data.sentRewardsCount** · 必填

    是用户已完成分享的好友数量。
  * **data.rewardUnit**

    是奖励单位。在 Apps in Toss 控制台中设置的 `爱心`, `宝石` 等名称会包含在内。可选传递。

**示例**

处理模块结束事件

```ts
contactsViral({
  options: { moduleId: 'your-module-id' },
  onEvent: (event) => {
    if (event.type === 'close') {
      console.log('结束原因：', event.data.closeReason);
      console.log('已完成分享的好友数：', event.data.sentRewardsCount);
    }
  },
  onError: (error) => {
    console.error('发生错误：', error);
  },
});
```

**`RewardFromContactsViralEvent`**

`RewardFromContactsViralEvent` 是一个用于存放完成分享给好友后要发放的奖励信息的类型。使用该类型时，可以确认分享完成后要发放的奖励信息。

**签名**

```ts
type RewardFromContactsViralEvent = {
  type: 'sendViral';
  data: {
    rewardAmount: number;
    rewardUnit: string;
  };
};
```

**属性**

* **类型** · 必填

  这是事件的类型。当完成向好友分享时 `'sendViral'` 会带着该值返回。
* **数据** · 必填

  包含要发放的奖励相关信息。

  * **data.rewardAmount** · 必填

    是要发放的奖励数量。这是 Apps in Toss 控制台中设置的数量和金额值。
  * **data.rewardUnit** · 必填

    是奖励单位。在 Apps in Toss 控制台中设置的奖励名称，如 `'爱心'`, `'宝石'` 等。

**示例**

分享完成后处理奖励信息

```ts
contactsViral({
  options: { moduleId: 'your-module-id' },
  onEvent: (event) => {
    if (event.type === 'sendViral') {
      console.log('奖励发放：', event.data.rewardAmount, event.data.rewardUnit);
    }
  },
  onError: (error) => {
    console.error('发生错误：', error);
  },
});
```

### 参考事项

* 共享奖励 **游戏/非游戏迷你应用均可使用**。
* 奖励政策和发放条件 **由控制台设置**来决定。
* 处理事件后，请务必调用 cleanup 函数。


---

# 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/common/growth/share/reward.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.
