起因
在用 Flutter 开发 App 时发现一个奇怪的现象:无论怎么配置,启动图始终没法做成全屏效果,系统总是显示"纯色背景 + 居中小图标"的样式。但手机里其他 App(比如闲鱼,同样是 Flutter 开发的)却能正常显示全屏启动图,一度让人怀疑是不是自己哪里配置漏了。
环境信息:
- 系统:Xiaomi HyperOS 2.0.209.0
- Android 版本:Android 15
排查过程
1. 先搞清楚 Android 官方的限制
从 Android 12(API 31)开始,Google 引入了官方的 SplashScreen API。这套新 API 的设计原则是:启动页只能是「纯色/渐变背景 + 居中小图标(约 240dp)+ 可选品牌图标」,**不允许**直接塞一张铺满全屏的位图作为系统级启动页。这是平台层面的硬性限制,跟用不用 Flutter 无关。
解决方案
第一步:退回老式配置,绕开新 API 的接管
找到 android/app/src/main/res/values-v31/styles.xml(如果有 values-night-v31/styles.xml 也一并处理),原本大概是这样:
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowSplashScreenBackground">@color/bgColor</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/launch_background</item>
</style>改成和低版本values/styles.xml)保持一致,直接用传统的 windowBackground 全屏图,不声明任何新版属性:
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>launch_background.xml 用铺满全屏的图片即可,不要用「纯色背景 + 居中小图标」那种 layer-list 写法。
改完之后,在 HyperOS 上系统闪屏这一层就基本不会再显示了,或者显示的时间极短——因为系统只会在 Flutter 引擎渲染出第一帧之前有一个最低展示时间,无法完全消除,但可以压到几乎无感知。
### 第二步:把这"极短的一下"也藏起来
既然这一下无法彻底消除,更实用的做法是让它和你自己的全屏图**视觉上无缝衔接**:
1. 尽量缩短它的展示时长
- main() 里不要做重活(网络请求、大文件解析等),这些放到首页加载完成后异步执行:
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp()); // 尽快调用
} - 如果用了 flutter_native_splash 的 preserve/remove 机制,一定要在**首帧渲染完成后立刻** remove,不要因为等待网络请求而人为拖长:
FlutterNativeSplash.preserve(widgetsBinding: WidgetsFlutterBinding.instance);
runApp(MyApp());
// 在首屏 Widget build 完成后立刻调用
FlutterNativeSplash.remove(); 全屏图的停留时长,改用自己 Widget 里的 Future.delayed 之类逻辑控制,而不是靠拖延 remove 的时机实现。
- 用 release 包flutter build apk --release)测试速度,debug 包的 JIT 编译开销会造成误判。
- 第三方插件(推送、统计 SDK 等)的初始化尽量延后或异步执行,避免阻塞首帧渲染。
2. 让颜色过渡保持一致
系统这一层背景色设置成和全屏图主色调一致,图标区域用透明图或者极小的 Logo,避免出现"图标一闪又换成另一张图"的跳变感:
<item name="android:windowSplashScreenBackground">@color/splash_bg</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/transparent_or_blank</item>
评论区