首页指南参考教程

使用 Expo 的 Push API 发送通知

了解当你想要发送通知时如何使用令牌调用 Expo 的 Push API。


expo-notifications 库提供推送通知的所有客户端功能。Expo 还负责将这些通知发送到 FCM 和 APN。你所需要做的就是使用你在上一步中获取的 ExpoPushToken 将请求发送到 Expo 的 Push API。

¥The expo-notifications library provides all the client-side functionality for push notifications. Expo also handles sending these notifications off to FCM and APNs. All you need to do is send the request to the Expo's Push API with the ExpoPushToken you grabbed in the last step.

如果你希望构建直接与 APN 和 FCM 通信的服务器,请参阅 使用 FCM 和 APN 发送通知。它比使用 Expo 的推送通知服务更复杂。

¥If you'd rather build a server that communicates with APNs and FCM directly, see Send notifications with FCM and APNs. It's more complicated than using Expo's push notification service.

使用服务器发送推送通知

¥Send push notifications using a server

设置推送通知凭据并添加逻辑以获取 ExpoPushToken 后,你可以使用 HTTPS POST 请求将其发送到 Expo API。你可以通过设置带有数据库的服务器来完成此操作(或者你也可以编写命令行工具来发送它们或直接从你的应用发送它们)。

¥After you setup your push notification credentials and add logic to get the ExpoPushToken, you can send it to the Expo API using an HTTPS POST request. You can do this by setting up a server with a database (or you can also write a command line tool to send them or send them straight from your app).

Expo 团队和社区已经用几种不同的语言为你创建了后端:

¥The Expo team and community have taken care of creating back-ends for you in a few different languages:

SDKs后端维护者
expo-server-sdk-nodeNode.jsExpo 团队
expo-server-sdk-pythonPython社区
expo-server-sdk-rubyRuby社区
expo-push-notification-client-rustRust社区
expo-notifier交响乐团交响乐团
exponent-server-sdk-phpPHP社区
expo-server-sdk-phpPHP社区
exponent-server-sdk-golangGolang社区
exponent-server-sdk-elixir灵丹妙药社区
expo-server-sdk-dotnetdotnet社区
expo-server-sdk-javaJava社区
laravel-expo-notifier拉维尔社区

上面的每个示例服务器都是 Expo 的 Push API 的封装器。

¥Each of the example servers above is a wrapper around Expo's Push API.

可靠地实现推送通知

¥Implement push notifications reliably

推送通知通过多个系统从服务器传输到接收设备。大部分时间都会发送通知。但是,偶尔会出现系统及其之间的网络连接问题。处理中断和错误将有助于推送通知更可靠地到达目的地。

¥Push Notifications travel through several systems from your server to recipient devices. Notifications are delivered most of the time. However, occasionally there are issues with systems along the way and the network connections between them. Handling outages and errors will help push notifications to arrive at their destinations more reliably.

限制并发连接数

¥Limit concurrent connections

一次发送大量推送通知时,请限制并发连接数。节点 SDK 为你实现了这一点,并打开最多六个并发连接。这可以缓解你的峰值负载,并帮助 Expo 推送通知服务成功接收推送通知。

¥When sending a large number of push notifications at once, limit the number of your concurrent connections. The Node SDK implements this for you and opens a maximum of six concurrent connections. This smooths out your peak load and helps the Expo push notification service receive push notifications successfully.

失败重试

¥Retry on failure

发送推送通知的第一步是将它们传送到 Expo 推送通知服务,该服务在内部将它们添加到队列中,以便传送到 Google (FCM)、Apple (APNs) 或其他推送通知提供商。第一步可能会因以下几个原因而失败:

¥The first step of sending push notifications is to deliver them to the Expo push notification service, which internally adds them to a queue for delivery to Google (FCM), Apple (APNs), or other push notification providers. This first step can fail for several reasons:

  • 你的服务器和 Expo 推送通知服务之间的网络问题

    ¥network issues between your server and the Expo push notification service

  • Expo 通知服务中断或可用性下降

    ¥an outage or degraded availability of the Expo notification service

  • 推送凭据配置错误

    ¥misconfigured push credentials

  • 无效的通知负载

    ¥an invalid notification payload

