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

Expo Notifications生产构建无法获取推送Token问题求助

Expo Notifications + Firebase Messaging生产环境无法获取推送Token问题排查

问题描述

我搭建了一个测试Expo Notifications与Firebase Messaging的应用,已完成以下配置:

  • 正确引入Firebase提供的google-services.json文件
  • 在app.json中添加权限:
"permissions": [
    "POST_NOTIFICATIONS",
    "RECEIVE_BOOT_COMPLETED"
],
  • 编写了通知权限请求与注册代码(见下方核心代码)

本地测试时推送功能完全正常,但发布生产构建后,应用不再显示Expo推送Token和设备Token。

核心代码

export default function App() {
  const [forceReload, setForceReload] = useState(true);
  const [notificationExpoToken, setNotificationExpoToken] = useState('');
  const [notificationDeviceToken, setNotificationDeviceToken] = useState('');

  const registerForPushNotificationsAsync = async () => {
    let tokenExpo;
    let tokenDevice;

    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.alert('ERROR', 'Non è stato possibile ricuperare il token per le notifiche!');
        return;
      }

      tokenExpo = (await Notifications.getExpoPushTokenAsync()).data;
      setNotificationExpoToken(tokenExpo);

      tokenDevice = (await Notifications.getDevicePushTokenAsync()).data;
      setNotificationDeviceToken(tokenDevice);
    } else {
      Alert.alert('ERROR', 'Deve utilizzare un device per le notifiche push!');
    }

    return tokenExpo;
  };

  useEffect(()=>{
    (async ()=>{
      await registerForPushNotificationsAsync();
    })();
  }, [notificationExpoToken, notificationDeviceToken]);

  return (
    <View style={styles.container} key={forceReload}>
      <StatusBar style="auto" />
      <Text style={{fontWeight: 'bold', color: 'orange', marginVertical: 10}}>notificationExpoToken:</Text>
      <Text selectable style={{margin: 10}}>{notificationExpoToken}</Text>
      <Text style={{fontWeight: 'bold', color: 'blue', marginVertical: 10}}>notificationDeviceToken:</Text>
      <Text selectable style={{margin: 10}}>{notificationDeviceToken}</Text>
      <Button title={"Reload"} onPress={()=>{ setForceReload(!forceReload) }} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

排查与解决方案

1. 核对Firebase生产环境配置

  • 确认google-services.json是生产环境专属配置文件,Firebase控制台中开发/生产环境的配置文件不通用,混用会导致生产构建无法正常获取Token。
  • 检查app.json中android.googleServicesFile的路径是否指向正确的生产环境文件,确保构建时该文件被正确打包。

2. 配置Expo生产环境推送凭证

  • Expo Push Token:生产环境中getExpoPushTokenAsync()需要关联Expo项目的生产级FCM凭证:
    1. 进入Expo Dashboard的项目设置 -> 云消息服务(Push Notifications)
    2. 上传从Firebase控制台(项目设置 -> 云消息服务)获取的生产环境FCM服务器密钥
  • 设备Token:若google-services.json配置错误,getDevicePushTokenAsync()会直接失败,需确保文件的包名、API密钥等信息与生产构建一致。

3. 修复useEffect依赖循环问题

你的useEffect依赖了notificationExpoToken和notificationDeviceToken,会导致Token更新时重复调用注册函数,形成无限循环,最终引发Token获取异常。修改依赖数组为空,确保仅在组件挂载时执行一次:

useEffect(()=>{
  (async ()=>{
    await registerForPushNotificationsAsync();
  })();
}, []); // 移除token依赖,仅在组件挂载时执行

4. 添加错误捕获与日志

生产环境无法直接查看调试信息,建议在Token获取逻辑中添加错误捕获,便于定位问题:

const registerForPushNotificationsAsync = async () => {
  try {
    // 原有逻辑...
  } catch (error) {
    console.error('Token获取失败:', error);
    Alert.alert('ERROR', `Token获取失败: ${error.message}`);
  }
};

可使用Expo的Logcat工具(针对Android)查看生产构建的日志,定位具体错误。

5. 确认生产构建权限配置

  • 对于Android 13+,POST_NOTIFICATIONS需运行时请求,你的代码已处理,但需确认生产构建中该权限未被ProGuard/R8规则移除,app.json的android.permissions中需明确声明。
  • 若使用EAS Build,检查eas.json是否有覆盖权限的配置,确保生产构建包含所需权限。

6. 验证EAS Build配置(若使用EAS)

  • 在eas.json的生产构建配置中,确认android.googleServicesFile路径指向正确的生产环境文件:
{
  "build": {
    "production": {
      "android": {
        "googleServicesFile": "./google-services-production.json"
      }
    }
  }
}
  • 查看构建日志,确认google-services.json已被正确加载,无文件找不到或解析错误。

内容的提问来源于stack exchange,提问作者vcorrea

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:57:16