Expo 多 push token 消息返回的 push tickets 是否保证顺序?
可以按消息和接收者的顺序建立对应关系:先遍历消息数组,再按 to 中的顺序展开每条消息的接收者。返回的 tickets[i] 对应展开后的第 i 个接收者。Expo 官方文档说明,tickets 按发送顺序返回;其示例中的三个消息对象包含四个接收者,返回了四张 ticket。因此,方式 B 可以用于关联 push token 和 ticket。Expo 官方文档
为什么 ticket 数量可能多于消息对象数量?
当 to 是数组时,同一个消息对象会向多个接收者发送通知,每个接收者都有自己的 ticket。例如:
const messages = [
{ title: 'Hello', to: [tokenA, tokenB] },
{ title: 'News', to: [tokenC] },
];
对应关系为:
tickets[0] → messages[0] → tokenA
tickets[1] → messages[0] → tokenB
tickets[2] → messages[1] → tokenC
因此,不能直接按相同索引关联 messages[i].to 和 tickets[i],需要先展开接收者。
SDK 会按接收者计算实际通知数量,并检查返回的 ticket 数量是否匹配。chunkPushNotifications() 也会遍历 to 数组,必要时将同一条消息的接收者拆到不同批次。因此,建立映射时应以实际发送的批次为单位。SDK 源码
如何在方式 B 中保存对应关系?
可以保留现有的多接收者消息结构。先调用 chunkPushNotifications(),然后展开每个批次中的接收者,与该批次返回的 tickets 配对:
import { Expo } from 'expo-server-sdk';
const expo = new Expo();
async function sendWithTicketMapping(messages) {
const results = [];
const chunks = expo.chunkPushNotifications(messages);
for (const chunk of chunks) {
const targets = chunk.flatMap((message) => {
const tokens = Array.isArray(message.to)
? message.to
: [message.to];
return tokens.map((pushToken) => ({ pushToken }));
});
const tickets = await expo.sendPushNotificationsAsync(chunk);
if (tickets.length !== targets.length) {
throw new Error('Ticket count does not match recipient count');
}
const mapped = tickets.map((ticket, index) => ({
pushToken: targets[index].pushToken,
ticket,
}));
results.push(...mapped);
}
return results;
}
这里假设传入的消息符合 Expo 要求。返回结果中的每一项都保留了 pushToken 和完整的 ticket,可按业务需要持久化。示例中的数量检查可以防止数量异常时继续配对,但不能独立证明服务端的返回顺序。
如果还要关联用户或业务消息,应在发送前另行保存这些标识与接收者的关系。同一个 token 可能收到多条消息,因此不能只用 token 作为每次发送记录的唯一键。
哪些操作会破坏映射?
- 先过滤失败的 tickets,再按索引配对。错误 ticket 也占据对应位置,必须先完成关联,再处理
status。失败的 ticket 可能没有id。ticket 格式说明 - 按并发请求的完成顺序拼接 tickets。不同批次可能先后返回,应在各自批次内部配对,再汇总映射结果。
- 某个批次失败后,继续用全局索引匹配剩余结果。请求抛出异常时,应针对该批次处理失败,避免后续结果整体错位。
对于 status === 'ok' 的 ticket,可以保存 ticket.id → pushToken 的关系。后续 getPushNotificationReceiptsAsync() 返回的是以 receipt ID 为键的对象,应按 ID 查询,不能再依赖数组位置。ticket 的 ok 表示 Expo 已接收通知,receipt 的 ok 表示推送提供方已接收,均不能据此认定设备已经收到通知。push receipts 说明
备注:内容仅供参考。