其中一些失败是暂时的。例如,如果 Expo 推送通知服务已关闭或无法访问,并且你收到网络错误、HTTP 429 错误(请求过多)或 HTTP 5xx 错误(服务器错误),请使用 指数退避 等待几秒钟,然后重试。如果第一次重试尝试不成功,请等待更长时间(遵循指数退避),然后重试。这可以让暂时不可用的服务在你重试之前恢复。

¥Some of these failures are temporary. For example, if the Expo push notification service is down or unreachable and you get a network error, an HTTP 429 error (Too Many Requests), or an HTTP 5xx error (Server Errors), use exponential backoff to wait a few seconds before retrying. If the first retry attempt is unsuccessful, wait for longer (follow exponential backoff) and retry again. This lets the temporarily unavailable service recover before you retry.

其他故障不会自行解决。例如,如果你的推送通知负载格式错误,你可能会收到 HTTP 400 响应,解释负载的问题。如果你的项目没有推送凭据,或者你在同一请求中发送不同项目的推送通知,你也会收到错误消息。

¥Other failures will not resolve themselves. For example, if your push notification payload is malformed, you may get an HTTP 400 response explaining the issue with the payload. You will also get an error if there are no push credentials for your project or if you send push notifications for different projects in the same request.

检查推送收据是否有错误

¥Check push receipts for errors

成功接收通知后,Expo 推送通知服务会响应 推票。推送票证表明 Expo 已收到你的通知负载,但可能仍需要发送。每个推送票证都包含一个票证 ID,稍后你可以使用该 ID 来查找 推送收据。Expo 尝试将通知传递给 FCM、APN 等后,即可获得推送收据。它告诉你是否已成功发送到推送通知提供商。

¥The Expo push notification service responds with push tickets upon successfully receiving notifications. A push ticket indicates that Expo has received your notification payload but may still need to send it. Each push ticket contains a ticket ID, which you later use to look up a push receipt. A push receipt is available after Expo has tried to deliver the notification to FCM, APNs, and so on. It tells you whether delivery to the push notification provider was successful.

你必须检查你的推送收据。如果推送通知出现问题,推送收据是获取根本原因信息的最佳方式。例如,收据可能表明 FCM 或 APN、Expo 推送通知服务或你的通知负载存在问题。

¥You must check your push receipts. If there is an issue delivering push notifications, the push receipts are the best way to get information about the underlying cause. For example, the receipts may indicate a problem with FCMs or APNs, the Expo push notification service, or your notification payload.

如果 APNs 或 FCM 等推送通知提供商以该信息进行响应,则推送收据还可以告诉你接收方设备是否已取消订阅通知(例如,通过撤销通知权限或卸载你的应用)。推送收据将包含设置为 DeviceNotRegistereddetailserror 字段。在这种情况下,请停止向该设备的推送令牌发送通知,直到它重新注册到你的服务器,这样你的应用仍然是一个好公民。仅当 Apple、Google 或其他推送通知提供商认为设备未注册时,推送收据中才会出现 DeviceNotRegistered 错误。这需要不确定的时间,并且通常无法通过卸载应用并在不久后发送推送通知来进行测试。

¥Push receipts may also tell you if a recipient device has unsubscribed from notifications (for example, by revoking notification permissions or uninstalling your app) if the push notification provider like APNs or FCM responds with that information. The push receipt will contain a detailserror field set to DeviceNotRegistered. In this scenario, stop sending notifications to this device's push token until it re-registers with your server, so your app remains a good citizen. The DeviceNotRegistered error appears in push receipts only when Apple, Google, or another push notification provider deems the device to be unregistered. It takes an undefined amount of time and is often impossible to test by uninstalling your app and sending a push notification shortly after.

我们建议你在发送推送通知 15 分钟后检查推送收据。虽然推送收据通常可以更快获得,但 15 分钟的窗口期为 Expo 推送通知服务提供了足够的时间来向你提供收据。如果 15 分钟后没有推送回执,则可能表示 Expo 推送通知服务出现错误。最后,推送收据将在 24 小时后清除。

