在 WebView 中将网页内容调暗

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

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

下表描述了 WebView 如何根据 Web 内容的样式和应用条件在您的应用中渲染 Web 内容:

应用条件 使用 prefers-color-scheme 的 Web 内容 不使用 prefers-color-scheme 的 Web 内容
应用使用的是浅色主题,其中 isLightTheme 设置为 true 或未设置。 WebView 使用内容作者定义的浅色主题渲染内容。 WebView 使用内容作者定义的默认样式渲染内容。
应用正在使用强制深色,以便算法性地将深色主题应用于应用。 WebView 使用内容作者定义的深色主题渲染内容。 如果内容作者允许,WebView 会使用算法生成的深色主题渲染内容。
应用使用的是深色主题,其中 isLightTheme 设置为 false,并且应用不允许对 WebView 进行算法性调暗。 WebView 使用内容作者定义的深色主题渲染内容。 WebView 使用内容作者定义的默认样式渲染内容。
应用使用的是深色主题,其中 isLightTheme 设置为 false,并且应用允许对 WebView 进行算法性调暗 WebView 使用内容作者定义的深色主题渲染内容。 如果内容作者允许,WebView 会使用算法生成的深色主题渲染内容。

内容作者样式

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

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

算法性调暗

为了处理 Web 内容不使用 prefers-color-scheme 的情况,您的应用可以在必要时允许 WebView 算法性地将深色主题应用于其渲染的 Web 内容。

如果您的应用正在使用应用级别的强制深色以便算法性地将深色主题应用于您的应用,请参阅下一节,其中描述了如何使用强制深色允许对 Web 内容进行算法性调暗

如果您的应用未使用强制深色,应用何时允许在 WebView 中进行算法性调暗取决于应用的目标 API 级别。有关详细信息,请参阅针对Android 13 或更高版本的应用和针对Android 12 或更低版本的应用的以下部分。

使用强制深色允许对 Web 内容进行算法性调暗

如果您的应用正在使用应用级别的强制深色,WebView 会在满足以下条件时对 Web 内容应用算法性调暗:

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

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

强制深色模式主要用于不提供自己的深色主题的应用的向后兼容性。如果您的应用使用强制深色,我们建议添加对深色主题的支持

允许算法性调暗(以 Android 13 或更高版本为目标的应用)

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

如果满足以下条件,WebView 随后会应用算法性调暗:

  • Web 内容不使用 prefers-color-scheme
  • Web 内容作者未明确禁用调暗。

允许算法性调暗(以 Android 12 或更低版本为目标的应用)

对于未使用应用级别强制深色且以 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;
    }
}

自定义深色主题处理

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

使用该 API,您的应用可以使用 Web 主题调暗或用户代理调暗:

  • Web 主题调暗:Web 开发者可能会应用 @media (prefers-color-scheme: dark) 来控制网页在深色模式下的外观。WebView 根据这些设置渲染内容。有关 Web 主题调暗的更多信息,请参阅规范
  • 用户代理调暗: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 媒体查询自定义的第一方 Web 内容,我们建议使用 DARK_STRATEGY_WEB_THEME_DARKENING_ONLY 以确保 WebView 使用自定义主题。

有关应用深色主题的示例,请参阅 GitHub 上的 WebView 演示