Expo React Native中iOS端FCM Token获取异常及APNs转FCM问题
问题
在React Native Expo应用中,Android端获取推送Token后用Firebase Admin发送推送正常,但iOS端报错:
code: 'messaging/invalid-argument', message: 'The registration token is not a valid FCM registration token'
前端获取Token的代码:
export const getFcmToken = async () => { const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; console.log("constatrn", Constants.expoConfig); try { const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== "granted") { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== "granted") { alert("Échec de l'obtention du jeton pour les notifications push!"); return; } const token = (await Notifications.getDevicePushTokenAsync()).data; console.log("Jeton Expo Push:", token); return token; } catch (error) { console.error("Erreur lors de l'obtention du jeton Expo push:", error); } };
后端用Firebase Admin发送的代码:
const sendNotification = async ( userID: string, title: string, body: string ) => { try { let tokenArray: string[] = []; const getTok = await getToken(userID); getTok?.map((item: any) => { tokenArray.push(item.token); }); console.log("tokenArray", tokenArray); // Envoyez la notification await firebaseAdmin .messaging() .sendEachForMulticast({ tokens: tokenArray, // ['token_1', 'token_2', ...] data: { owner: "test", user: "test", picture: "", }, apns: { payload: { aps: { // Required for background/quit data-only messages on iOS // Note: iOS frequently will receive the message but decline to deliver it to your app. // This is an Apple design choice to favor user battery life over data-only delivery // reliability. It is not under app control, though you may see the behavior in device logs. "content-available": true, // Required for background/quit data-only messages on Android priority: "high", }, }, }, }) .then((response: any) => { console.log("Response sent message:", response.responses[0].error); }) .catch((error) => { console.log("Error sending message:", error); }); } catch (error) { console.error("Erreur lors de l'envoi de la notification:", error); } };
用户怀疑前端获取的是APNs Token而非FCM Token,想知道是否遗漏了步骤。
问题根源
你前端用Notifications.getDevicePushTokenAsync()获取的是Expo Push Token,既不是FCM Token也不是原生APNs Token。Expo Push Token是Expo推送服务的中转令牌,只能用于调用Expo的推送API,无法直接给Firebase Admin使用——这就是iOS端报错的核心原因。
解决方案
有两种可行的处理方式,根据你的需求选择:
方式一:直接获取FCM Token(适配Firebase Admin)
要让Firebase Admin能正常发送推送,需要获取原生FCM Token,步骤如下:
- 安装Expo Firebase Messaging依赖:
npx expo install expo-firebase-messaging
- 修改前端代码,替换为获取FCM Token的逻辑:
import * as FirebaseMessaging from 'expo-firebase-messaging'; import Constants from 'expo-constants'; export const getFcmToken = async () => { try { // 请求推送权限 const { status: existingStatus } = await FirebaseMessaging.requestPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const { status } = await FirebaseMessaging.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { alert('无法获取推送令牌!'); return; } // 获取FCM Token(iOS/Android通用) const fcmToken = await FirebaseMessaging.getToken(); console.log('FCM Token:', fcmToken); return fcmToken; } catch (error) { console.error('获取FCM Token失败:', error); } };
- 配置验证:
- iOS:确保Firebase项目已关联APNs证书/密钥(在Firebase控制台「项目设置」→「云消息传递」中配置)
- 确保Expo项目已正确关联Firebase项目(可通过app.json配置或EAS构建时注入环境变量)
方式二:改用Expo推送服务(无需修改前端Token)
如果不想切换到FCM Token,后端可以直接调用Expo的推送API,兼容iOS和Android:
import axios from 'axios'; const sendExpoNotification = async (userID: string, title: string, body: string) => { try { let tokenArray: string[] = []; const getTok = await getToken(userID); getTok?.map((item: any) => { tokenArray.push(item.token); }); await axios.post('https://exp.host/--/api/v2/push/send', { to: tokenArray, title: title, body: body, data: { owner: 'test', user: 'test', picture: '' }, aps: { 'content-available': true, priority: 'high' } }); } catch (error) { console.error('发送推送失败:', error); } };
内容的提问来源于stack exchange,提问作者Bonnie06
相关产品推荐
相关产品推荐