¥We recommend checking push receipts 15 minutes after sending your push notifications. While push receipts are often available much sooner, a 15-minute window gives the Expo push notification service a comfortable amount of time to make the receipts available to you. If after 15 minutes there is no push receipt, this likely indicates an error with the Expo push notification service. Lastly, push receipts are cleared after 24 hours.

SLAs

Expo 推送通知服务没有 SLA,FCM 和 APNs 服务也可能偶尔出现中断。通过遵循上述指导,你可以使你的应用能够抵御临时服务中断。

¥The Expo push notification service does not have an SLA and the FCM and APNs services also may have occasional outages. By following the guidance above, you can make your application robust against temporary service interruptions.

HTTP/2 API

你可能希望直接向我们的 HTTP/2 API 发送请求(此 API 目前不需要任何身份验证),而不是使用前面列出的库之一。

¥Instead of using one of the libraries listed earlier, you may want to send requests directly to our HTTP/2 API (this API currently does not require any authentication).

为此,请使用以下 HTTP 标头向 https://exp.host/--/api/v2/push/send 发送 POST 请求:

¥To do so, send a POST request to https://exp.host/--/api/v2/push/send with the following HTTP headers:

host: exp.host
accept: application/json
accept-encoding: gzip, deflate
content-type: application/json

这是使用 cURL 的 "你好世界" 推送通知,你可以使用 CLI 发送该通知(将占位符推送令牌替换为你自己的):

¥This is a "hello world" push notification using cURL that you can send using your CLI (replace the placeholder push token with your own):

curl -H "Content-Type: application/json" -X POST "https://exp.host/--/api/v2/push/send" -d '{
  "to": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
  "title":"hello",
  "body": "world"
}'

请求正文必须是 JSON。它可以是单个 消息对象(如上例所示),也可以是最多 100 个消息对象的数组,只要它们都用于同一项目,如下所示。当你想要发送多条消息时,我们建议你使用数组,以有效地减少需要向 Expo 服务器发出的请求数量。以下是发送四条消息的请求正文示例:

¥The request body must be JSON. It may either be a single message object (as shown in the example above) or an array of up to 100 message objects, as long as they are all for the same project as shown below. We recommend using an array when you want to send multiple messages to efficiently minimize the number of requests you need to make to Expo servers. Here's an example request body that sends four messages:

[
  {
    "to": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
    "sound": "default",
    "body": "Hello world!"
  },
  {
    "to": "ExponentPushToken[yyyyyyyyyyyyyyyyyyyyyy]",
    "badge": 1,
    "body": "You've got mail"
  },
  {
    "to": [
      "ExponentPushToken[zzzzzzzzzzzzzzzzzzzzzz]",
      "ExponentPushToken[aaaaaaaaaaaaaaaaaaaaaa]"
    ],
    "body": "Breaking news!"
  }
]

Expo 服务器还可以选择接受 gzip 压缩的请求主体。这可以大大减少发送大量通知所需的上传带宽量。节点 Expo 服务器 SDK 会自动为你压缩请求并自动限制你的请求以平滑负载,因此我们强烈推荐它。

¥The Expo server also optionally accepts gzip-compressed request bodies. This can greatly reduce the amount of upload bandwidth needed to send large numbers of notifications. The Node Expo Server SDK automatically gzips requests for you and automatically throttles your requests to smooth out the load, so we highly recommend it.

推票

¥Push tickets

上述请求将使用带有两个可选字段 dataerrors 的 JSON 对象进行响应。data 将包含一个 推票 数组,其顺序与消息发送的顺序相同(或者一个推送票据对象,如果你向单个收件人发送一条消息)。每张票证都包含一个 status 字段,指示 Expo 是否成功收到通知,如果成功,还包含一个 id 字段,可用于稍后检索推送收据。

¥The requests above will respond with a JSON object with two optional fields, data and errors. data will contain an array of push tickets in the same order in which the messages were sent (or one push ticket object, if you send a single message to a single recipient). Each ticket includes a status field indicating whether Expo successfully received the notification and, if successful, an id field that can be used to retrieve a push receipt later.

状态 ok 和收据 ID 意味着该消息是由 Expo 的服务器接收的,而不是由用户接收的(为此,你需要检查 推送收据)。

¥A status of ok along with a receipt ID means that the message was received by Expo's servers, not that it was received by the user (for that you will need to check the push receipt).

