# 符合 Apple 和 Google 的外部购买要求

> 了解您在 Apple 和 Google 上进行外部购买的合规性责任，以及 Unity 提供的 SDK 和网络钩子工具可帮助您履行这些责任。

外部购买通过您自己的 Web 结帐（例如付款提供商）而不是 Apple 或 Google 的应用内计费来销售数字内容。Apple 和 Google 仅在特定地区允许这样做，并且仅在自己的计划规则（例如 [External Purchase Program](https://developer.apple.com/documentation/storekit/external-purchase) (Apple) 和 [external offers Program](https://developer.android.com/google/play/billing/externalcontentlinks) (Google Play)）下允许这样做。资格、费用、披露和交易报告因平台、地区和应用而异。在某些地区，您可能只需要很少或不需要这些购买要求。

> **Important:**
>
> Unity 不会代表您执行平台合规性。您有责任确定自己的资格，满足每个平台的技术和政策要求，并根据需要向 Apple 和 Google 报告交易。在对外购买之前，请直接咨询 Apple 和 Google，并查看[预发布条款](./_index.md)。

为了帮助您构建自己的合规性流程，Unity 提供了 SDK 挂钩和 Webhook 数据。本页面将介绍职责分工、合规性步骤所依据的顺序模型以及您可以采取的具体行动。

本页面是[集成直接到消费者 (D2C) 支付提供商工作流程](./workflow.md#platform-compliance-for-external-purchases)的一部分。在添加此处描述的合规性处理之前，请设置您的[支付提供商](./configure-payment-provider.md)和[购买流程](./purchases-sdk.md)。

## 职责分工##division-of-responsibilities

Unity 仅提供技术便利。您的支付提供商充当支付处理、税务和争议的记录商家，但不处理 Apple 或 Google 平台报告。平台合规性是您的责任，Unity 不会将您注册到任何平台计划中。

### Unity 的技术便利##unity's-technical-facilitation

当付款提供商进行购买时，Unity 会代表您打开结帐 URL。默认情况下，它会在设备的外部浏览器中打开。如果选择应用内演示 (`CheckoutPresentationMode.WebView`)，Unity 会改为在应用内浏览器中将其打开。要进一步了解 Unity 如何处理订单，请参阅 [Unity 如何创建和打开订单](#how-unity-creates-and-opens-an-order)。

Unity 不会为您调用 Apple 的外部购买通知或 Google 的外部链接 API，Unity 也不会决定您的资格。您自己调用这些平台 API，如[责任](#your-responsibilities)中所述。

### 您的责任##your-responsibilities

Unity 仅提供技术便利。您负责以下任务：

* 确定您的应用和地区是否符合每个平台的外部购买计划的条件。
* 在购买开始之前，使用 Apple 的 `ExternalPurchaseClient` 和 Google 的 `ExternalBillingProgramClient` 进行您自己的资格和披露检查。
* 使用每个平台自己的 API 获取并报告 Apple 或 Google 所需的任何交易令牌。

## Unity 如何创建和打开订单##how-unity-creates-and-opens-an-order

付款提供商购买时，通常只需调用 `PurchaseProduct(catalogListingId)`，`catalogListingId` 便会在[远程目录](./configure-remote-catalog.md)中识别优惠。购买有两个基本步骤，您可以自己运行第一个步骤：

* `GenerateURL(catalogListingId, tokens)` 会创建订单并返回其签出 URL，而不会将其打开。
* `PurchaseProduct(catalogListingId)` 打开结帐。如果您已经为同一列表调用了 `GenerateURL`，则会重用该顺序。如果没有，则会创建没有令牌的订单本身，然后将其打开。

仅当前期需要 URL（[披露或渲染](#disclose-or-render-the-checkout-url) URL）或需要将[报告令牌附加](#attach-and-report-transaction-tokens)到订单时，才首先需要`GenerateURL`。否则，请直接调用 `PurchaseProduct`。

## 确定合规性流程的需求##decide-what-your-compliance-flow-needs

其余部分是独立的。使用下表查找适用于应用程序和平台的步骤：

| 如果需要                    | 执行此操作                                            | 部分                                                     |
| :---------------------- | :----------------------------------------------- | :----------------------------------------------------- |
| 在应用内强制执行您自己的资格规则        | 注册在每次购买之前运行的合规性回调                                | [通过合规性检查进行门购](#gate-purchases-with-a-compliance-check) |
| 在购买打开之前显示或公开结帐 URL      | 调用 `GenerateURL` 获取 URL，然后`PurchaseProduct` 将其打开 | [显示或渲染签出 URL](#disclose-or-render-the-checkout-url)    |
| 向 Apple 或 Google 报告外部交易 | 使用 `GenerateURL` 附加令牌，然后从订单 Webhook 中读取令牌        | [附加和报告交易令牌](#attach-and-report-transaction-tokens)     |

## 通过合规性检查进行购买##gate-purchases-with-a-compliance-check

此步骤是可选的。仅当在应用内强制执行自己的资格规则时，才添加此属性。

注册合规性回调以在购买进行之前应用您自己的资格规则。调用 `PurchaseProduct`（或 `Purchase`）时，Unity 首先运行回调并传递一个`PaymentProviderComplianceContext`来显示正在购买的`Cart`。如果回调返回 `false`（或抛出），则购买会因 `PurchasingUnavailable` 而失败，并且不会创建订单。

1. 定义一个函数，返回一个`Task<bool>`，指示玩家是否通过了合规性检查：

   ```csharp
   任务<bool> RunComplianceCheckAsync(PaymentProviderComplianceContext 上下文)
   {
       const bool allow = true;
       return Task.FromResult(allow);
   }
   ```

2. 在支付提供商购买服务上注册 函数，以便 Unity 在购买开始时调用 函数：

   ```csharp
   m_PurchasingService.PaymentProviders?.SetComplianceCheck(RunComplianceCheckAsync);
   ```

3. 使用检查中的平台客户端可以调用每个平台所需的 API 以实现合规性：

   * **Apple**：使用 `ExternalPurchaseClient` 访问 Apple 的外部购买 API。
   * **Google**：使用 `ExternalBillingProgramClient` 访问 Google 的外部计费 API。

> **Note:**
>
> 合规性回调仅对 `PurchaseProduct` 和 `Purchase` 运行。`GenerateURL` 不受其控制，会立即创建订单，因此，如果调用 `GenerateURL`（用于披露或令牌），请在调用之前运行资格检查。

## 显示或渲染签出 URL##disclose-or-render-the-checkout-url

平台可能要求您在玩家继续之前显示或公开外部购买 URL，或者您可能希望在自己的 Web 视图中渲染结帐。在这两种情况下，请调用 `GenerateURL` 获取 URL 而不将其打开：

```csharp
string url = await m_PurchasingService.PaymentProviders.GenerateURL(catalogListingId);
// Display or disclose the URL, then call PurchaseProduct to open the checkout.
```

然后，`PurchaseProduct(catalogListingId)` 会重用已创建的顺序`GenerateURL`，而不是创建重复。

> **Note:**
>
> 不要仅为提前准备购买而致电 `GenerateURL`。如果不需要 URL 或令牌，请直接调用 `PurchaseProduct`。它会为您创建和打开订单。冗余`GenerateURL`（尤其是具有遗忘`await`的冗余窗口）只会添加一个竞争窗口。

## 附加和报告交易令牌##attach-and-report-transaction-tokens

Apple 或 Google 要求您报告外部交易时，需要执行此步骤（此步骤因程序和地区而异）。

Apple 和 Google 要求您通过其服务器 API 将每个外部交易报告给他们。您可以从平台获取不透明的交易令牌，将其附加到 Unity 订单，然后在订单 Webhook 中接收该令牌，以便您可以提交报告。您自己生成令牌：Apple 令牌来自 `ExternalPurchaseClient`，而 Google 令牌来自 `ExternalBillingProgramClient`。

`PurchaseProduct` 不接受令牌，因此自行创建订单的购买不会附加令牌。要将令牌添加到订单中，请先调用 `GenerateURL(catalogListingId, tokens)`。然后，同一列表的后续`PurchaseProduct`将采用该令牌顺序：

```csharp
await m_PurchasingService.PaymentProviders.GenerateURL(catalogListingId, tokenList);
m_PurchasingService.PurchaseProduct(catalogListingId);
```

Unity 将令牌与顺序一起存储而不检查或验证令牌，并按顺序将它们呈现在 Webhook 中。它们不会在顺序 API 响应中返回。

> **Note:**
>
> 如果附加报告令牌，则 Webhook 顺序是 Unity 返回令牌的唯一位置。请参阅[配置 Webhook 或 Cloud Code 模块以实现购买](./configure-fulfilment.md)。

### Webhook 有效负载中的令牌##tokens-in-the-webhook-payload

顺序 Webhook 包含一个 `data` 下的 `externalTransactionTokens` 数组。每个条目都带有令牌及其目标商店：

```json
{
  "eventType": "order.paid",
  "data": {
    "id": "...",
    "playerId": "...",
    "status": "paid",
    "externalTransactionTokens": [
      { "store": "apple", "token": "opaque-apple-transaction-token", "type": "acquisition" },
      { "store": "google", "token": "opaque-google-transaction-token" }
    ]
  }
}
```

**store** (string, required): 应用程序存储令牌目标。`apple` 或 `google` 之一。确定报告交易的位置。**token** (string, required): 外部购买或交易令牌。Unity 会存储和转发此信息而不对其进行检查。**type** (string): 仅限 Apple 的令牌类别。`acquisition`、`services` 或 `linkOut` 之一。Google 省略。

> **Note:**
>
> 每个订单最多可以提供两个令牌，因为单个 Apple 外部购买可能需要两种令牌类型，具体取决于地区，例如 `acquisition` 令牌 (EU) 和 `linkOut` 令牌 (Japan)。根据相关程序报告每个令牌。Unity 不会对`type`执行操作。

使用这些令牌可根据每个程序的要求通过 Apple 的外部购买服务器 API 或 Google 的`externalTransactions` API 来自我报告交易。

## 后续步骤##next-steps

本页面是使用 IAP 设置 D2C 支付提供商的工作流程的一部分。要继续此工作流程，请选择以下选项之一：

[Integrate D2C payment providers](./workflow.md#platform-compliance-for-external-purchases): 返回到 Integration D2C payment providers with IAP workflow（将 D2C 支付提供商与 IAP 工作流程集成）页面。
[Fulfill purchases through the SDK](./purchases-sdk.md): 查看这些合规性步骤所依据的正常购买流程。
[Configure a webhook for fulfillment](./configure-fulfilment.md): 配置 Webhook 以接收订单事件，包括外部交易令牌。
