You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Splash Screen API深色模式适配异常问题求助

Android闪屏主题跟随应用设置不生效问题(三星Android 13设备)

问题描述

使用Android闪屏API实现应用闪屏,深色模式主题开发完成后整体功能正常,但在部分设备(如搭载Android 13(API 33)的三星设备)上出现异常:当应用内切换为浅色模式,但系统深色模式仍处于开启状态时,闪屏仍显示深色主题,仅跟随系统设置而非应用自身主题配置。该问题在Pixel模拟器上不存在。

现有代码实现

主题切换函数

fun changeTheme(context: Context, state: DarkModeState) {
    SharedPrefsHelper.putInt(Consts.Prefs.DARK_MODE, state.ordinal)
    val mode = when {
        state == DarkModeState.ON && isSdk31AndUp -> UiModeManager.MODE_NIGHT_YES
        state == DarkModeState.ON -> AppCompatDelegate.MODE_NIGHT_YES
        state == DarkModeState.OFF && isSdk31AndUp -> UiModeManager.MODE_NIGHT_NO
        state == DarkModeState.OFF -> AppCompatDelegate.MODE_NIGHT_NO
        state == DarkModeState.SYSTEM && isSdk31AndUp -> UiModeManager.MODE_NIGHT_AUTO
        state == DarkModeState.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
        else -> return
    }

    if (isSdk31AndUp) {
        context.applicationContext.getSystemService(UiModeManager::class.java).apply {
            setApplicationNightMode(mode)
        }
        return
    }
    AppCompatDelegate.setDefaultNightMode(mode)
}

BaseTheme

<style name="BaseTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
    <!-- No Actionbar theme -->
    <item name="colorPrimary">@color/primary</item>
    <item name="colorAccent">@color/primary</item>
    <item name="android:statusBarColor">@color/layerTwoBg</item>
    <item name="android:windowBackground">@color/surfaceBg</item>
    <item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
</style>

闪屏主题(浅色模式)

res/values/splash_theme.xml

<style name="Theme.AppSplash" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/white</item>
    <item name="android:windowBackground">@color/white</item>
    <item name="postSplashScreenTheme">@style/AppTheme</item>
    <item name="android:statusBarColor">@color/white</item>
    <item name="android:navigationBarColor">@color/white</item>
    <item name="android:windowLightStatusBar" tools:targetApi="m">true</item>
    <item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
</style>

闪屏主题(深色模式)

res/values-night/splash_theme.xml

<style name="Theme.AppSplash" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/surfaceBg</item>
    <item name="android:windowBackground">@color/surfaceBg</item>
    <item name="postSplashScreenTheme">@style/AppTheme</item>
    <item name="android:statusBarColor">@color/surfaceBg</item>
    <item name="android:navigationBarColor">@color/surfaceBg</item>
    <item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
    <item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
</style>

启动Activity

override fun onCreate(savedInstanceState: Bundle?) {
    installSplashScreen()
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
}

AndroidManifest配置

<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:enableOnBackInvokedCallback="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:networkSecurityConfig="@xml/network_security_config"
    android:roundIcon="@drawable/ic_launcher"
    android:screenOrientation="portrait"
    android:supportsRtl="false"
    android:theme="@style/Theme.AppSplash"
    tools:ignore="HardcodedDebugMode"
    tools:replace="android:supportsRtl">

    <activity
        android:name=".view.main.MainActivity"
        android:exported="true"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustPan">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

依赖配置

implementation "androidx.core:core-splashscreen:1.0.1"

问题根源

Android 12+的Splash Screen API在部分厂商定制系统(如三星One UI)中,应用启动时的闪屏主题加载时机早于应用内主题配置的生效时机,导致系统优先读取系统夜间模式状态,而非应用自身保存的主题设置。

修复方案

1. 提前在Application初始化时设置主题

在MyApplication的onCreate中优先读取保存的主题状态并设置,确保闪屏加载前应用主题已生效:

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // 读取保存的深色模式状态
        val darkModeOrdinal = SharedPrefsHelper.getInt(Consts.Prefs.DARK_MODE, DarkModeState.SYSTEM.ordinal)
        val darkModeState = DarkModeState.values()[darkModeOrdinal]
        // 提前设置应用主题
        changeTheme(this, darkModeState)
    }

    private fun changeTheme(context: Context, state: DarkModeState) {
        val mode = when {
            state == DarkModeState.ON && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> UiModeManager.MODE_NIGHT_YES
            state == DarkModeState.ON -> AppCompatDelegate.MODE_NIGHT_YES
            state == DarkModeState.OFF && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> UiModeManager.MODE_NIGHT_NO
            state == DarkModeState.OFF -> AppCompatDelegate.MODE_NIGHT_NO
            state == DarkModeState.SYSTEM && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> UiModeManager.MODE_NIGHT_AUTO
            state == DarkModeState.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
            else -> return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            context.applicationContext.getSystemService(UiModeManager::class.java).apply {
                setApplicationNightMode(mode)
            }
            return
        }
        AppCompatDelegate.setDefaultNightMode(mode)
    }
}

2. 强化forceDarkAllowed属性

移除闪屏主题中tools:targetApi="q"限制,确保android:forceDarkAllowed="false"在所有版本生效,避免厂商系统强制切换深色:

<!-- res/values/splash_theme.xml -->
<style name="Theme.AppSplash" parent="Theme.SplashScreen">
    <!-- 其他属性保留 -->
    <item name="android:forceDarkAllowed">false</item>
</style>
<!-- res/values-night/splash_theme.xml -->
<style name="Theme.AppSplash" parent="Theme.SplashScreen">
    <!-- 其他属性保留 -->
    <item name="android:forceDarkAllowed">false</item>
</style>

3. 延迟闪屏隐藏(可选)

若前两种方案无效,可通过延迟闪屏隐藏给主题加载留足时间:

override fun onCreate(savedInstanceState: Bundle?) {
    val splashScreen = installSplashScreen()
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    
    // 设置闪屏保留条件,等待主题加载完成
    var isThemeReady = false
    splashScreen.setKeepOnScreenCondition { isThemeReady }
    
    // 模拟主题加载完成,实际可根据主题设置状态调整延迟时间
    Handler(Looper.getMainLooper()).postDelayed({
        isThemeReady = true
    }, 100)
    
    setContentView(binding.root)
}

验证步骤

  1. 切换应用主题为浅色,杀死应用进程后重新启动
  2. 检查三星设备上闪屏是否显示浅色主题
  3. 确认应用主界面主题切换正常

内容的提问来源于stack exchange,提问作者Baset Esmaeili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 02:58:08