继续上面的示例,成功的响应正文如下所示:

¥Continuing the above example, this is what a successful response body looks like:

{
  "data": [
    { "status": "ok", "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" },
    { "status": "ok", "id": "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY" },
    { "status": "ok", "id": "ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ" },
    { "status": "ok", "id": "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" }
  ]
}

如果个别消息有错误,但不是整个请求有错误,则错误消息对应的推送票证的状态将为 error,并且描述错误的字段如下所示:

¥If there were errors with individual messages, but not the entire request, the bad messages' corresponding push tickets will have a status of error, and fields that describe the error as shown below:

{
  "data": [
    {
      "status": "error",
      "message": "\"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]\" is not a registered push notification recipient",
      "details": {
        "error": "DeviceNotRegistered"
      }
    },
    {
      "status": "ok",
      "id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
    }
  ]
}

如果整个请求失败,HTTP 状态代码将为 4xx 或 5xx,errors 字段将是一组错误对象(通常只有一个)。否则,HTTP 状态代码将为 200,并且你的消息将发送至 Android 和 iOS 推送通知服务。

¥If the entire request failed, the HTTP status code will be 4xx or 5xx and the errors field will be an array of error objects (usually just one). Otherwise, the HTTP status code will be 200 and your messages will be on their way to the Android and iOS push notification services.

推送收据

¥Push receipts

收到一批通知后,Expo 将每个通知放入队列以传送到 Android 和 iOS 推送通知服务(分别为 FCM 和 APN)。大多数通知通常会在几秒钟内发送。然而,有时可能需要更长的时间来发送通知,特别是如果 Android 或 iOS 推送通知服务需要比平常更长的时间来接收和发送通知,或者 Expo 的云基础设施负载较高。

¥After receiving a batch of notifications, Expo enqueues each notification to deliver to the Android and iOS push notification services (FCM and APNs, respectively). Most notifications are typically delivered within a few seconds. However, sometimes it may take longer to deliver notifications, particularly if the Android or iOS push notification services take longer than usual to receive and deliver notifications or if Expo's cloud infrastructure is under high load.

一旦 Expo 将通知发送到 Android 或 iOS 推送通知服务,Expo 就会创建一个 推送收据 来指示 Android 或 iOS 推送通知服务是否成功接收到该通知。如果在发送通知时出现错误(可能是由于凭据错误或服务停机),推送回执将包含有关该错误的更多信息。

¥Once Expo delivers a notification to the Android or iOS push notification service, Expo creates a push receipt that indicates whether the Android or iOS push notification service successfully received the notification. If there was an error in delivering the notification, perhaps due to faulty credentials or service downtime, the push receipt will contain more information regarding that error.

要获取推送收据,请向 https://exp.host/--/api/v2/push/getReceipts 发送 POST 请求。请求正文 必须是一个 JSON 对象,其字段名称 ids 是票证 ID 字符串的数组:

¥To fetch the push receipts, send a POST request to https://exp.host/--/api/v2/push/getReceipts. The request body must be a JSON object with a field name ids that is an array of ticket ID strings:

curl -H "Content-Type: application/json" -X POST "https://exp.host/--/api/v2/push/getReceipts" -d '{
  "ids": [
    "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY",
    "ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ"
  ]
}'

推送收据的 响应体 与推送票据的 响应体 非常相似;它是一个 JSON 对象,具有两个可选字段 dataerrorsdata 包含收据 ID 到收据的映射。收据包括一个 status 字段以及两个可选的 messagedetails 字段(在 "status": "error" 的情况下)。如果所请求的收据 ID 没有推送收据,则映射将不包含该 ID。对上述请求的成功响应如下所示:

¥The response body for push receipts is very similar to that of push tickets; it is a JSON object with two optional fields, data and errors. data contains a mapping of receipt IDs to receipts. Receipts include a status field, and two optional message and details fields (in the case where "status": "error"). If there is no push receipt for a requested receipt ID, the mapping won't contain that ID. This is what a successful response to the above request looks like:

{
  "data": {
    "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX": { "status": "ok" },
    "ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ": { "status": "ok" }
    // When there is no receipt with a given ID (YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY in this
    // example), the ID is omitted from the response.
  }
}

