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

React Native应用TestFlight因栈导航问题崩溃求助

问题:React Native Expo应用TestFlight启动崩溃,替换导航组件后触发

问题描述

开发的React Native应用通过Expo在真机和模拟器上运行正常,但打包上传至Apple开发者控制台并发布到TestFlight后,启动即崩溃,日志未提供有效排查线索。当底部标签导航使用无内容的默认通用页面时能正常渲染,但将Properties标签页替换为栈导航组件后,应用加载时立即崩溃。

相关代码文件

App.js

import { useEffect, useState } from 'react';
import { StyleSheet, LogBox } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { NavigationContainer } from '@react-navigation/native';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from './src/api/firebase';

import { GeneralContextProvider } from './src/context/GeneralContext';
import { PropertyContextProvider } from './src/context/PropertyContext';
import { FilterSortContextProvider } from './src/context/FilterSortContext';
import { SinglePropertyContextProvider } from './src/context/SinglePropertyContext';
import { FinancesContextProvider } from './src/context/FinancialContext';
import { UserContextProvider } from './src/context/UserContext';
import { FeedContextProvider } from './src/context/FeedContext';
import BottomTabNavigation from './src/navigation/BottomTabNavigation';
import LoadProfile from './src/iOS/iPhone/screens/LoadProfile';

LogBox.ignoreAllLogs();

export default function App() {
  const [initializing, setInitializing] = useState(true);
  const [user, setUser] = useState(null);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
      if (initializing) {
        setInitializing(false);
        if (user) {
          console.log(user.uid)
        }
      }
    });

    return () => unsubscribe();
  }, []);

  if (initializing) {
    return null;
  }

  return(
    <NavigationContainer style={styles.container}>
      <StatusBar 
        barStyle="dark" />
      <FeedContextProvider>
        <UserContextProvider>
          <FilterSortContextProvider>
              <FinancesContextProvider>
                <SinglePropertyContextProvider>
                  <PropertyContextProvider>
                    <GeneralContextProvider>
                      <BottomTabNavigation />
                    </GeneralContextProvider>
                  </PropertyContextProvider>
                </SinglePropertyContextProvider>
              </FinancesContextProvider>
          </FilterSortContextProvider>
        </UserContextProvider>
      </FeedContextProvider>
    </NavigationContainer>
  )
}

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

BottomTabNavigation.js

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import { Feather } from 'react-native-vector-icons'

import DefaultPropertiesScreen from './DefaultPropertiesScreen';
import DefaultFavoritesScreen from './DefaultFavoritesScreen';
import DefaultProfileScreen from './DefaultProfileScreen';
import DefaultFeedScreen from './DefaultFeedScreen'
import PropertiesStackNavigation from './PhoneStackNavigation/PropertiesStackNavigation';


const Tab = createBottomTabNavigator();

function BottomTabNavigation() {
  return (
    <Tab.Navigator initialRouteName='PropertiesScreen' screenOptions={{headerShown: false}}>
      <Tab.Screen 
        name="Properties" 
        key='Properties'
        component={PropertiesStackNavigation} 
        options={{
          tabBarShowLabel: false,
          tabBarIcon: ({size, color}) => (<Feather name={"home"} color={color} size={size} />)
        }}/>
      <Tab.Screen 
        name="Favorites" 
        key='Favorites'
        component={DefaultFavoritesScreen} 
        options={{
          tabBarShowLabel: false,
          tabBarIcon: ({size, color}) => (<Feather name={"heart"} color={color} size={size} />)
        }}/>
      <Tab.Screen 
        name="Feed"
        key='Feed'
        component={DefaultFeedScreen} 
        options={{
          tabBarShowLabel: false,
          tabBarIcon: ({size, color}) => (<Feather name={"grid"} color={color} size={size} />)
        }}/>
      <Tab.Screen 
        name="Profile"
        key='Profile'
        component={DefaultProfileScreen} 
        options={{
          tabBarShowLabel: false,
          tabBarIcon: ({size, color}) => (<Feather name={"user"} color={color} size={size} />)
        }}/>
    </Tab.Navigator>
  );
}

export default BottomTabNavigation

PropertiesStackNavigation.js

