Expo Android独立版应用启动卡在空白白屏问题求助
首先,我先梳理下你遇到的问题:开发和模拟生产模式都正常,但打包成独立APK后,启动时在闪屏前出现空白白屏。这在Expo独立版里是比较常见的问题,主要和资源预加载时机、原生闪屏配置以及JS初始化顺序有关。下面给你几个针对性的解决方案:
1. 修复代码里的资源预加载Bug
先看你的cacheImages函数,里面用到了Image.prefetch,但你没在代码顶部导入Image组件!这会导致图片预加载失败,直接跳过资源加载流程,提前进入App,从而出现白屏。
先补上导入:
import { Image, ActivityIndicator, LogBox, View } from "react-native";
另外,你的_loadAssetsAsync里,fontsLoaded是useFonts返回的布尔值,不是Promise,所以await Promise.all([...imageAssets, fontsLoaded])这里有问题——布尔值不能被await。useFonts本身已经在异步加载字体了,你不需要再把它放到Promise.all里,应该改成:
async function _loadAssetsAsync() { const imageAssets = cacheImages([ require("./ASSETS/Loading_Black.gif"), require("./ASSETS/icons/like.png"), require("./ASSETS/icons/like-red.png"), require("./ASSETS/icons/comment.png"), require("./ASSETS/icons/share.png"), require("./ASSETS/CHAT_BGRD-02.jpeg"), ]); // 等待图片加载完成即可,字体由useFonts自动处理 await Promise.all(imageAssets); }
还有,把ready的初始值改成false,确保App一开始就进入资源加载流程,而不是先尝试渲染主界面:
const [ready, setReady] = useState(false);
2. 配置app.json里的闪屏参数,让原生闪屏持续显示到资源加载完成
Expo独立版的原生闪屏默认会在JS开始执行后自动隐藏,这时候如果你的资源还没加载完,就会出现白屏。你需要在app.json(或app.config.js)里配置闪屏的backgroundColor和resizeMode,并且设置android.splash.showSpinner(可选),同时确保闪屏图片和你的App主题一致:
{ "expo": { "splash": { "image": "./assets/splash.png", // 替换成你的闪屏图片路径 "resizeMode": "cover", // 或者"contain",根据你的图片选择 "backgroundColor": "#ffffff", // 设置成和闪屏图片一致的背景色,避免切换时的突兀 "android": { "splash": { "showSpinner": true, // 可选,显示加载指示器 "backgroundColor": "#ffffff" } } } } }
3. 改用expo-splash-screen手动控制闪屏隐藏(更可靠)
expo-app-loading在独立版里有时候会有兼容性问题,推荐使用官方的expo-splash-screenAPI来手动控制闪屏的显示和隐藏,这样能精确控制闪屏直到所有资源加载完成:
首先安装依赖(如果没装的话):
expo install expo-splash-screen
然后修改你的App.js代码:
import React, { useState, useEffect, useRef } from "react"; import { NavigationContainer } from "@react-navigation/native"; import StackNavigator from "./StackNavigator"; import { AuthProvider } from "./hooks/useAuth"; import { Image, ActivityIndicator, LogBox, View } from "react-native"; import { Asset } from "expo-asset"; import { Roboto_100Thin, Roboto_100Thin_Italic, Roboto_300Light, Roboto_300Light_Italic, useFonts, } from "@expo-google-fonts/roboto"; import * as SplashScreen from 'expo-splash-screen'; import * as Font from "expo-font"; import * as encoding from "text-encoding"; LogBox.ignoreAllLogs(); // 阻止闪屏自动隐藏 SplashScreen.preventAutoHideAsync(); function cacheImages(images) { return images.map((image) => { if (typeof image === "string") { return Image.prefetch(image); } else { return Asset.fromModule(image).downloadAsync(); } }); } export default function App() { const [isReady, setIsReady] = useState(false); let [fontsLoaded] = useFonts({ "Roboto-Thin": Roboto_100Thin, Roboto_100Thin_Italic, "Roboto-Light": Roboto_300Light, Roboto_300Light_Italic, }); useEffect(() => { async function prepare() { try { // 预加载图片资源 const imageAssets = cacheImages([ require("./ASSETS/Loading_Black.gif"), require("./ASSETS/icons/like.png"), require("./ASSETS/icons/like-red.png"), require("./ASSETS/icons/comment.png"), require("./ASSETS/icons/share.png"), require("./ASSETS/CHAT_BGRD-02.jpeg"), ]); await Promise.all(imageAssets); } catch (e) { console.warn(e); } finally { // 所有资源加载完成后,隐藏闪屏 setIsReady(true); await SplashScreen.hideAsync(); } } prepare(); }, []); if (!isReady || !fontsLoaded) { // 这里可以返回一个自定义的加载界面,或者什么都不返回(因为闪屏还在显示) return null; } return ( <NavigationContainer> <AuthProvider> <StackNavigator /> </AuthProvider> </NavigationContainer> ); }
这个方案的核心是:一开始阻止闪屏自动隐藏,等所有图片和字体都加载完成后,再手动隐藏闪屏,这样就不会出现中间的白屏了。
4. 检查独立版打包时的资源是否正确嵌入
有时候打包时资源没有正确嵌入到APK里,也会导致加载延迟出现白屏。你可以在打包前执行expo prebuild(如果是bare workflow的话),或者确保所有资源路径都是正确的,没有拼写错误。另外,用expo build:android -t apk重新打包,确保打包过程没有报错。
按照上面的步骤逐一排查,应该就能解决你遇到的白屏问题了。
内容的提问来源于stack exchange,提问作者Lahfir