你必须检查每个推送收据,因为它们可能包含有关你需要解决的错误的信息。例如,如果设备不再有资格接收通知,Apple 的文档会要求你停止向该设备发送通知。推送收据将包含有关这些错误的信息。

¥You must check each push receipt, since they may contain information about errors you need to resolve. For example, if a device is no longer eligible to receive notifications, Apple's documentation asks that you stop sending notifications to that device. The push receipts will contain information about these errors.

即使收据的 status 表示 ok,这也不能保证设备已收到该消息;推送回执中的 "ok" 表示 Android 或 iOS 推送通知服务已成功收到通知。例如,如果接收方设备已关闭,iOS 或 Android 推送通知服务将尝试传递消息,但设备不一定会收到该消息。

¥Even if a receipt's status says ok, this doesn't guarantee that the device has received the message; "ok" in a push receipt means that the Android or iOS push notification service successfully received the notification. If the recipient device is turned off, for example, the iOS or Android push notification service will try to deliver the message but the device won't necessarily receive it.

如果整个请求失败,HTTP 状态代码将为 4xx 或 5xx,errors 字段将是一组错误对象(通常只有一个)。否则,HTTP 状态代码将为 200,并且你的消息将发送至用户的设备。

¥If the entire request failed, the HTTP status code will be 4xx or 5xx and the errors field will be an array of error objects (usually just one). Otherwise, the HTTP status code will be 200 and your messages will be on their way to your users' devices.

错误

¥Errors

Expo 提供了有关整个过程中发生的任何错误的详细信息。我们将在下面介绍一些最常见的错误,以便你可以在服务器上实现自动处理这些错误的逻辑。

¥Expo provides details regarding any errors that occur during this entire process. We'll cover some of the most common errors below so that you can implement logic to handle them automatically on your server.

如果出于某种原因,Expo 无法将消息传送到 Android 或 iOS 推送通知服务,则推送收据的详细信息还可能包括特定于服务的信息。这主要用于调试并向 Expo 报告可能的错误。

¥If for whatever reason, Expo couldn't deliver the message to the Android or iOS push notification service, the push receipt's details may also include service-specific information. This is useful mostly for debugging and reporting possible bugs to Expo.

个别错误

¥Individual errors

在推送票证和推送收据中,查找带有 error 字段的 details 对象。如果存在,它可能是以下值之一,你应该像这样处理这些错误:

¥Inside both push tickets and push receipts, look for a details object with an error field. If present, it may be one of the following values, and you should handle these errors like so:

推送票据错误

¥Push ticket errors

  • DeviceNotRegistered:设备无法再接收推送通知,你应该停止向相应的 Expo 推送令牌发送消息。

    ¥DeviceNotRegistered: The device cannot receive push notifications anymore and you should stop sending messages to the corresponding Expo push token.

推送收据错误

