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

# VoIP 推送通知

> 使用 OneSignal 在 iOS 上通过 PushKit 令牌注册和 VoIP 证书发送 VoIP 推送通知，以及 Android 上模拟通话行为的替代方案。

VoIP 推送通知让您的应用即使在后台或已终止时也能接收来电提醒。Apple 对 VoIP 推送的处理方式与标准推送通知不同——它们使用独立的证书类型、独立的令牌（通过 PushKit），以及不同的传递规则。

OneSignal 支持**发送** VoIP 推送，但 OneSignal SDK **不**处理 VoIP 令牌注册。您需要负责：

* 在应用中使用 Apple PushKit 注册 VoIP 令牌
* 创建一个使用 VoIP Services 证书的专用 OneSignal 应用
* 通过 OneSignal REST API 注册令牌并发送推送

### 平台差异

| 平台          | 是否支持 VoIP 推送 | 工作原理                            |
| ----------- | ------------ | ------------------------------- |
| **iOS**     | Yes          | 使用 Apple PushKit 和 VoIP APNs 证书 |
| **Android** | No           | 使用纯数据推送模拟通话样式行为                 |

如果您正在构建跨平台通话应用，则需要针对不同平台使用不同的方法。

***

## iOS：发送 VoIP 推送通知

在 iOS 上，VoIP 通知使用 Apple PushKit，并遵循与标准推送通知不同的特殊传递规则。由于 Apple 对 VoIP 推送的处理方式不同，OneSignal 需要为 VoIP 使用单独的应用配置。

<Warning>
  **开始之前** — 以下是最常见的 VoIP 设置错误：

  1. **未为 VoIP 创建独立的 OneSignal 应用。** Apple 要求 VoIP 使用不同的证书类型，因此 OneSignal 需要一个专用应用来发送 VoIP 推送。您现有的推送应用不能同时用于两者。
  2. **上传了错误的证书。** 您需要 **VoIP Services 证书（.p12）**，而不是标准的 APNs 推送证书。使用错误的证书会导致静默传递失败。
  3. **在沙盒环境中忘记填写 `test_type`。** 使用开发构建进行测试时，注册令牌时必须包含 `"test_type": 1`。不包含此字段时，API 调用会成功，但推送始终无法送达。
</Warning>

