Expo推送通知报错DeviceNotRegistered,请求技术排查
DeviceNotRegistered排查方案 问题概述
基于Expo构建的React Native应用已完成推送通知配置,能正常获取ExponentPushToken,但通过Expo API或官方工具推送时,持续报错:
DeviceNotRegistered: "ExponentPushToken[***]" is not a registered push notification recipient
已实现代码
通知Hook实现
export const useNotifications = () => { const registerForPushNotificationsAsync = async () => { 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; } const token = (await Notifications.getExpoPushTokenAsync()).data; console.log("TOKEN------------", token); alert(token); } else { alert("Must use physical device for Push Notifications"); } if (Platform.OS === "android") { Notifications.setNotificationChannelAsync("default", { name: "default", importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: "#FF231F7C", }); } }; const handleNotification = (notification = Notifications.Notification) => { // 自定义通知处理逻辑 }; // 通知点击监听器 const handleNotificationResponse = ( response = Notifications.NotificationResponse ) => { const data = ({ url } = response.notification.request.content.data); if (data?.url) Linking.openURL(data.url); }; return { registerForPushNotificationsAsync, handleNotification, handleNotificationResponse, }; };
组件中使用代码
useEffect(() => { registerForPushNotificationsAsync(); Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, shouldPlaySound: false, shouldSetBadge: true, }), }); const responseListener = Notifications.addNotificationResponseReceivedListener( handleNotificationResponse ); return () => { if (responseListener) { Notifications.removeNotificationSubscription(responseListener); } }; }, []);
已执行操作
- 执行
eas build -p android --profile preview生成安卓预览包并在真机测试 - 通过
expo push:android:upload --api-key <your-token-here>上传Firebase Cloud Messaging服务器密钥
排查与解决步骤
匹配推送环境与构建配置
预览包(preview profile)对应Expo的staging环境,推送时必须指定环境:
使用官方工具推送时添加--staging参数:expo push:send --staging --message "测试通知" --to ExponentPushToken[xxx]调用API时需使用staging端点:
https://exp.host/--/api/v2/push/send(默认端点为production,会导致令牌不匹配)对应Firebase密钥环境
Firebase Cloud Messaging有两个密钥:生产环境服务器密钥、测试环境服务器密钥。若上传的是生产密钥但用staging环境推送,会导致令牌无法识别。重新上传staging对应的测试密钥:expo push:android:upload --api-key <firebase-staging-server-key> --staging验证令牌生成环境
预览包生成的令牌属于staging环境,不能用生产推送服务发送。部分版本的staging令牌会带有STAGING-前缀,可快速识别。检查EAS构建配置
确认eas.json中preview profile的环境配置,避免强制指定production:{ "build": { "preview": { "android": { "buildType": "apk" }, "env": { "EXPO_PUBLIC_ENV": "staging" } } } }重新生成令牌测试
卸载现有预览包,重新安装后获取新令牌,立即用对应环境的推送工具测试,避免令牌过期或环境绑定错误。核对Firebase包名
确认Firebase项目的包名(applicationId)与EAS构建配置中的android.package完全一致(大小写敏感),包名不匹配会导致Firebase拒绝请求,进而触发Expo的设备未注册错误。
内容的提问来源于stack exchange,提问作者Zaki Kendil

