使 WebView 中的网页内容变暗

在 Android 10 及更高版本中,应用可以支持深色主题,并根据系统主题在浅色和深色应用主题之间自动切换。为了与当前应用主题相匹配,WebView 中的网页内容也可以使用浅色、深色或默认样式。

WebView 的行为与 prefers-color-schemecolor-scheme Web 标准相互配合。如果可能,如果您是应用在 WebView 中所显示的网页内容的作者,您应该为您的网站定义深色主题并实现 prefers-color-scheme,以便 WebView 能够将网页内容的颜色与您应用的主题相匹配。

下表根据网页内容的样式和您的应用条件,描述了 WebView 在您的应用中呈现网页内容的方式:

应用条件 使用 prefers-color-scheme 的网页内容 未使用 prefers-color-scheme 的网页内容
应用使用的是浅色主题,且 isLightTheme 设置为 true 或未设置。 WebView 使用内容作者定义的浅色主题呈现内容。 WebView 使用内容作者定义的默认样式呈现内容。
应用正在使用“强制深色”(Force Dark) 以算法方式将深色主题应用于应用。 WebView 使用内容作者定义的深色主题呈现内容。 如果内容作者允许,WebView 将使用通过算法生成的深色主题来呈现内容。
应用正在使用深色主题,且 isLightTheme 设置为 false,并且应用不允许为 WebView 进行算法变暗。 WebView 使用内容作者定义的深色主题呈现内容。 WebView 使用内容作者定义的默认样式呈现内容。
应用正在使用深色主题,且 isLightTheme 设置为 false,并且应用允许为 WebView 进行算法变暗 WebView 使用内容作者定义的深色主题呈现内容。 如果内容作者允许,WebView 将使用通过算法生成的深色主题来呈现内容。

内容作者定义的样式

应用的 isLightTheme 属性用于指明应用主题是浅色还是深色。WebView 始终会根据 isLightTheme 设置 prefers-color-scheme。如果 isLightThemetrue 或未指定,则 prefers-color-schemelight;否则为 dark

这意味着,如果网页内容使用了 prefers-color-scheme 且内容作者允许,则内容作者定义的浅色或深色主题始终会自动应用于网页内容,以匹配应用主题。

算法变暗

为了涵盖网页内容未使用 prefers-color-scheme 的情况,您的应用可以在必要时允许 WebView 以算法方式将深色主题应用于所呈现的网页内容。

如果您的应用正在使用应用级的“强制深色”(Force Dark) 来以算法方式将深色主题应用于您的应用,请参阅下一节,了解如何通过“强制深色”允许网页内容的算法变暗

如果您的应用没有使用“强制深色”,则应用指定何时允许在 WebView 中进行算法变暗的方式取决于应用的目标 API 级别。有关详细信息,请参阅针对 Android 13 或更高版本以及 Android 12 或更低版本的应用的相应章节。

通过“强制深色”允许网页内容的算法变暗

如果您的应用正在使用应用级的“强制深色”(Force Dark),则在满足以下条件时,WebView 会对网页内容应用算法变暗:

  • WebView 及其父元素允许“强制深色”。
  • 当前 Activity 主题被标记为浅色,且 isLightTheme 设置为 true
  • 网页内容作者未明确禁用变暗功能。
  • 对于目标 API 级别为 Android 13 (API 33) 或更高的应用,网页内容未使用 prefers-color-scheme
  • 对于目标 API 级别为 Android 12 (API 32) 或更低的应用:应用已将 WebView 的 forceDarkMode 设置设为 FORCE_DARK_AUTO,并将强制深色策略设为 DARK_STRATEGY_USER_AGENT_DARKENING_ONLY

WebView 及其所有父级可以使用 View.setForceDarkAllowed() 允许强制深色。默认值取自 Android 主题的 setForceDarkAllowed() 属性,该属性也必须设置为 true

强制深色模式主要用于那些未提供自有深色主题的应用,以实现向后兼容。如果您的应用使用了“强制深色”,我们建议您添加对深色主题的支持

允许算法变暗(针对 Android 13 或更高版本的应用)