¥Push receipt errors

  • DeviceNotRegistered:设备无法再接收推送通知,你应该停止向相应的 Expo 推送令牌发送消息。

    ¥DeviceNotRegistered: The device cannot receive push notifications anymore and you should stop sending messages to the corresponding Expo push token.

  • MessageTooBig:总通知负载太大。在 Android 和 iOS 上,总负载不得超过 4096 字节。

    ¥MessageTooBig: The total notification payload was too large. On Android and iOS, the total payload must be at most 4096 bytes.

  • MessageRateExceeded:你向给定设备发送消息过于频繁。实现指数退避并缓慢重试发送消息。

    ¥MessageRateExceeded: You are sending messages too frequently to the given device. Implement exponential backoff and slowly retry sending messages.

  • MismatchSenderId:这表明你的 FCM 推送凭据存在问题。FCM 推送凭证有两部分:你的 FCM 服务器密钥和 google-services.json 文件。两者必须与相同的发送者 ID 关联。你可以在 你可以在同一位置找到服务器密钥.txt 中找到你的发送者 ID。检查项目的 Expo 仪表板中的“凭据”>“应用标识符”>“FCM 服务器密钥”下的服务器密钥以及项目的 google-services.json > project_number 中的发送者 ID 是否与 Firebase 控制台中的“项目设置”>“云消息传递”选项卡下显示的相同 > 云消息 API(旧版)。

    ¥MismatchSenderId: This indicates that there is an issue with your FCM push credentials. There are two pieces to FCM push credentials: your FCM server key, and your google-services.json file. Both must be associated with the same sender ID. You can find your sender ID in the same place you find your server key. Check that the server key from your project's Expo dashboard under Credentials > Application Identifier > FCM Server Key and that the sender ID from your project's google-services.json > project_number is the same as shown in the Firebase console under Project Settings > Cloud Messaging tab > Cloud Messaging API (Legacy).

  • InvalidCredentials:你的独立应用的推送通知凭据无效(例如,你可能已撤销它们)。

    ¥InvalidCredentials: Your push notification credentials for your standalone app are invalid (for example, you may have revoked them).

    • 安卓:确保你已按照 上传 FCM V1 服务器凭据 中的指定从 Firebase 控制台正确上传服务器密钥。

      ¥Android: Make sure that you have correctly uploaded the server key from the Firebase Console as specified in uploading FCM V1 server credentials.

    • iOS:运行 eas credentials 并按照提示重新生成新的推送通知凭据。如果你撤销 APN 密钥,则所有依赖该密钥的应用将无法再发送或接收推送通知,直到你上传新密钥来替换它。上传新的 APN 密钥不会更改用户的 Expo Push 令牌。有时,这些错误将包含声称存在 InvalidProviderToken 错误的更多详细信息。这实际上与你的 APN 密钥和配置文件相关。要解决此错误,你应该重建应用并重新生成新的推送密钥和配置文件。

      ¥iOS: Run eas credentials and follow the prompts to regenerate new push notification credentials. If you revoke an APN key, all apps that rely on that key will no longer be able to send or receive push notifications until you upload a new key to replace it. Uploading a new APN key will not change your users' Expo Push Tokens. Sometimes, these errors will contain further details claiming an InvalidProviderToken error. This is actually tied to both your APN key and your provisioning profile. To resolve this error, you should rebuild the app and regenerate a new push key and provisioning profile.

为了更好地了解 iOS 凭据(包括推送通知凭据),请阅读我们的 应用签名文档

¥For a better understanding of iOS credentials, including push notification credentials, read our App Signing docs.

请求错误

¥Request errors

如果推送票证或推送收据的整个请求存在错误,则 errors 对象可能具有以下值之一,你应该处理这些错误:

¥If there's an error with the entire request for either push tickets or push receipts, the errors object might have one of the following values, and you should handle these errors:

  • TOO_MANY_REQUESTS:你超出了每个项目每秒 600 个通知的请求限制。我们建议在你的服务器中实现速率限制,以防止每秒发送超过 600 个通知(请注意,如果你使用 expo-server-sdk-node,这已经与重试的指数退避一起实现)。

    ¥TOO_MANY_REQUESTS: You are exceeding the request limit of 600 notifications per second per project. We recommend implementing rate-limiting in your server to prevent sending more than 600 notifications per second (note that if you use expo-server-sdk-node, this is already implemented along with exponential backoffs for retries).

  • PUSH_TOO_MANY_EXPERIENCE_IDS:你正在尝试向不同的 Expo 体验发送推送通知,例如 @username/projectAAA@username/projectBBB。检查 details 字段以获取请求中体验名称与其关联的推送令牌的映射,并从其他体验中删除任何内容。

    ¥PUSH_TOO_MANY_EXPERIENCE_IDS: You are trying to send push notifications to different Expo experiences, for example, @username/projectAAA and @username/projectBBB. Check the details field for a mapping of experience names to their associated push tokens from the request, and remove any from another experience.

  • PUSH_TOO_MANY_NOTIFICATIONS:你正尝试在一个请求中发送 100 多个推送通知。确保你在每个请求中仅发送 100 个(或更少)通知。

    ¥PUSH_TOO_MANY_NOTIFICATIONS: You are trying to send more than 100 push notifications in one request. Make sure you are only sending 100 (or fewer) notifications in each request.

  • PUSH_TOO_MANY_RECEIPTS:你正尝试在一个请求中获取超过 1000 个推送收据。确保你仅发送 1000 个(或更少)票证 ID 字符串的数组来获取推送收据。

    ¥PUSH_TOO_MANY_RECEIPTS: You are trying to get more than 1000 push receipts in one request. Make sure you are only sending an array of 1000 (or fewer) ticket ID strings to get your push receipts.

