安卓12+后的系统默认使用Splash配置(icon+背景色)导致重复启动Splash屏幕
如果是老项目会发现在新的原生系统上打开,比如模拟器上,总是会先出现一个icon+白色或者黑色背景色,随后出现我们自己的Splash屏幕。国内的设备大部分没有强制使用,所以不影响,不过有其他Splash问题本文也会给出解决方案,比如全屏幕,透明状态栏,避免home(主页)短暂的闪烁,一般是空的Header或者自定义了Header会出现这个问题。
修复双重Splash的思路
关于双重启动Splash可以参考安卓官方发布:将启动画面实现迁移到 Android 12 及更高版本,由于Expo53以前使用的还是老的自定义Activity作为Splash启动,所以加上新SDK的默认Splash就出现两次Splash。新的API不再使用Activity,而是由系统接管,我们只需要配置style即可,也能更好的适配夜间模式切换。
如果你的项目暂时不考虑大版本跨度升级,我们可以想办法配置系统的启动画面为透明状态,这样可以做到无缝过渡到自定义Splash的状态。有一个其他的方案就是将系统Splash配置设置和自定义的一样,但是这里有个问题就是:如过你的自定义是个广告屏幕或者不是纯色,就很麻烦。比如渐变色的,这个时候状态栏就会很不和谐,很突兀(后面会给出代码,让状态栏后面能够渲染Splash。既然方向确定了,开始写代码。
非Expo项目
如果你是原生的ReactNative项目,在你的android文件目录,打开如下文件编辑:
src…..res….values…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:textColor">@android:color/black</item> <item name="android:editTextStyle">@style/ResetEditText</item> <item name="android:editTextBackground">@drawable/rn_edit_text_material</item> <item name="colorPrimary">@color/colorPrimary</item> <item name="android:statusBarColor">@android:color/transparent</item> </style> <style name="ResetEditText" parent="@android:style/Widget.EditText"> <item name="android:padding">0dp</item> <item name="android:textColorHint">#c8c8c8</item> <item name="android:textColor">@android:color/black</item> </style>
<style name="Theme.App.SplashScreen" parent="AppTheme"> <item name="android:windowBackground">@drawable/splashscreen</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowLightStatusBar">true</item> </style> </resources>
|
设置好Styles后我们要去改系统的默认启动Splash颜色
1 2 3 4 5 6 7 8 9 10
|
<resources>
<color name="splashscreen_background">@android:color/transparent</color> <color name="iconBackground">#ffffff</color> <color name="colorPrimary">#023c69</color> <color name="colorPrimaryDark">#ffffff</color> </resources>
|
Expo Prebuild项目 & Expo Bare项目
如果你是Expo的项目,并且使用了Prebuild,那么需要按照上面RN原生方案改的基础上再修改如下配置,因为Expo Prebuild后会按照app.json配置生成Android目录配置文件,如果你没设置,则是默认的:
1 2 3 4 5 6 7 8 9 10 11 12
|
<resources> <string name="app_name">name</string> <string name="expo_splash_screen_resize_mode" translatable="false">cover</string> <string name="expo_splash_screen_status_bar_translucent" translatable="false">true</string> <string name="expo_system_ui_user_interface_style" translatable="false">light</string> </resources>
|
由于我们在上面已经将系统Splash设置了透明,所以启动后会无缝过渡到自定义的Splash,同时设置“translucent”,实现FullScreen。如果你使用Expo的app.json配置,有个很可惜的配置项就是Splash背景色不支持设置android的透明格式,Eas会报错,所以Bare工作流需要使用下面的插件自动替换修复这个色值。
在App.config.js or app.json
1 2 3 4 5 6 7 8 9 10 11 12 13
| { "expo":{ "android":{ "statusbar": { "barStyle": "dark-content", "translucent": true, } } } }
|
为了方面Bare流的开发,我写了一个插件在构建打包的时候同步修改更新,使用这个插件后,不再需要修改prebuild后的文件,也不需要Android目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
const { withAndroidStyles, AndroidConfig, withStringsXml, } = require("@expo/config-plugins"); const { Styles, Strings } = AndroidConfig;
function withTransparentStatusBar(config) { config = withAndroidStyles(config, (config) => { let styles = config.modResults;
styles = Styles.assignStylesValue(styles, { add: true, parent: { name: "AppTheme" }, name: "android:statusBarColor", value: "@android:color/transparent", });
styles = Styles.assignStylesValue(styles, { add: true, parent: { name: "Theme.App.SplashScreen" }, name: "android:windowIsTranslucent", value: "true", });
styles = Styles.assignStylesValue(styles, { add: true, parent: { name: "Theme.App.SplashScreen" }, name: "android:windowLightStatusBar", value: "true", });
config.modResults = styles; return config; });
config = withStringsXml(config, (config) => { config.modResults = Strings.setStringItem( [ { $: { name: "expo_splash_screen_status_bar_translucent", translatable: "false", }, _: "true", }, ], config.modResults, ); return config; });
return config; }
module.exports = withTransparentStatusBar;
|
插件用法和其他expo插件一样的写法
1 2 3 4 5
| plugins: [ "./fix-transparent-statusbar.js", ]
|
这个问题的解决其实很取巧,不需要代码演示,其实闪烁的原因就是因为Splash过快关闭,在计算自定义的Header高度或者隐藏header的时候有个延迟,只需要将Splash延迟关闭500ms-600ms即可。