You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,步骤如下:

  1. 安装Expo Firebase Messaging依赖:
npx expo install expo-firebase-messaging
  1. 修改前端代码,替换为获取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);
  }
};
  1. 配置验证:
    • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 23:13:11