额外的安全保障

¥Additional security

你可以要求在我们将推送请求发送给你的用户之前发送带有有效 访问令牌 的任何推送请求。你可以从 Expo 仪表板 启用此增强的推送安全性。

¥You can require any push requests to be sent with a valid access token before we will deliver them to your users. You can enable this enhanced push security from your Expo Dashboard.

默认情况下,你可以通过发送 Expo Push Token 以及消息所需的任何文本或其他数据来向用户发送通知。这很容易设置,但如果令牌泄露,恶意用户将能够冒充你的应用并将其消息发送给你的用户。我们从未有过这样的报道。但是,为了遵循最佳安全实践,我们提供使用访问令牌和推送令牌作为附加安全层。

¥By default, you can send a notification to your users by sending their Expo Push Token and any text or additional data needed for the message. This is easy to set up, but if the tokens are leaked, a malicious user would be able to impersonate your app and send their message to your users. We have never had an instance of this report. However, to follow best security practices, we offer the use of an access token alongside the push token as an additional layer of security.

如果你使用的是 expo-server-sdk-node,请至少升级到 v3.6.0 并将 accessToken 作为构造函数中的选项传递。否则,将标头 'Authorization': 'Bearer ${accessToken}' 与任何请求一起传递给我们的推送 API。

¥If you're using the expo-server-sdk-node, upgrade to at least v3.6.0 and pass your accessToken as an option in the constructor. Otherwise, pass in the header 'Authorization': 'Bearer ${accessToken}' with any requests to our push API.

启用推送安全性后,发送的任何没有有效访问令牌的请求都将导致代码错误:UNAUTHORIZED

¥Any requests sent without a valid access token after you enable push security will result in an error with code: UNAUTHORIZED.

格式

¥Formats

消息请求格式

¥Message request format

每条消息必须是具有给定字段的 JSON 对象(仅需要 to 字段):

¥Each message must be a JSON object with the given fields (only the to field is required):

FieldPlatformTypeDescription
toAndroid and iOSstring | string[]An Expo push token or an array of Expo push tokens specifying the recipient(s) of this message.
dataAndroid and iOSObjectA JSON object delivered to your app. It may be up to about 4KiB; the total notification payload sent to Apple and Google must be at most 4KiB or else you will get a "Message Too Big" error.
titleAndroid and iOSstringThe title to display in the notification. Often displayed above the notification body
bodyAndroid and iOSstringThe message to display in the notification.
ttlAndroid and iOSnumberTime to Live: the number of seconds for which the message may be kept around for redelivery if it hasn't been delivered yet. Defaults to undefined to use the respective defaults of each provider (0 for iOS/APNs and 2419200 (4 weeks) for Android/FCM).
expirationAndroid and iOSnumberTimestamp since the Unix epoch specifying when the message expires. Same effect as ttl (ttl takes precedence over expiration).
priorityAndroid and iOS'default' | 'normal' | 'high'The delivery priority of the message. Specify "default" or omit this field to use the default priority on each platform ("normal" on Android and "high" on iOS).
subtitleiOS OnlystringThe subtitle to display in the notification below the title.
soundiOS Only'default' | nullPlay a sound when the recipient receives this notification. Specify "default" to play the device's default notification sound, or omit this field to play no sound. Custom sounds are not supported.
badgeiOS OnlynumberNumber to display in the badge on the app icon. Specify zero to clear the badge.
channelIdAndroid OnlystringID of the Notification Channel through which to display this notification. If an ID is specified but the corresponding channel does not exist on the device (that has not yet been created by your app), the notification will not be displayed to the user.
categoryIdAndroid and iOSstringID of the notification category that this notification is associated with. Find out more about notification categories here. Must be on at least SDK 41 or bare workflow.
mutableContentiOS OnlybooleanSpecifies whether this notification can be intercepted by the client app. In Expo Go, this defaults to true, and if you change that to false, you may experience issues. In standalone and bare apps, this defaults to false.

