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

React Native iOS应用白屏:NativeEventEmitter参数不能为空错误排查

解决React Native iOS模拟器白屏及NativeEventEmitter参数错误问题

问题背景

React Native应用构建成功,但安装到iOS模拟器后显示白屏。环境配置:NVM管理Node(版本16.14.2)、Xcode 14.2、2017款MacBook Pro,项目集成了@react-native-firebase的Firestore与推送通知功能。

报错栈

BUNDLE  ./index.js 

 ERROR  Invariant Violation: `new NativeEventEmitter()` requires a non-null argument.
 ERROR  Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
      This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.
 ERROR  Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect.
      This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.

相关配置文件

package.json

{
  "name": "digitvl_app",
  "version": "0.0.1",
  "private": true,
  "rnpm":{
    "assets":["./assets/fonts"]
    
  },
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-native-firebase/app": "^16.5.0",
    "@react-native-firebase/auth": "^16.5.0",
    "@react-native-firebase/firestore": "^16.5.0",
    "@react-native-firebase/messaging": "^16.5.0",
    "@react-navigation/native": "^6.1.1",
    "@react-navigation/native-stack": "^6.9.7",
    "firebase": "^9.15.0",
    "react": "17.0.2",
    "react-native": "0.68.2",
    "react-native-paper": "^5.1.3",
    "react-native-push-notification": "^8.1.1",
    "react-native-safe-area-context": "^4.4.1",
    "react-native-screens": "^3.18.2"
  },
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/runtime": "^7.20.7",
    "@react-native-community/eslint-config": "^3.2.0",
    "babel-jest": "^29.3.1",
    "eslint": "^8.31.0",
    "jest": "^29.3.1",
    "metro-react-native-babel-preset": "^0.73.7",
    "react-test-renderer": "17.0.2"
  },
  "jest": {
    "preset": "react-native"
  }
}

metro.config.js

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
      },
    }),
  },
};
const { getDefaultConfig } = require("metro-config");
const { resolver: defaultResolver } = getDefaultConfig.getDefaultValues();
exports.resolver = {
  ...defaultResolver,
  sourceExts: [
    ...defaultResolver.sourceExts,
    "cjs",
  ],
};

App.js

import React, {useEffect, useState} from 'react';
import {StyleSheet, Text, View, Linking, Platform} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import LoginScreen from './screens/LoginScreen';
import messaging from '@react-native-firebase/messaging';
import SendNotificationScreen from './screens/SendNotificationScreen';
import PushNotification, {Importance} from 'react-native-push-notification';
import firestore from '@react-native-firebase/firestore';
import auth from '@react-native-firebase/auth'
const Stack = createNativeStackNavigator();

