> ## 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.

# 移动推送：通知未显示或延迟

> 排查在 OneSignal 中显示为已送达但未出现或延迟的移动推送通知——适用于 Android 和 iOS 设备。

在您的 OneSignal 仪表板[推送消息报告](./push-notification-message-reports)中：

* **已送达**表示 OneSignal 已成功将通知交给推送服务（FCM、APNs 或 HMS）并收到成功响应。
* **已确认**表示设备上的 OneSignal SDK 已收到通知。

如果您的通知显示为"已送达"但未"已确认"，且未出现在设备上，请从以下步骤开始排查。

***

## 开始之前

收集以下信息以协助排查。您需要这些信息来确认正确的订阅并检查投递状态。

* 您的 [OneSignal App ID](./keys-and-ids)
* 未显示通知的[消息 ID](./push-notification-message-reports)
* 受影响用户的[订阅 ID](./test-users)

<Note>
  如果您只有外部 ID，请在**受众 > 订阅**中通过设备类型、最后会话或 IP 地址筛选来查找订阅。
</Note>

***

## 设备设置

本节适用于所有平台。在排查平台特定或代码层面的原因之前，请先检查这些设置。

### 权限和订阅状态

在设备上：

1. 导航到**设置 > 通知**，打开应用的通知设置。
2. 确认通知权限已启用。
3. 然后打开应用。如果我们的 SDK 初始化，它会将订阅状态同步回 OneSignal。

在您的 OneSignal 仪表板中：