<Steps>
  <Step title="使用 PushKit 注册 VoIP 令牌">
    使用 Apple 的 PushKit 框架注册 VoIP 通知并获取 VoIP 令牌。

    * 在您的应用中实现 PushKit
    * 在 Apple 轮换时存储并刷新 VoIP 令牌
    * 严格遵守 Apple 的 VoIP 策略

    <Accordion title="示例：PushKit 委托实现">
      ```swift theme={null}
      import PushKit

      class AppDelegate: NSObject, PKPushRegistryDelegate {
          func registerForVoIPPushes() {
              let registry = PKPushRegistry(queue: .main)
              registry.delegate = self
              registry.desiredPushTypes = [.voIP]
          }

          func pushRegistry(_ registry: PKPushRegistry, didUpdatePushCredentials credentials: PKPushCredentials, for type: PKPushType) {
              let token = credentials.token.map { String(format: "%02x", $0) }.joined()
              // Pass this token to OneSignal — see Step 4
          }
      }
      ```

      <Note>这是标准的 Apple PushKit 代码。OneSignal 不提供 PushKit SDK——您需要自行注册令牌，然后在第 4 步将其传递给 OneSignal。</Note>
    </Accordion>

    Apple 资源：

    * [PushKit 文档](https://developer.apple.com/documentation/pushkit)
    * [响应 VoIP 推送](https://developer.apple.com/documentation/pushkit/responding_to_voip_notifications_from_pushkit)
    * [Apple 的 VoIP 最佳实践](https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/OptimizeVoIP.html)
  </Step>

  <Step title="为 VoIP 创建独立的 OneSignal 应用">
    Apple VoIP 推送需要与标准推送通知不同的证书类型。单个 OneSignal 应用只能使用一种证书类型，因此您必须创建**两个独立的 OneSignal 应用**：

    * **主推送应用**：使用 APNs 证书处理标准推送通知
    * **VoIP 推送应用**：使用 VoIP Services 证书专门处理 VoIP 通知

    两个应用都必须使用相同的 iOS Bundle ID，并与同一原生 iOS 应用关联。您**无需**初始化 OneSignal SDK 两次——VoIP 应用仅在服务端通过 API 发送 VoIP 推送时使用。

    <Note>Bundle ID（例如 `com.yourcompany.appname`）可在 Xcode 中您的 target 的 **General** 选项卡下找到。</Note>
  </Step>

  <Step title="上传 VoIP Services 证书">
    在您的 VoIP OneSignal 应用中，上传 **VoIP Services 证书（.p12）**。这与您用于常规通知的标准 APNs 推送证书是不同的证书类型。

    创建步骤：

    1. 前往 [Apple Developer Portal](https://developer.apple.com/account/resources/certificates/add)
    2. 选择 **VoIP Services Certificate**
    3. 按照提示生成并下载证书
    4. 在"钥匙串访问"中打开并将其导出为 `.p12` 文件
    5. 将 `.p12` 文件上传至您的 VoIP OneSignal 应用的 iOS 设置中

    <Warning>
      **不要**将标准 APNs 推送证书上传到 VoIP 应用。如果使用了错误的证书类型，API 会接受您的推送请求，但 Apple 会拒绝它，通知将永远无法送达。
    </Warning>

    <Frame caption="钥匙串访问中的 VoIP 证书">
      <img src="https://mintcdn.com/onesignal/jFWn5xzleD8du3j6/images/docs/6101554-Screen_Shot_2020-04-26_at_1.07.52_PM.png?fit=max&auto=format&n=jFWn5xzleD8du3j6&q=85&s=5d19f1262fdf67d5185ed8d8b4743493" alt="macOS 钥匙串访问中显示的 VoIP Services 证书" width="1868" height="1624" data-path="images/docs/6101554-Screen_Shot_2020-04-26_at_1.07.52_PM.png" />
    </Frame>

    <Frame caption="在 OneSignal 仪表板中上传的 VoIP 证书">
      <img src="https://mintcdn.com/onesignal/0qspEXXeJ8zJbkJ-/images/docs/81a2fea-a2a2e71-Screenshot_2024-02-23_at_1.32.08_PM.png?fit=max&auto=format&n=0qspEXXeJ8zJbkJ-&q=85&s=6ee92a10fc3473c644880fa7517eb46b" alt="在 OneSignal 仪表板中上传的 VoIP Services 证书" width="466" height="130" data-path="images/docs/81a2fea-a2a2e71-Screenshot_2024-02-23_at_1.32.08_PM.png" />
    </Frame>
  </Step>

  <Step title="向 OneSignal 注册 VoIP 令牌">
    使用 [Create User](/reference/create-user) API 将 VoIP 令牌注册到您的 VoIP OneSignal 应用。

    <Warning>
      **沙盒/开发构建需要填写 `"test_type": 1`。** 如果省略此字段，API 调用会成功且不返回任何错误，但 Apple 会将该令牌视为生产令牌并静默拒绝所有发送至该令牌的推送。
    </Warning>

    ```curl theme={null}
    curl --request POST \
         --url https://api.onesignal.com/apps/YOUR_VOIP_APP_ID/users \
         --header 'accept: application/json' \
         --header 'content-type: application/json' \
         --data '
    {
      "subscriptions": [
        {
          "type": "iOSPush",
          "token": "YOUR_VOIP_TOKEN",
          "test_type": 1
        }
      ]
    }
    '
    ```

    <Note>有效的 VoIP 令牌是 64 个字符的小写十六进制字符串（例如 `a1b2c3d4e5f6...`）。PushKit 在 iOS 模拟器上无法使用——您必须使用真实设备才能获取有效令牌。</Note>

    如需稍后更新令牌，请使用 [Update Subscription](/reference/update-subscription) API。
  </Step>

  <Step title="发送 VoIP 通知">
    使用 [Create Notification](/reference/create-message) API 并包含以下参数：

    * `"apns_push_type_override": "voip"` — 告知 Apple 这是 VoIP 推送
    * `app_id` — 您的 VoIP 应用 ID
    * `include_subscription_ids` — 您注册的 VoIP 订阅 ID
    * `contents` 或 `content_available` 二选一，必须填写

    ```curl theme={null}
    curl --include \
         --request POST \
         --header "Content-Type: application/json; charset=utf-8" \
         --header "Authorization: key YOUR_REST_API_KEY" \
         --data-binary '{
      "app_id": "YOUR_VOIP_APP_ID",
      "content_available": true,
      "data": {
        "your_custom_data": "your_custom_value"
      },
      "apns_push_type_override": "voip",
      "include_subscription_ids": ["YOUR_VOIP_SUBSCRIPTION_ID"]
    }' \
    https://api.onesignal.com/notifications
    ```
  </Step>

  <Step title="验证您的 VoIP 设置">
    如果满足以下条件，则说明您的 iOS VoIP 集成运行正常：

    1. VoIP 令牌在您的 **VoIP 应用**中显示为 iOS 推送订阅
    2. VoIP 推送触发了应用中的 [`pushRegistry(_:didReceiveIncomingPushWith:for:completion:)`](https://developer.apple.com/documentation/pushkit/responding_to_voip_notifications_from_pushkit)
    3. 即使应用已终止或在后台运行，也能被唤醒
  </Step>
</Steps>

***

## Android：模拟 VoIP 样式行为

Android 不支持 VoIP 推送通知，没有与 Apple PushKit 等效的功能。

Android 通话应用使用以下方式模拟 VoIP 行为：

* 纯数据推送通知
* 前台服务
* 自定义通话样式 UI

您可以将 OneSignal 的常规 Android 推送支持与原生 Android API 结合使用来实现此功能。

**推荐方法：**

* 发送纯数据通知
* 在您的应用中处理它们以：
  * 启动前台服务
  * 启动通话 UI 活动
  * 显示自定义来电通知

如果您想拦截并完全控制通知呈现，请使用 Android 的[通知服务扩展](./service-extensions#notification-service-extension)。

**有用的资源：**

* [Android 通话应用指南](https://developer.android.com/guide/topics/connectivity/telecom/selfManaged)
* [来电 UI 示例](https://medium.com/@dcostalloyd90/show-incoming-voip-call-notification-and-open-activity-for-android-os-10-5aada2d4c1e4)

<Info>Android 设置**并非 OneSignal 特定的**。OneSignal 仅传递推送负载；您的应用负责处理通话行为。</Info>

***

## 常见问题

### 确认送达功能是否适用于 VoIP？

不适用。VoIP 推送**不会跟踪**[确认送达](./confirmed-delivery)。确认送达依赖于通知服务扩展，而通知服务扩展不会为 VoIP 通知触发。

请通过原生 iOS PushKit 事件来跟踪接收情况：

```swift theme={null}
pushRegistry(_:didReceiveIncomingPushWith:for:completion:)
```

此事件是主应用 target 的一部分，不需要单独的扩展。详情请参阅 [Apple 的 VoIP 文档](https://developer.apple.com/documentation/pushkit/responding_to_voip_notifications_from_pushkit#3377587)。

### 能否从 OneSignal 仪表板发送 VoIP 通知？

不能。VoIP 通知必须通过 [Create Notification](/reference/create-message) API 并携带 `"apns_push_type_override": "voip"` 参数来发送。仪表板不支持此参数。

### 为什么我的 VoIP 推送静默失败？

VoIP 推送可能在 OneSignal API 不返回任何错误的情况下失败。请逐一检查以下清单：

1. **您使用的是沙盒/开发构建吗？** 通过 Create User API 注册令牌时，必须包含 `"test_type": 1`。不包含此字段时，令牌会被注册为生产令牌，Apple 会拒绝推送并静默失败。
2. **您上传了正确的证书吗？** VoIP OneSignal 应用必须使用 **VoIP Services 证书（.p12）**，而非标准 APNs 推送证书。两者在"钥匙串访问"中看起来相似——请确认证书名称以"VoIP Services"开头。
3. **您是否向正确的 OneSignal 应用发送？** 发送请求中的 `app_id` 必须是您的 **VoIP 应用**，而非主推送应用。`REST API Key` 也必须来自 VoIP 应用。
4. **VoIP 令牌是否有效？** 重新安装应用或恢复设备后令牌会过期。请确认令牌是 64 个字符的小写十六进制字符串，且是近期注册的。
5. **您的应用是否调用了 `reportNewIncomingVoIPPushPayload`？** 从 iOS 13 开始，Apple 会**终止**收到 VoIP 推送但未向 CallKit 报告通话的应用。这是 Apple 的要求，而非 OneSignal 的限制。

***

## 相关页面

<Columns cols={2}>
  <Card title="创建消息 API" icon="code" href="/reference/create-message">
    使用 REST API 以编程方式发送推送通知。
  </Card>

  <Card title="确认送达" icon="circle-check" href="./confirmed-delivery">
    在支持的平台上跟踪推送通知的送达确认。
  </Card>

  <Card title="服务扩展" icon="puzzle-piece" href="./service-extensions">
    使用通知服务扩展自定义通知处理。
  </Card>

  <Card title="Create User API" icon="user-plus" href="/reference/create-user">
    通过 OneSignal API 注册用户和订阅。
  </Card>
</Columns>