import { createStackNavigator } from '@react-navigation/stack'
import PropertyScreen from '../../iOS/iPhone/screens/Properties/PropertyScreen'
import CarouselScreen from '../../iOS/iPhone/screens/Properties/CarouselScreen'
import MakeAnOfferScreen from '../../iOS/iPhone/screens/Properties/MakeAnOfferScreen'
import PropertiesScreen from '../../iOS/iPhone/screens/Properties/PropertiesScreen'

const StackNav = createStackNavigator();

const PropertiesStackNavigation = () => {
  return (
    <StackNav.Navigator initialRouteName='PropertiesScreen' screenOptions={{headerShown: false}}>
      <StackNav.Screen name="PropertiesScreen" component={PropertiesScreen}/>
      <StackNav.Screen name="PropertyScreen" component={PropertyScreen}/>
      <StackNav.Screen name="CarouselScreen" component={CarouselScreen}/>
      <StackNav.Screen name="MakeOfferScreen" component={MakeAnOfferScreen} />
    </StackNav.Navigator>
  )
}

export default PropertiesStackNavigation

package.json

{
  "name": "rippe",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@babel/runtime": "^7.21.0",
    "@ptomasroos/react-native-multi-slider": "^2.2.2",
    "@react-native-async-storage/async-storage": "1.17.11",
    "@react-navigation/bottom-tabs": "^6.5.8",
    "@react-navigation/native": "^6.1.7",
    "@react-navigation/stack": "^6.3.17",
    "axios": "^1.4.0",
    "expo": "~48.0.18",
    "expo-device": "~5.2.1",
    "expo-status-bar": "~1.4.4",
    "firebase": "^10.1.0",
    "npx": "^10.2.2",
    "react": "18.2.0",
    "react-native": "0.71.8",
    "react-native-google-places-autocomplete": "^2.5.1",
    "react-native-maps": "1.3.2",
    "react-native-safe-area-context": "4.5.0",
    "react-native-screens": "~3.20.0",
    "react-native-vector-icons": "^10.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

本地运行截图

本地Expo真机运行截图

排查方向与解决办法

1. 修复依赖版本兼容性

Expo 48适配的React Native版本是0.71.x,而你使用的firebase@10.1.0需要Expo 49及以上版本支持,版本不匹配会导致生产环境崩溃。执行以下命令降级Firebase:

npm install firebase@9.23.0

重新打包测试。

2. 定位栈导航内的错误组件

默认页面能正常运行,说明问题出在PropertiesStackNavigation包含的页面组件中:

  • 临时将栈导航的初始页面替换为极简测试组件:
    import { View, Text } from 'react-native';
    const TestScreen = () => <View style={{flex:1, justifyContent:'center', alignItems:'center'}}><Text>Test Page</Text></View>;
    
    // 在PropertiesStackNavigation中替换初始页面
    <StackNav.Screen name="PropertiesScreen" component={TestScreen}/>
    
    如果打包后能正常启动,逐步恢复原页面组件,定位到具体出错的组件,检查是否存在开发环境专属代码、未处理的异步错误或未打包的依赖。

3. 开启生产环境错误日志

  • 移除LogBox.ignoreAllLogs(),只忽略特定已知警告,确保生产环境错误能被捕获。
  • 安装expo-error-recovery收集崩溃日志:
    expo install expo-error-recovery
    
    在App.js中添加错误监听:
    import * as ErrorRecovery from 'expo-error-recovery';
    
    useEffect(() => {
      const lastError = ErrorRecovery.getLastError();
      if (lastError) {
        console.error('Crash Details:', lastError);
        // 可将日志上传到Firebase等服务
        ErrorRecovery.clearLastError();
      }
    }, []);
    

4. 检查文件路径大小写

iOS生产环境对文件路径大小写敏感,本地开发环境会忽略该差异。确认PropertiesStackNavigation中导入组件的路径与实际文件路径大小写完全一致,比如../../iOS/iPhone/screens/Properties/PropertiesScreen是否匹配真实文件的命名。

5. 清理缓存重新打包

执行以下命令清理缓存后重新打包:

# 清理Expo缓存
expo r -c
# 清理npm缓存
npm cache clean --force
# 重新打包iOS应用
eas build --platform ios

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 07:17:33