对于未使用应用级“强制深色”且目标 API 级别为 Android 13 (API 33) 或更高的应用,请使用 Jetpack Webkit 的 setAlgorithmicDarkeningAllowed() 方法并传入 true,以指定 WebView 应允许算法变暗。此方法向后兼容以前的 Android 版本。

此时,若满足以下条件,WebView 将应用算法变暗:

  • 网页内容未使用 prefers-color-scheme
  • 网页内容作者未明确禁用变暗功能。

允许算法变暗(针对 Android 12 或更低版本的应用)

对于未使用应用级“强制深色”且目标 API 级别为 Android 12 (API 32) 或更低的应用,请使用 FORCE_DARK_ON 来允许算法变暗。

如果您应用本身提供了切换浅色和深色主题的方法(例如 UI 中的切换开关或基于时间的选择),请将 FORCE_DARK_ONFORCE_DARK_OFF 配合使用。

要检查该功能是否受支持,请在配置 WebView 对象的任何位置(例如 Activity.onCreate)添加以下代码行:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(...)
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(...);
}

如果您的应用依赖于检测系统首选项的更改,则应显式监听主题更改,并使用 FORCE_DARK_ONFORCE_DARK_OFF 状态将这些更改应用于 WebView。

以下代码片段展示了如何更改主题格式:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
        Configuration.UI_MODE_NIGHT_YES -> {
            WebSettingsCompat.setForceDark(myWebView.settings, FORCE_DARK_ON)
        }
        Configuration.UI_MODE_NIGHT_NO, Configuration.UI_MODE_NIGHT_UNDEFINED -> {
            WebSettingsCompat.setForceDark(myWebView.settings, FORCE_DARK_OFF)
        }
        else -> {
            //
        }
    }
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    switch (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
        case Configuration.UI_MODE_NIGHT_YES:
            WebSettingsCompat.setForceDark(myWebView.getSettings(), FORCE_DARK_ON);
            break;
        case Configuration.UI_MODE_NIGHT_NO:
        case Configuration.UI_MODE_NIGHT_UNDEFINED:
            WebSettingsCompat.setForceDark(myWebView.getSettings(), FORCE_DARK_OFF);
            break;
    }
}

自定义深色主题处理

您还可以使用 Jetpack 库中的 ForceDarkStrategy API 来控制如何对给定的 WebView 应用变暗。此 API 仅在强制深色设置为 FORCE_DARK_ONFORCE_DARK_AUTO 时适用。

使用该 API,您的应用可以选择网页主题变暗或用户代理变暗:

  • 网页主题变暗:Web 开发者可以使用 @media (prefers-color-scheme: dark) 来控制网页在深色模式下的外观。WebView 根据这些设置呈现内容。有关网页主题变暗的更多信息,请参阅规范
  • 用户代理变暗:WebView 会自动反转网页的颜色。如果您使用用户代理变暗,@media (prefers-color-scheme: dark) 查询的计算结果将为 false

要在这两种策略之间进行选择,请使用以下 API:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
    WebSettingsCompat.setForceDarkStrategy(...)
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
    WebSettingsCompat.setForceDarkStrategy(...);
}

支持的策略选项包括:

  • DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING:这是默认选项。虽然大多数浏览器将 <meta name="color-scheme" content="dark light"> 标签视为可选,但 Android WebView 的默认模式要求必须包含该元标签,才能遵循网页的 prefers-color-scheme 媒体查询。您可以使用 DARK_STRATEGY_WEB_THEME_DARKENING_ONLY 模式的 WebView,在该模式下,即使省略了标签,WebView 也会始终应用媒体查询。

    不过,我们建议 Web 开发者在其网站中添加 <meta name="color-scheme" content="dark light"> 标签,以确保内容在采用默认配置的 WebView 中能正确呈现。

  • DARK_STRATEGY_USER_AGENT_DARKENING_ONLY:称为“用户代理变暗”,WebView 会忽略任何网页端的变暗处理并强制应用自动变暗。

如果您的应用展示的是您使用 prefers-color-scheme 媒体查询自定义的第一方网页内容,我们建议使用 DARK_STRATEGY_WEB_THEME_DARKENING_ONLY,以确保 WebView 使用自定义主题。

如需查看应用深色主题的示例,请参阅 GitHub 上的 WebView 演示