Expo Notifications推送票据/回执状态正常但未收到通知
Expo Managed Workflow下expo-notifications推送通知无法接收排查
我在Expo Managed Workflow中使用expo-notifications模块发送推送通知,已依据官方文档搭建最小复现项目,但遇到无法接收推送通知的问题:
- 本地定时通知可正常显示
- 提取FCM推送令牌直接通过FCM发送也能正常接收
- 推送票据(Push Ticket)与回执(Receipt)状态均标记为
ok,但设备仍收不到通知 - 当前使用安卓真机上的EAS开发构建版本
相关代码
import { useState, useEffect, useRef } from 'react'; import { Text, View, Button, Platform } from 'react-native'; import * as Device from 'expo-device'; import * as Notifications from 'expo-notifications'; import Constants from 'expo-constants'; Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: false, shouldSetBadge: false, }), }); export default function App() { const [expoPushToken, setExpoPushToken] = useState(''); const [notification, setNotification] = useState(false); const notificationListener = useRef(); const responseListener = useRef(); useEffect(() => { registerForPushNotificationsAsync().then(token => setExpoPushToken(token.data)); notificationListener.current = Notifications.addNotificationReceivedListener(notification => { setNotification(notification); }); responseListener.current = Notifications.addNotificationResponseReceivedListener(response => { console.log(response); }); return () => { Notifications.removeNotificationSubscription(notificationListener.current); Notifications.removeNotificationSubscription(responseListener.current); }; }, []); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'space-around', }}> <Text>Your expo push token: {expoPushToken}</Text> <View style={{ alignItems: 'center', justifyContent: 'center' }}> <Text>Title: {notification && notification.request.content.title} </Text> <Text>Body: {notification && notification.request.content.body}</Text> <Text>Data: {notification && JSON.stringify(notification.request.content.data)}</Text> </View> <Button title="Press to schedule a notification" onPress={async () => { await scheduleNotification(); }} /> <Button title="Press to send a push notification" onPress={async () => { await sendPushNotification(expoPushToken); }} /> </View> ); } async function scheduleNotification() { console.log("pressed") await Notifications.scheduleNotificationAsync({ content: { title: "test", body: 'test3', data: {}, }, trigger: null }); } async function sendPushNotification(expoPushToken) { const message = { to: expoPushToken, sound: 'default', title: 'Original Title', body: 'And here is the body!', data: { someData: 'goes here' }, }; const response = await fetch('https://exp.host/--/api/v2/push/send', { method: 'POST', headers: { Accept: 'application/json', 'Accept-encoding': 'gzip, deflate', 'Content-Type': 'application/json', }, body: JSON.stringify(message), }) const responseData = await response.json() console.log("Push Ticket : ", responseData.data) fetchReceipt(responseData.data.id) } async function fetchReceipt(id) { ids = new Array(id) const message = { ids: ids } const response = await fetch('https://exp.host/--/api/v2/push/getReceipts', { method: 'POST', headers: { Accept: 'application/json', 'Accept-encoding': 'gzip, deflate', 'Content-Type': 'application/json', }, body: JSON.stringify(message), }); const responseData = await response.json(); console.log("Reciept : ", responseData.data) } async function registerForPushNotificationsAsync() { let token; if (Platform.OS === 'android') { await Notifications.setNotificationChannelAsync('default', { name: 'default', importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: '#FF231F7C', }); } if (Device.isDevice) { const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { alert('Failed to get push token for push notification!'); return; } token = await Notifications.getExpoPushTokenAsync({ projectId: Constants.expoConfig.extra.eas.projectId, }); console.log(token); const firebaseToken = (await Notifications.getDevicePushTokenAsync()).data; console.log("FCM Token : ", firebaseToken) } else { alert('Must use physical device for Push Notifications'); } return token; }
日志示例
Push Ticket : Object { "id": "2fbfdd91-53a0-4199-ac32-b53131d72933", "status": "ok", } Reciept : Object { "2fbfdd91-53a0-4199-ac32-b53131d72933": Object { "status": "ok", }, }
关键信息
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.
但通过FCM控制台直接推送成功,说明设备与FCM的通信无问题,问题应出在Expo推送服务到FCM的转发环节或配置上。
排查方向
- 检查Expo项目的FCM配置:确认EAS构建时已正确配置
google-services.json,项目的app.json/app.config.js中对应的Firebase配置无错误 - 验证Expo Push Token有效性:确保获取的Expo Push Token与FCM Token绑定到同一设备,可对比设备标识(如
Device.deviceId)是否一致 - 完善推送消息参数:Android设备需要指定
channelId,当前代码创建了default频道,但推送消息中未添加该参数,可在message中添加android: { channelId: 'default' } - 测试后台接收情况:当前代码的监听仅针对前台,将应用退到后台后再次测试推送
- 查看Expo控制台推送记录:在Expo Dashboard中查看推送请求的详细日志,是否存在隐藏错误
- 检查EAS构建配置:确认开发构建已开启推送权限,构建过程中无配置遗漏
内容的提问来源于stack exchange,提问作者Freddie Moore
相关产品推荐
相关产品推荐

