在 WebView 中使网页内容变暗

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

WebView 的行为与 prefers-color-schemecolor-scheme 网页标准交互。如果可能,如果您编写了希望应用在 WebView 中显示的网页内容,则应 为您的网站定义深色主题 并实现 prefers-color-scheme,以便 WebView 可以将网页内容的主题与应用的主题相匹配。

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

应用条件 使用 prefers-color-scheme 的网页内容 不使用 prefers-color-scheme 的网页内容
应用正在使用亮色主题,其中 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

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

算法变暗

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

如果您的应用正在使用应用级 强制深色 以算法方式将深色主题应用于您的应用,请参阅以下部分,该部分介绍了如何 允许使用强制深色对网页内容进行算法变暗。

如果您的应用未使用强制深色,则您的应用如何指定何时允许 WebView 进行算法变暗取决于您的应用的 目标 API 级别。 有关详细信息,请参阅以下部分,了解 目标 API 级别为 33 或更高的应用目标 API 级别为 32 或更低的应用。

使用强制深色允许网页内容进行算法变暗

如果您的应用正在使用应用级 强制深色,则 WebView 会在满足以下条件时将算法变暗应用于网页内容

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

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

允许网页内容进行算法变暗(目标 API 级别为 33 或更高的应用)

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

然后,WebView 会在满足以下条件时应用算法变暗

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

允许网页内容进行算法变暗(目标 API 级别为 32 或更低的应用)

对于不使用应用级强制深色且目标 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,您的应用可以使用网页主题深色或用户代理深色。

  • 网页主题深色:网页开发者可能会应用 @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 媒体查询。您可以将 WebView 与 DARK_STRATEGY_WEB_THEME_DARKENING_ONLY 模式一起使用,在这种情况下,即使省略了标签,WebView 也会始终应用媒体查询。

    但是,我们建议网页开发者将其网站添加 <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 演示