关于 ttl 的注意事项:在 Android 上,我们尽最大努力立即传递 TTL 为零的消息,并且不会限制它们。但是,将 TTL 设置为较低值(例如零)可以防止普通优先级通知到达处于打瞌睡模式的 Android 设备。为了保证通知能够送达,TTL 必须足够长,以便设备能够从打瞌睡模式中唤醒。当两者都指定时,该字段优先于 expiration

¥Note on ttl: On Android, we make our best effort to deliver messages with zero TTL immediately and do not throttle them. However, setting TTL to a low value (for example, zero) can prevent normal-priority notifications from ever reaching Android devices that are in doze mode. To guarantee that a notification will be delivered, TTL must be long enough for the device to wake from doze mode. This field takes precedence over expiration when both are specified.

关于 priority 的注意事项:在 Android 上,普通优先级消息不会在睡眠设备上打开网络连接,并且可能会延迟发送以节省电池。如果可能,高优先级消息会立即传递,并且可能会唤醒睡眠设备以打开网络连接,从而消耗能量。在 iOS 上,正常优先级消息的发送时间会考虑设备的功耗,并且可能会分组并突发传送。它们受到限制,可能不会由 Apple 提供。高优先级消息会立即发送。普通优先级对应于 APN 优先级 5,高优先级对应于 10。

¥Note on priority: On Android, normal-priority messages won't open network connections on sleeping devices and their delivery may be delayed to conserve the battery. High-priority messages are delivered immediately if possible and may wake sleeping devices to open network connections, consuming energy. On iOS, normal-priority messages are sent at a time that takes into account power considerations for the device and may be grouped and delivered in bursts. They are throttled and may not be delivered by Apple. High-priority messages are sent immediately. Normal priority corresponds to APNs priority level 5 and high priority to 10.

关于 channelId 的注意事项:如果留空,则将使用 "默认" 通道,如果该通道尚不存在,Expo 将在设备上创建该通道。但是,请谨慎使用,因为 "默认" 通道是面向用户的,你可能无法完全删除它。

¥Note on channelId: If left null, a "Default" channel will be used, and Expo will create the channel on the device if it does not yet exist. However, use caution, as the "Default" channel is user-facing and you may not be able to fully delete it.

推送票格式

¥Push ticket format

{
  "data": [
    {
      "status": "error" | "ok",
      "id": string, // this is the Receipt ID
      // if status === "error"
      "message": string,
      "details": JSON
    },
    ...
  ],
  // only populated if there was an error with the entire request
  "errors": [{
    "code": string,
    "message": string
  }]
}

推送回执请求格式

¥Push receipt request format

{
  "ids": string[]
}

推送回执响应格式

¥Push receipt response format

{
  "data": {
    Receipt ID: {
      "status": "error" | "ok",
      // if status === "error"
      "message": string,
      "details": JSON
    },
    ...
  },
  // only populated if there was an error with the entire request
  "errors": [{
    "code": string,
    "message": string
  }]
}

交货保证

¥Delivery guarantees

Expo 尽最大努力向 Google 和 Apple 运营的推送通知服务发送通知。Expo 的基础设施被设计为至少一次传递到底层推送通知服务。通知更有可能不止一次发送给谷歌或苹果,而不是根本不发送,尽管这两种情况都不常见,但也是有可能的。

¥Expo makes the best effort to deliver notifications to the push notification services operated by Google and Apple. Expo's infrastructure is designed for at least once delivery to the underlying push notification services. It is more likely for a notification to be delivered to Google or Apple more than once rather than not at all, though both are uncommon and possible.

将通知移交给底层推送通知服务后,Expo 会创建一个 "推送收据" 来记录移交是否成功。推送收据表示底层推送通知服务是否收到通知。

¥After a notification has been handed off to an underlying push notification service, Expo creates a "push receipt" that records whether the handoff was successful. A push receipt denotes whether the underlying push notification service received the notification.

最后,Google、Apple 等的推送通知服务遵循其策略将通知传递到设备。

¥Finally, the push notification services from Google, Apple, and so on follow their policies to deliver the notifications to the device.

Expo 中文网 - 粤ICP备13048890号