在 WebView 中调暗 Web 内容

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

WebView 的行为可与 prefers-color-schemecolor-scheme Web 标准进行互操作。如果您编写了要在 WebView 中显示的 Web 内容,那么您应尽可能为网站定义深色主题并实现 prefers-color-scheme,以便 WebView 将 Web 内容的主题与应用的主题进行匹配。

下表介绍了 WebView 如何根据 Web 内容的样式和应用的条件在应用中呈现 Web 内容:

应用条件 使用 prefers-color-scheme 的网络内容 未使用 prefers-color-scheme 的 Web 内容
应用使用的是浅色主题,并将 isLightTheme 设置为 true 或未设置。 WebView 使用内容作者定义的浅色主题渲染内容。 WebView 使用内容作者定义的默认样式来呈现内容。
应用使用 Force Dark 为应用通过算法应用深色主题 WebView 使用内容作者定义的深色主题来呈现内容。 如果内容作者允许,WebView 会使用通过算法生成的深色主题来渲染内容。
应用使用的是深色主题,并将 isLightTheme 设置为 false,并且应用不允许通过算法加深 WebView。 WebView 使用内容作者定义的深色主题来呈现内容。 WebView 使用内容作者定义的默认样式来呈现内容。
应用使用的是深色主题,并将 isLightTheme 设置为 false,并且该应用允许 为 WebView 进行算法加深 WebView 使用内容作者定义的深色主题来呈现内容。 如果内容作者允许,WebView 会使用通过算法生成的深色主题来渲染内容。

Content-author 样式设置

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

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

算法加深

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

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

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

使用 Force Dark 允许通过算法调暗网页内容

如果您的应用使用的是应用级 Force Dark,WebView 会在满足以下条件时对网页内容应用算法加深:

  • WebView 及其父元素允许使用 Force Dark。
  • 当前的 activity 主题标记为浅色,并将 isLightTheme 设置为 true
  • 网络内容作者并未明确停用加深模式。
  • 对于以 Android 13(API 级别 33)或更高版本为目标平台的应用,Web 内容不使用 prefers-color-scheme
  • 对于以 Android 12(API 级别 32)或更低版本为目标平台的应用:应用已将 WebView 的 forceDarkMode 设置设为 FORCE_DARK_AUTO,并将其 Force Dark 策略设为 DARK_STRATEGY_USER_AGENT_DARKENING_ONLY

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

强制使用深色模式主要是为了在未提供自己的深色主题的应用中实现向后兼容性。如果您的应用使用 Force Dark,我们建议您添加对深色主题的支持

允许使用算法调暗功能(以 Android 13 或更高版本为目标平台的应用)

对于未使用应用级 Force Dark 并且以 Android 13(API 级别 33)或更高版本为目标平台的应用,请使用 AndroidX setAlgorithmicDarkeningAllowed() 方法并传入 true 以指定 WebView 应允许算法加深。此方法可向后兼容以前的 Android 版本。

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

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

允许使用算法调暗功能(以 Android 12 或更低版本为目标平台的应用)

对于未使用应用级 Force Dark 且以 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;
    }
}

自定义深色主题处理

您还可以使用 AndroidX 中的 ForceDarkStrategy API 来控制如何对给定 WebView 应用加深。仅当强制深色设置为 FORCE_DARK_ONFORCE_DARK_AUTO 时,此 API 才适用。

通过该 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 媒体查询。您可以在 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 演示