使用 Expo Push Service 发送通知
了解如何调用 Expo Push Service API 从你的服务器发送推送通知。
expo-notifications
库提供推送通知的所有客户端功能。Expo 还负责将推送通知发送到 FCM 和 APN,然后将其发送到特定设备。你需要做的就是使用通过 getExpoPushTokenAsync
获得的 ExpoPushToken
向 Expo Push API 发送请求。
¥The expo-notifications
library provides all the client-side functionality for push notifications. Expo also handles sending push notifications off to FCM and APNs which then send them to particular devices. All you need to do is send a request to Expo Push API with the ExpoPushToken
you obtain with getExpoPushTokenAsync
.
如果你希望构建直接与 APN 和 FCM 通信的服务器,请参阅 使用 FCM 和 APN 发送通知。它比使用 Expo Push Service 更复杂,但允许更细粒度的控制,并可以完全访问所有 FCM 和 APNs 功能。
¥If you'd rather build a server that communicates with APNs and FCM directly, see Send notifications with FCM and APNs. It's more complex than using Expo Push Service, but allows finer-grained control, and full access to all FCM and APNs features.
使用服务器发送推送通知
¥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-node | Node.js | Expo 团队 |
expo-server-sdk-python | Python | 社区 |
expo-server-sdk-ruby | Ruby | 社区 |
expo-push-notification-client-rust | Rust | 社区 |
expo-notifier | 交响乐团 | 交响乐团 |
exponent-server-sdk-php | PHP | 社区 |
expo-server-sdk-php | PHP | 社区 |
exponent-server-sdk-golang | Golang | 社区 |
exponent | Golang | 社区 |
exponent-server-sdk-elixir | 灵丹妙药 | 社区 |
expo-server-sdk-dotnet | dotnet | 社区 |
expo-server-sdk-java | Java | 社区 |
laravel-expo-notifier | 拉维尔 | 社区 |
上面的每个示例服务器都是 Expo Push Service API 的封装器。
¥Each of the example servers above is a wrapper around Expo Push Service 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 errors helps 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 notification requests successfully.
失败重试
¥Retry on failure
发送推送通知的第一步是将它们传递给 Expo 推送通知服务,该服务在内部将它们添加到队列中以传递给 Google (FCM v1) 和 Apple (APNs)。第一步可能会因以下几个原因而失败:
¥The first step in 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 v1) and Apple (APNs). 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 - a HTTP 429 error (Too Many Requests), or a 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 or APNs. 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 响应该信息,推送回执还可能告诉你接收设备是否已取消订阅通知(例如,通过撤销通知权限或卸载你的应用)。推送收据将包含设置为 DeviceNotRegistered
的 details
→ error
字段。在这种情况下,请停止向该设备的推送令牌发送通知,直到它重新注册到你的服务器,这样你的应用仍然是一个好公民。仅当 Google 或 Apple 认为设备未注册时,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 APNs or FCM responds with that information. The push receipt will contain a details
→ error
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 Google or Apple 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 的 "你好世界" 推送通知,你可以使用终端发送(将占位符推送令牌替换为你自己的):
¥This is a "hello world" push notification using cURL that you can send using your terminal (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 Push Service 还可以选择接受 gzip 压缩的请求主体。这可以大大减少发送大量通知所需的上传带宽量。节点 Expo 服务器 SDK 会自动为你压缩请求并自动限制你的请求以平滑负载,因此我们强烈推荐它。
¥The Expo Push Service 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
上述请求将使用带有两个可选字段 data
和 errors
的 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 is 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 Push Service 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 对象,具有两个可选字段 data
和 errors
。data
包含收据 ID 到收据的映射。收据包括一个 status
字段以及两个可选的 message
和 details
字段(在 "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 it 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 contain information about these errors.
即使收据的
status
表示ok
,这也不能保证设备已收到该消息;推送回执中的 "ok" 表示 Android (FCM) 或 iOS (APNs) 推送通知服务已成功收到通知。例如,如果接收方设备已关闭,iOS 或 Android 推送通知服务将尝试传递消息,但设备不一定会收到该消息。¥Even if a receipt's
status
saysok
, this doesn't guarantee that the device has received the message; "ok" in a push receipt means that the Android (FCM) or iOS (APNs) 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 anInvalidProviderToken
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 thedetails
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 server 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):
Field | Platform | Type | Description |
---|---|---|---|
to | Android and iOS | string | string[] | An Expo push token or an array of Expo push tokens specifying the recipient(s) of this message. |
_contentAvailable | iOS Only | boolean | undefined | When this is set to true, the notification will cause the iOS app to start in the background to run a background task. Your app needs to be configured to support this. |
data | Android and iOS | Object | A 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. |
title | Android and iOS | string | The title to display in the notification. Often displayed above the notification body. Maps to AndroidNotification.title and aps.alert.title . |
body | Android and iOS | string | The message to display in the notification. Maps to AndroidNotification.body and aps.alert.body . |
ttl | Android and iOS | number | Time 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 (1 month for Android/FCM as well as iOS/APNs). |
expiration | Android and iOS | number | Timestamp since the Unix epoch specifying when the message expires. Same effect as ttl (ttl takes precedence over expiration ). |
priority | Android 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). |
subtitle | iOS Only | string | The subtitle to display in the notification below the title. Maps to aps.alert.subtitle . |
sound | iOS Only | string | null | Play 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 need to be configured via the config plugin and then specified including the file extension. Example: bells_sound.wav . |
badge | iOS Only | number | Number to display in the badge on the app icon. Specify zero to clear the badge. |
interruptionLevel | iOS Only | 'active' | 'critical' | 'passive' | 'time-sensitive' | The importance and delivery timing of a notification. The string values correspond to the UNNotificationInterruptionLevel enumeration cases. |
channelId | Android Only | string | ID 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. |
categoryId | Android and iOS | string | ID of the notification category that this notification is associated with. Find out more about notification categories here. |
mutableContent | iOS Only | boolean | Specifies whether this notification can be intercepted by the client app. 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 is 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 more likely to be delivered immediately 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 usually 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 is used, and Expo creates 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 的基础架构设计用于至少一次尝试传送到底层推送通知服务。通知更有可能多次发送给 Google 或 Apple,而不是根本不发送;但是,这两种结果都不常见。
¥Expo makes a best effort to deliver notifications to the push notification services operated by Google and Apple. Expo's infrastructure is designed for at least one attempt at 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; however, both these results are uncommon.
将通知移交给底层推送通知服务后,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 and Apple follow their own policies to deliver the notifications to the device.