React Native Expo项目闪屏不显示(仅白屏)问题求助
Expo托管React Native项目闪屏不显示问题排查与解决
我运行着一个Expo托管式React Native项目,初始化时闪屏正常显示,但现在完全无法看到闪屏,仅显示空白白屏(无报错)。闪屏加载后的所有功能均正常,急需解决闪屏显示问题。
已尝试的操作
- 在iOS模拟器、iOS真机、Android模拟器上运行,问题一致
- 删除node_modules和package-lock.json后执行
npm i - 清除Expo和npm的缓存
- 将app.js返回内容替换为仅
<View><Text>...</Text></View>,问题仍存在
项目配置
package.json
{ "name": "placeholder", "version": "1.0.0", "description": "placeholder", "main": "node_modules/expo/AppEntry.js", "type": "commonjs", "private": true, "scripts": { "type:check": "npx tsc", "format:check": "prettier --check \"src/**/*\"", "format:write": "prettier --write \"src/**/*\"", "lint:check": "eslint \"App.tsx\" \"src/**/*\"", "lint:fix": "eslint --fix \"App.tsx\" \"src/**/*\"", "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web" }, "engines": { "node": "16.x" }, "dependencies": { "@react-native-async-storage/async-storage": "~1.17.3", "@react-navigation/drawer": "^6.4.3", "@react-navigation/native": "^6.0.11", "@react-navigation/native-stack": "^6.7.0", "@react-navigation/stack": "^6.2.2", "@reduxjs/toolkit": "^1.8.4", "dotenv": "^16.0.1", "expo": "~46.0.6", "expo-status-bar": "~1.4.0", "react": "18.0.0", "react-dom": "18.0.0", "react-native": "0.69.4", "react-native-gesture-handler": "~2.5.0", "react-native-reanimated": "~2.9.1", "react-native-screens": "~3.15.0", "react-native-web": "~0.18.7", "react-redux": "^8.0.2", "styled-components": "^5.3.5", "expo-screen-orientation": "~4.3.0", "expo-splash-screen": "~0.16.1", "react-native-safe-area-context": "4.3.1" }, "devDependencies": { "@babel/core": "^7.12.9", "@redux-devtools/core": "^3.13.1", "@types/react": "~18.0.14", "@types/react-native": "~0.69.1", "@types/react-redux": "^7.1.24", "@types/styled-components": "^5.1.26", "@types/styled-components-react-native": "^5.1.3", "@typescript-eslint/eslint-plugin": "^5.33.1", "eslint": "^8.22.0", "eslint-config-standard-with-typescript": "^22.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.2.4", "eslint-plugin-promise": "^6.0.0", "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "prettier": "^2.7.1", "typescript": "^4.7.4" } }
app.json
{ "expo": { "name": "placeholder", "slug": "placeholder", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/images/icon.png", "userInterfaceStyle": "light", "splash": { "image": "./assets/images/splash.png", "resizeMode": "cover", "backgroundColor": "#1D1A1F" }, "updates": { "fallbackToCacheTimeout": 0 }, "assetBundlePatterns": ["**/*"], "ios": { "supportsTablet": true, "requireFullScreen": true }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/images/adaptive-icon.png", "backgroundColor": "#1D1A1F" } }, "web": { "favicon": "./assets/images/favicon.png" } } }
babel.config.js
module.exports = function (api) { api.cache(true) return { presets: ['babel-preset-expo'], plugins: ['react-native-reanimated/plugin'] } }
app.tsx
import 'react-native-gesture-handler' import Constants from 'expo-constants' import { useState, useEffect } from 'react' import { useFonts } from 'expo-font' import * as SplashScreen from 'expo-splash-screen' import * as ScreenOrientation from 'expo-screen-orientation' import AsyncStorage from '@react-native-async-storage/async-storage' import { SafeAreaProvider } from 'react-native-safe-area-context' import { Provider } from 'react-redux' import { ThemeProvider } from 'styled-components/native' import store from './src/redux/store' import { lightTheme, darkTheme } from './src/res/theme/theme' import Loading from './src/screens/loading/loading' import { logger } from './src/logger/logger' import Application from './src/components/application/application' // Function to keep the splash screen visible while we fetch resources SplashScreen.preventAutoHideAsync() .then((data) => logger.log(`SplashScreen.preventAutoHideAsync() succeeded: ${data.toString()}`)) .catch(logger.warn) logger.log('NODE_ENV: ', Constants?.manifest?.extra?.env) //eslint-disable-line export const App = (): JSX.Element => { const [fontsLoaded] = useFonts({ SedgwickAveDisplay: require('./assets/fonts/sedgwick-ave-display/SedgwickAveDisplay-Regular.ttf'), QuicksandRegular: require('./assets/fonts/Quicksand/static/Quicksand-Regular.ttf'), QuicksandSemiBold: require('./assets/fonts/Quicksand/static/Quicksand-SemiBold.ttf'), QuicksandBold: require('./assets/fonts/Quicksand/static/Quicksand-Bold.ttf') }) const [loading, setLoading] = useState(true) const [theme, setTheme] = useState('light') const selectedTheme = theme === 'dark' ? darkTheme : lightTheme // Load the app here useEffect(() => { // Hide splash screen after 2 seconds setTimeout(() => { SplashScreen.hideAsync() .then((data) => logger.log(`SplashScreen.hideAsync() succeeded: ${data.toString()}`)) .catch(logger.warn) }, 2000) ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) .then(() => { logger.log('ScreenOrientation.lockAsync() succeeded') return AsyncStorage.getItem('@theme') }) .then((data) => { if (data) setTheme(data) setLoading(false) }) .catch((e) => { logger.warn(e) setLoading(false) }) }, []) if (loading || !fontsLoaded) { return <Loading /> } return ( <SafeAreaProvider> <Provider store={store}> <ThemeProvider theme={selectedTheme}> <Application /> </ThemeProvider> </Provider> </SafeAreaProvider> ) } export default App
排查与修复方案
1. 调整SplashScreen.preventAutoHideAsync执行时机
你在组件外部调用SplashScreen.preventAutoHideAsync(),可能导致竞态问题——Expo闪屏可能已自动隐藏,此调用才生效。将逻辑移至组件内部useEffect,确保挂载后立即执行:
export const App = (): JSX.Element => { const [fontsLoaded] = useFonts({ // 字体配置保留 }) const [loading, setLoading] = useState(true) const [theme, setTheme] = useState('light') const selectedTheme = theme === 'dark' ? darkTheme : lightTheme useEffect(() => { const prepareApp = async () => { try { await SplashScreen.preventAutoHideAsync() logger.log('SplashScreen.preventAutoHideAsync() succeeded') } catch (e) { logger.warn(e) } try { await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) logger.log('ScreenOrientation.lockAsync() succeeded') const savedTheme = await AsyncStorage.getItem('@theme') if (savedTheme) setTheme(savedTheme) } catch (e) { logger.warn(e) } finally { // 等待字体加载完成后再处理闪屏隐藏 const waitForFonts = new Promise(resolve => { const interval = setInterval(() => { if (fontsLoaded) { clearInterval(interval) resolve(true) } }, 50) }) await waitForFonts setTimeout(() => { SplashScreen.hideAsync() .then(data => logger.log(`SplashScreen.hideAsync() succeeded: ${data.toString()}`)) .catch(logger.warn) setLoading(false) }, 2000) } } prepareApp() }, [fontsLoaded]) // 其余代码保留 }
2. 检查闪屏资源有效性
- 确认
./assets/images/splash.png文件存在,尺寸符合Expo要求(建议:iOS 2208×2208,Android 1280×1920) - 可尝试在
assetBundlePatterns中明确指定闪屏路径:["assets/images/*"],确保资源被正确打包
3. 排查Loading组件干扰
你在加载状态返回的<Loading />可能是白底,覆盖了Expo闪屏。暂时注释该返回,测试闪屏是否显示:
// if (loading || !fontsLoaded) { // return <Loading /> // } if (!fontsLoaded) { return null // 让Expo闪屏正常显示 }
若闪屏恢复,说明Loading组件需调整样式(比如设置透明背景)。
4. 修复版本兼容性问题
Expo 46对应的expo-splash-screen@~0.16.1存在自动隐藏bug,可尝试:
- 升级至Expo 47+
- 降级
expo-splash-screen到兼容版本:
npm install expo-splash-screen@0.15.1
5. 彻底清理缓存
执行以下命令重置项目缓存:
expo start -c npm cache clean --force rm -rf node_modules package-lock.json npm install
内容的提问来源于stack exchange,提问作者mprouve
相关产品推荐
相关产品推荐

