在 WebView 中调暗 Web 内容

在 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 以算法方式将深色 主题应用于其呈现的网络内容。

如果您的应用使用应用级 Force Dark以算法方式 将深色主题应用于应用,请参阅以下部分,了解如何 允许 Force Dark 对网络内容进行算法加深

如果您的应用未使用强制深色模式,则应用指定何时允许在 WebView 中进行算法加深的方式取决于应用的目标 API 级别。如需了解详情,请参阅以下部分,了解 以 Android 13 或更高版本为目标平台的应用以 Android 12 或更低版本为目标平台的应用

允许强制深色模式对 Web 内容进行算法加深

如果您的应用使用应用级 强制深色模式,则当满足以下条件时,WebView 会对 Web 内容应用 算法加深:

  • WebView 及其父元素允许强制深色模式。
  • 当前 activity 主题被标记为浅色,且 isLightTheme 设置为 true
  • 网络内容作者未明确停用加深。
  • 对于以 Android 13(API 级别 33)或更高版本为目标平台的应用,网络内容不使用 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)或更高版本为目标平台的应用,请使用 Jetpack Webkit setAlgorithmicDarkeningAllowed() 方法并传入 true,以指定 WebView 应允许算法 加深。此方法与之前的 Android 版本向后兼容。

然后,如果满足以下条件,WebView 会应用算法加深:

  • 网络内容不使用 prefers-color-scheme
  • 网络内容作者未明确停用加深。

允许算法加深(以 Android 12 或更低版本为目标平台的应用)

对于不使用应用级强制深色模式且以 Android 12(API 级别 32) 或更低版本为目标平台的应用,请使用 FORCE_DARK_ON 以允许算法加深。

如果您的应用提供了自己的方法来切换浅色和深色主题(例如界面中的可切换元素或基于时间的自动选择),请将 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;
    }
}

自定义深色主题处理

您还可以使用 ForceDarkStrategy API 在 Jetpack 库中控制如何将加深应用于给定的 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 演示