1. 导航到**受众 > 订阅**。
2. 搜索订阅 ID 或外部 ID，或按设备类型、最后会话或 IP 地址排序。
3. 确认推送状态显示为**已订阅**。如果显示未订阅或未出现，无论发送什么内容，设备都不会收到通知。如果状态异常，请参阅下方[故障排除](#故障排除)。

### 请勿打扰和专注模式

Android 和 iOS 上的请勿打扰和专注模式可以完全抑制通知，或以使通知不可见的方式将其分组，直到模式被取消。

在测试之前禁用这些模式：

* **iOS：** 设置 > 专注 > 请勿打扰 > 关闭
* **Android：** 设置 > 通知 > 请勿打扰 > 关闭

禁用后发送测试通知。如果通知出现，则该模式就是原因。

<Note>
  在 iOS 上，如果通知在专注模式下到达，用户滑走分组的通知摘要后，这些通知之后不会单独重新出现。
</Note>

### 低电量模式和电池优化

**iOS**：测试前在设置 > 电池中禁用低电量模式。

**Android 设备**：在电池设置中，将应用设置为"不受限制"或"未优化"。如果没有该选项，请搜索**电池优化**、**省电模式**、**节能**、**后台使用限制**或**自适应电池设置**，并为该应用禁用。

### 网络和连接

设备必须在线才能接收推送通知。如果设备已关闭、处于飞行模式、网络连接不稳定或无网络连接，推送将不会显示，直到建立适当的连接。您可以使用生存时间 (TTL) 参数设置 FCM 和 APNs 等待连接的时间（默认为 3 天）。

如果设备连接了带有防火墙或 VPN 的 WiFi 网络，该网络可能阻止了与 Apple 或 Google 服务器的连接。请尝试切换到移动数据进行测试。

如果您通过防火墙管理网络流量，请将其配置为允许以下连接：

* **FCM（Android）：** 出站 TCP 端口 5228、5229 和 5230。完整要求请参阅 [FCM 文档](https://firebase.google.com/docs/cloud-messaging/concept-options)。
* **APNs（iOS）：** 出站 TCP 端口 5223 以及 TCP 端口 443 或 2197。完整要求请参阅 [Apple 文档](https://support.apple.com/en-us/HT203609)。

### 通知分组行为

不同版本的 Android 和 iOS 有各自的通知分组行为。通知分组是指同一应用或多个应用的几条通知被组合到通知中心。被一起清除的分组通知常常导致用户错过单条通知。

***

## Android 问题

本节仅适用于 Android 设备。如果您正在排查 iOS 问题，请跳至 [iOS 问题](#ios-问题)。

### Android 强制停止

当 Android 应用被强制停止时，操作系统会阻止其接收推送通知，直到用户手动重新打开它。这是 Android 上通知丢失最常见的原因之一。

一些制造商——包括三星、小米和华为——在用户从最近应用列表中滑走应用时会主动强制停止应用，但会对 Gmail 和 WhatsApp 等大型应用豁免。有关设备特定行为，请参阅 [dontkillmyapp.com](https://dontkillmyapp.com/)。

要减少受影响设备上的强制停止行为，请按顺序尝试以下步骤：

1. **允许后台活动**：设置 > 应用 > 您的应用 > 电池 > 允许后台活动。
2. **禁用休眠应用**：设置 > 电池和设备维护 > 电池 > 后台使用限制 > 休眠应用 > 从此列表中移除您的应用。
3. **在最近应用中锁定应用**：打开您的应用，点击最近应用按钮，然后点击并按住应用窗口，选择**锁定此应用**（在某些三星机型上可用）。
4. **启用自动启动**（某些设备）：设置 > 应用 > 您的应用 > 权限 > 自动启动 > 启用。
5. **禁用自适应电池优化**：设置 > 电池和设备维护 > 电池 > 更多电池设置 > 自适应电池 > 关闭（或排除您的应用）。

要检查应用是否已被强制停止，请运行以下命令。将 `com.company.appname` 替换为您的包名：

```bash theme={null}
adb shell dumpsys package com.company.appname | grep stopped
```

`stopped=false` 表示应用未被强制停止。`stopped=true` 表示已被强制停止。

您也可以发送几条通知并检查 logcat 中是否出现以下条目：

```text theme={null}
W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent {
   act=com.google.android.c2dm.intent.RECEIVE pkg=com.onesignal.example (has extras)
}
```

如果看到此取消的 intent，表示应用无法启动来处理通知。

<Note>
  FCM 提供了一个 API 来检查设备上次连接到 FCM 服务器的时间。这可以确认设备是否根本无法访问。有关详细信息，请参阅 [Google 关于应用实例信息的文档](https://developers.google.com/instance-id/reference/server#get_information_about_app_instances)。

  要帮助用户自行解决此问题，请使用应用内消息定向已知 Android 设备用户，提供启用后台活动的说明。请参阅[示例：定向特定 Android 制造商和设备](./example-target-certain-android-manufacturers-and-devices)。
</Note>

### Android 通知类别已禁用

Android 通知类别（也称为渠道）允许用户禁用应用中特定类型的通知。如果某个类别被禁用，使用该类别发送的通知将不会出现在设备上——即使应用拥有通知权限。

在设备上检查类别状态：**设置 > 通知 > 您的应用**。确认"显示通知"已启用，且所有类别均已开启。

<Frame caption="Android 应用通知设置显示 放弃购物车 - 紧急 类别已关闭，这会阻止该类别的通知出现在设备上。">
  <img src="https://mintcdn.com/onesignal/jFWn5xzleD8du3j6/images/docs/5a83479-Screen_Shot_2021-07-29_at_7.47.11_AM.png?fit=max&auto=format&n=jFWn5xzleD8du3j6&q=85&s=7f6d3cc24cda04f807e1c9840895c22b" alt="Android 应用通知设置显示 放弃购物车 - 紧急 类别已关闭，这会阻止该类别的通知出现在设备上。" width="800" height="650" data-path="images/docs/5a83479-Screen_Shot_2021-07-29_at_7.47.11_AM.png" />
</Frame>

如果通知未设置类别，OneSignal 使用默认的"杂项"类别。如果您不使用自定义类别，请确认此类别已启用。有关设置详情，请参阅 [Android 通知类别](./android-notification-categories)。

<Warning>
  三星 One UI 6.1 会自动禁用许多应用的通知类别。如果您的用户使用三星设备且最近停止接收某些通知，这很可能是原因。有关详情，请参阅 [Android Police 的报道](https://www.androidpolice.com/one-ui-61-disables-notification-channels/)。
</Warning>

<Note>
  您可以使用应用内消息定向三星用户，提供重新启用类别的说明。请参阅[示例：定向特定 Android 制造商和设备](./example-target-certain-android-manufacturers-and-devices)。
</Note>

### Android 休眠模式、优先级和降级消息

Android 的[休眠模式](https://developer.android.com/training/monitoring-device-state/doze-standby)和[应用待机](https://developer.android.com/training/monitoring-device-state/doze-standby#understand_app_standby)功能会在设备断电并静止时延迟后台进程——包括推送投递。这些模式会自动激活，用户不可见。

发送[高优先级](./push#priority)消息将唤醒设备并绕过休眠模式。但是，如果发送过多不能产生可见通知的高优先级消息，FCM 可能会自动将您的消息降级为普通优先级。来自 [FCM 文档](https://firebase.google.com/docs/cloud-messaging/android/message-priority)：

> Android 上的高优先级消息旨在处理时间敏感、用户可见的内容。如果 FCM 检测到消息未导致用户可见通知的模式，您的消息可能会被降级为普通优先级。

如果您怀疑存在降级问题，请将高优先级使用限制在仅时间敏感的消息上。

### Android 模拟器设置

Android 模拟器上的推送通知需要 Google Play 服务。如果您在模拟器上测试但未收到通知，请确认以下几点：

1. 模拟器镜像包含 Google Play 商店
2. 模拟器配置为使用冷启动

设置冷启动：打开 Android Studio 设备管理器 > 选择您的设备 > 编辑 > 其他设置 > 将启动选项设置为冷启动 > 保存并重启。

***

## iOS 问题

本节仅适用于 iOS 设备。如果您正在排查 Android 问题，请参阅 [Android 问题](#android-问题)。

### APNs 通知合并

如果在 iOS 设备离线或不可达时发送了多条通知，设备重新连接后可能只显示最新的一条。APNs 在设备离线期间每个应用仅存储一条通知，并丢弃之前的通知。这是预期的 [APNs 行为](https://developer.apple.com/documentation/usernotifications/sending-notification-requests-to-apns)，OneSignal 或您的应用无法更改。

### iOS 前台阻止

如果您设置了 [iOS UNUserNotificationCenterDelegate](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate)，您的代码可能会阻止应用在前台时显示通知。

请移除此自定义代码，改为使用我们的 SDK [前台事件监听器](./mobile-sdk-reference#addforegroundlifecyclelistener-push)。

### iOS 徽章清除

当应用清除其徽章计数时，iOS 会从通知中心移除该应用的所有通知。OneSignal SDK 会在应用打开时自动清除徽章，这意味着之前投递的通知可能会在用户下次打开应用时消失。

如果这在测试中造成混淆，请参阅[徽章](./badges)了解如何控制此行为。

***

## 消息配置

本节涉及由 OneSignal 中通知配置方式引起的问题，而非设备问题。

### 订阅不在目标受众中

检查消息受众以确认您的移动订阅已包含在内：

* **[细分](./segmentation)**：确认您的订阅满足所有受众筛选条件。
* **直接发送**：确认您定向的 ID 正确：
  * 该订阅仍订阅了推送。
  * 它有最近的最后会话日期——您可能正在向旧的或非活跃的订阅发送消息。

### 折叠 ID 替换通知

如果您在消息上设置了折叠 ID，具有相同折叠 ID 的新通知将静默替换任何未读的同 ID 通知。如果用户未打开之前的通知，他们只会看到最新的通知。有关折叠 ID 工作原理的详细信息，请参阅[移除通知和 TTL](./push)。

***

## 代码层面的原因

本节需要访问应用的源代码。如果您没有代码访问权限，请将这些检查项分享给您的开发团队。

### OneSignal 前台通知阻止

OneSignal SDK 的[前台事件监听器](./mobile-sdk-reference#addforegroundlifecyclelistener-push)包含一个 `event.preventDefault()` 方法，当应用在前台时会抑制通知。如果此方法在您的代码中被无条件调用，所有前台通知都将被静默阻止。

测试时，将应用保持在后台或完全关闭，以排除前台抑制作为原因。

### Android 通知服务扩展

如果您实现了 [Android 通知服务扩展](./service-extensions)，这是通知进入应用的第一个入口点。如果在此扩展中调用了 `event.preventDefault()`，无论应用状态如何，通知都将被阻止。请检查扩展代码，确认此方法仅在有意为之时调用。

### Firebase Messaging SDK 冲突

如果您的应用还集成了 Firebase Messaging SDK，请确认它没有在 OneSignal 处理 FCM 消息之前拦截这些消息。

此问题常见于以下情况：

* 通知在 OneSignal 中显示为**已投递**，但从未出现在设备上。
* 应用同时包含 OneSignal 和 `firebase_messaging`（或自定义 `FirebaseMessagingService`）。
* 移除 Firebase Messaging 后推送正常，但两个 SDK 同时存在时失败。

1. 检查您的 `AndroidManifest.xml` 是否有旧版 Firebase 接收器，例如 `com.google.firebase.iid.FirebaseInstanceIdReceiver`，如果 OneSignal 负责推送投递，请移除或有条件地排除它们。

2. 检查是否有覆盖 `onMessageReceived` 的自定义 `FirebaseMessagingService` 实现（或 Flutter 中的 `firebase_messaging` 等库）。如果另一个服务完全处理或抑制消息，它可能会在 OneSignal 显示通知之前消费 FCM 有效载荷。

3. 避免调用 Firebase 令牌管理 API，例如：`FirebaseMessaging.getToken()` 或 `FirebaseMessaging.deleteToken()`。

如果 OneSignal 负责推送投递，则它应该是唯一管理推送令牌生命周期的 SDK。直接获取或管理 FCM 令牌可能导致令牌所有权冲突和投递行为不一致。

如果您需要为其他系统获取设备推送令牌，请从 OneSignal 读取（例如，`User.pushSubscription.token`），并使用 [SDK 的观察者 API](./mobile-sdk-reference#addobserver-push-subscription-changes) 监听订阅/令牌变更。

***

## 故障排除

如果您已完成以上各节的排查但问题仍未解决，请捕获调试日志。这是确定投递失败位置最快的方法。

按照[获取调试日志](./capturing-a-debug-log)在应用中启用详细日志记录。然后：

1. 将应用置于后台
2. 向受影响的设备发送测试通知
3. 检查日志中的任何错误。确认您能看到 OneSignal 已初始化，且日志中的 `subscription-id` 已订阅推送，且与您发送消息的订阅 ID 相同。

***

<Info>
  需要帮助？

  请发送邮件至 `support@onesignal.com` 联系我们的支持团队

  请提供：

  * 您的 OneSignal App ID
  * 订阅 ID 或外部 ID
  * 您在 OneSignal 仪表板中测试的消息链接
  * 来自[获取调试日志](./capturing-a-debug-log)的完整调试日志

  我们很乐意提供帮助！
</Info>
