Flutter Add to App Android启动Activity白屏问题解决方案咨询
已验证的Flutter Add to App首帧白屏解决方案
我之前在处理Flutter Add to App的项目时遇到过完全一样的白屏问题,下面给你几个经过项目验证的可行方案,你可以根据自己的需求组合使用:
方案一:透明主题+首帧就绪后显示Activity
这个方案的核心是让FlutterActivity启动时保持透明,直到Flutter首帧渲染完成后再切换回正常主题并显示窗口,彻底避免白屏:
- 添加透明主题
在styles.xml中新增一个透明主题,继承自你现有的AppTheme.NoFullscreen:
<style name="TransparentFlutterActivityTheme" parent="AppTheme.NoFullscreen"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowIsTranslucent">true</item> </style>
- 修改AndroidManifest配置
将CMFlutterActivity的主题临时设置为这个透明主题:
<activity android:name=".ui.flutter.CMFlutterActivity" android:theme="@style/TransparentFlutterActivityTheme" <!-- 替换成透明主题 --> android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:screenOrientation="portrait" android:stateNotNeeded="true" android:exported="true" />
- 修改CMFlutterActivity代码
重写onFlutterUiDisplayed方法,在首帧就绪后恢复正常显示:
class CMFlutterActivity : FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { // 先设置窗口flag确保透明效果 window.setFlags( WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS ) super.onCreate(savedInstanceState) } override fun onFlutterUiDisplayed() { super.onFlutterUiDisplayed() // Flutter首帧渲染完成,切换回原主题 setTheme(R.style.AppTheme_NoFullscreen) // 移除透明相关flag,恢复窗口正常布局 window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) // 确保窗口可见(如果之前被隐藏的话) window.decorView.visibility = View.VISIBLE } }
方案二:添加占位加载页(提升用户体验)
如果觉得透明过渡不够友好,可以在FlutterView上层添加一个和App风格一致的加载页,等首帧就绪后隐藏,用户看到的是加载状态而非空白:
- 创建加载布局
新建layout_loading.xml,比如包含进度条和App Logo:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="@color/app_background" android:orientation="vertical"> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="加载中..." android:textColor="@color/text_primary" /> </LinearLayout>
- 修改CMFlutterActivity代码
在onCreate中添加加载View,首帧就绪后隐藏:
class CMFlutterActivity : FlutterActivity() { private lateinit var loadingView: View override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 加载自定义加载布局 loadingView = LayoutInflater.from(this).inflate(R.layout.layout_loading, null) // 获取Activity根布局,添加加载View val rootContainer = findViewById<ViewGroup>(android.R.id.content) rootContainer.addView(loadingView) } override fun onFlutterUiDisplayed() { super.onFlutterUiDisplayed() // 首帧就绪,隐藏加载View loadingView.visibility = View.GONE } }
方案三:预加载FlutterEngine(从根源减少等待时间)
如果你的App会多次启动Flutter页面,预加载FlutterEngine可以大幅缩短首帧加载时间,从根源减少白屏时长:
- 在Application中预初始化FlutterEngine
class MyApp : Application() { lateinit var preWarmedEngine: FlutterEngine override fun onCreate() { super.onCreate() // 初始化FlutterEngine preWarmedEngine = FlutterEngine(this) // 执行Dart入口点 preWarmedEngine.dartExecutor.executeDartEntrypoint( DartExecutor.DartEntrypoint.createDefault() ) // 将Engine缓存起来,供后续Activity复用 FlutterEngineCache.getInstance().put("pre_warmed_engine", preWarmedEngine) } }
- 在CMFlutterActivity中复用预加载的Engine
class CMFlutterActivity : FlutterActivity() { override fun provideFlutterEngine(context: Context): FlutterEngine? { // 复用预加载的FlutterEngine return FlutterEngineCache.getInstance().get("pre_warmed_engine") } }
推荐组合
我个人推荐方案二 + 方案三的组合:预加载Engine减少等待时间,同时用加载页提升用户感知,几乎可以消除白屏带来的不良体验。
内容的提问来源于stack exchange,提问作者Leonardo da Silva