export default function App() {
  const [state,setState] = useState({})
  const requestPermission = async () => {
    const oldToken = await messaging().getToken();
    console.log('oldToken:' + oldToken);
    if(auth().currentUser){
      firestore().collection("userToken").doc(auth().currentUser.uid).update({
        token:oldToken
      })
    }
    
    messaging().onTokenRefresh(token => {
      console.log('tokenRefresh:' + token);
      firestore().collection("userToken").add({
        token:token
    })

    });

    PushNotification.getChannels(function (channel_ids) {
      console.log('chanells: ' + channel_ids);
    });

    const granted = await messaging()
      .requestPermission()
      .catch(err => console.log(err));
    if (granted) {
      console.log('User granted messaging permissions!');

      createNotificationListners();
    } else {
      console.log('User declined messaging permissions :(');
    }
    await messaging().registerDeviceForRemoteMessages();
    return granted;
  };

  useEffect(() => {
    requestPermission();

    PushNotification.configure({
      onNotification: notification => {
        console.log('notificationOpen' + JSON.stringify(notification.data));
        setNotificationData(notification.data);
      },
    });
    return () => {
      setState({});
    };
  }, []);

  const [noticationData, setNotificationData] = useState({});

  useEffect(() => {
    console.log('notificationReceived: ' + noticationData);
    
    Linking.openURL(""+noticationData.url+"").catch(err => console.error("Couldn't load page", err));
  }, [noticationData]);

  const createNotificationListners = async () => {
    PushNotification.createChannel(
      {
        channelId: 'channel-id',
        channelName: 'My channel',
        channelDescription: 'A channel to categorise your notifications',
        playSound: true,
        soundName: 'notification.mp3',
        importance: Importance.HIGH,
        vibrate: true,
      },
      created => console.log(`createChannel returned '${created}'`),
    );

    messaging().onMessage(async remoteMessage => {
      var localNotification = {
        channelId: 'channel-id',
        channelName: 'My channel',
        title: remoteMessage.data.title,
        message: remoteMessage.data.body,
        userInfo: remoteMessage.data,
        data: remoteMessage.data,
        soundName: 'default',
        onNotification: function (notification) {
          console.log('onNotification:');
          console.log('onNotification:' + notification);
        },
      };

      Platform.OS == 'android' &&
        (localNotification = {
          ...localNotification,
          channelId: 'channel-id',
          channelName: 'My channel',
          largeIcon: '',
          smallIcon:
            Platform.Version >= 23 ? 'ic_launcher' : 'ic_launcher_round',
          priority: 'high',
          ignoreInForeground: false,
          onlyAlertOnce: false,
          invokeApp: true,
        });
      setNotificationData({});
      setNotificationData(remoteMessage.data);
      PushNotification.localNotification(localNotification);
    });

    messaging().setBackgroundMessageHandler(async remoteMessage => {
      console.log("Background message handler")
      setNotificationData(
        remoteMessage.data
      );
      if(auth().currentUser !== null){
        const userId = auth().currentUser.uid
        firestore().collection("users").doc(userId).update({
          coins:firestore.FieldValue.increment(1)
        }).then(res => {
            console.log("Success update coins")
        }).catch(err => {
            console.log("Error update coins")
        })
      }
    });

    messaging().onNotificationOpenedApp(remoteMessage => {
      console.log("on notification Opened App")
      setNotificationData(
        remoteMessage.data
      );
    });

    messaging()
      .getInitialNotification()
      .then(remoteMessage => {
        if (remoteMessage) {
          console.log("Initial Notification")
          setNotificationData(
            remoteMessage.data
          );
        }
      });
  };

  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          options={{headerShown: false}}
          name="Login"
          component={LoginScreen}
        />
        <Stack.Screen
          options={{headerShown: false}}
          name="Home"
          component={HomeScreen}
        />
        <Stack.Screen
          options={{headerShown: false}}
          name="SendNotification"
          component={SendNotificationScreen}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

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

已尝试操作

  • 清理npm缓存
  • 清理React Native缓存
  • 切换Node版本
  • 删除并重新安装Pods
  • 清理Xcode构建产物
  • 按照rnfirebase.io指南配置Firebase

解决方案

1. 修复metro.config.js配置错误

原配置存在导出冲突,导致transformer设置被覆盖,替换为合并后的正确配置:

const { getDefaultConfig } = require("metro-config");

module.exports = (async () => {
  const { resolver } = await getDefaultConfig();
  return {
    transformer: {
      getTransformOptions: async () => ({
        transform: {
          experimentalImportSupport: false,
          inlineRequires: true,
        },
      }),
    },
    resolver: {
      ...resolver,
      sourceExts: [...resolver.sourceExts, "cjs"],
    },
  };
})();

2. 移除react-native-push-notification,避免与@react-native-firebase/messaging冲突

@react-native-firebase/messaging已完整支持远程/本地通知处理,无需额外依赖react-native-push-notification,两者共存会导致NativeEventEmitter初始化失败。执行以下步骤:

  • 卸载依赖:npm uninstall react-native-push-notification
  • 清理iOS目录Pods:cd ios && rm -rf Pods Podfile.lock && pod install

3. 调整App.js中的通知处理逻辑(移除react-native-push-notification相关代码)

修改后的核心通知处理逻辑如下(仅保留@react-native-firebase/messaging相关代码):

// 移除PushNotification导入
// 替换requestPermission和createNotificationListners函数
const requestPermission = async () => {
  const oldToken = await messaging().getToken();
  console.log('oldToken:' + oldToken);
  if(auth().currentUser){
    firestore().collection("userToken").doc(auth().currentUser.uid).update({
      token:oldToken
    })
  }
  
  messaging().onTokenRefresh(token => {
    console.log('tokenRefresh:' + token);
    firestore().collection("userToken").add({
      token:token
    })
  });

  const granted = await messaging()
    .requestPermission()
    .catch(err => console.log(err));
  if (granted) {
    console.log('User granted messaging permissions!');
    createNotificationListners();
  } else {
    console.log('User declined messaging permissions :(');
  }
  await messaging().registerDeviceForRemoteMessages();
  return granted;
};

const createNotificationListners = async () => {
  messaging().onMessage(async remoteMessage => {
    console.log("Foreground message received:", remoteMessage.data);
    setNotificationData(remoteMessage.data);
  });

  messaging().setBackgroundMessageHandler(async remoteMessage => {
    console.log("Background message handler");
    if(auth().currentUser !== null){
      const userId = auth().currentUser.uid
      firestore().collection("users").doc(userId).update({
        coins:firestore.FieldValue.increment(1)
      }).then(res => {
          console.log("Success update coins")
      }).catch(err => {
          console.log("Error update coins")
      })
    }
  });

  messaging().onNotificationOpenedApp(remoteMessage => {
    console.log("On notification opened app");
    setNotificationData(remoteMessage.data);
  });

  messaging()
    .getInitialNotification()
    .then(remoteMessage => {
      if (remoteMessage) {
        console.log("Initial Notification");
        setNotificationData(remoteMessage.data);
      }
    });
};

4. 确保Firebase配置文件正确导入

检查Xcode项目中GoogleService-Info.plist的Target membership是否勾选了当前应用目标,确保文件被正确打包进应用。

5. 重新构建项目

  • 清除React Native缓存:npx react-native start --reset-cache
  • 清理Xcode构建产物:打开Xcode,按Cmd+Shift+K清理,然后重新运行项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 11:00:42