31

我有一个使用 webview 的 Android 应用程序,最近我试图弄清楚如何通过使用新的@media (prefers-color-scheme: dark)CSS 语法来添加深色主题。我在我的页面上写了正确的 CSS,如果我在 Chrome 中打开它并打开 Chrome 的暗模式,它就可以工作。我也有我的AppTheme继承Theme.AppCompat.DayNight,当我为设备上的整个操作系统打开暗模式时,我的应用程序会显示暗加载对话框等。甚至元素的自动完成选项也会<input>变暗。但是,我的 webview 加载的网页仍然没有变暗。根据这个页面,webviews 应该支持这个特性,但我就是不能让它工作。我在这里想念什么?

我也刚刚发现在 API 29 中有这个WebSettings.setForceDark()方法;会不会是我要找的东西?我希望找到一个适用于较低 API 级别的解决方案。

顺便说一句,我目前的解决方法是注入这样的 JavaScript 接口:

webView.addJavascriptInterface(new JSInterface(), "jsInterface");

...

public class JSInterface {
    @JavascriptInterface
    public boolean isNightMode() {
        int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
        return nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
    }
}

然后在我的网页中,调用该jsInterface.isNightMode()方法并根据结果动态加载不同的 CSS 文件。它当然可以根据需要对全局暗模式设置做出响应,但我仍然想知道我是否可以prefers-color-scheme工作。

4

6 回答 6

49

Android Webview 处理日/夜模式与其他视图略有不同。将您的主题设置为深色会将 WebView 组件(滚动条、缩放按钮等)更改为深色模式版本,但不会更改它加载的内容。

要更改内容,您需要使用 webview 设置的 setForceDark 方法使其也更改其内容。此方法的兼容版本可以在 AndroidX webkit 包中找到。

将以下依赖项添加到您的 gradle 构建中:

implementation 'androidx.webkit:webkit:1.3.0'

(1.3.0 是此软件包的最低要求版本。但更高版本也应该可以工作。)

并将以下代码行添加到您的 webview 初始化中:

if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(myWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON);
}

检查是为了isFeatureSupported确保用户在其设备上安装的Android System WebView版本支持暗模式(因为这可以通过 Google Play 独立于 Android 版本进行更新或降级)。

注意:该功能需要在运行的设备上安装setForceDarkAndroid System WebView v76或更高版本。

webview 内容的 force dark 功能有两个所谓的策略:

  • 用户代理变暗: webview 将通过自动反转或变暗其内容的颜色将其内容设置为暗模式。

  • 基于主题的变暗: webview 将根据内容的主题(包括@media (prefers-color-scheme: dark)查询)更改为暗模式。

要设置 webview 应该使用哪种策略来应用强制黑暗,您可以使用以下代码:

if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
    WebSettingsCompat.setForceDarkStrategy(myWebView.getSettings(), WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY);
}

注意:策略选择需要在运行设备上安装Android System WebView v83或更高版本。setForceDark支持但不支持策略选择的WebView 版本(v76 到 v81)将使用用户代理变暗

支持的策略选项有:

  • DARK_STRATEGY_USER_AGENT_DARKENING_ONLY:仅使用用户代理变暗并忽略内容中的任何主题(默认)
  • DARK_STRATEGY_WEB_THEME_DARKENING_ONLY:仅使用内容本身的深色主题将页面设置为深色模式。如果内容没有深色主题,则 webview 不会应用任何变暗并“按原样”显示。
  • DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING:使用内容本身的深色主题将页面设置为深色模式。如果内容没有深色主题,请使用用户代理变暗。

Javascript 检查如何对变暗的 webviews 起作用?

JavaScript 调用window.matchMedia('(prefers-color-scheme: dark)')将在用户代理变暗和 Web 主题变暗策略中匹配。

我的 webview 设置为 FORCE_DARK_AUTO 并且我的应用程序在昼夜主题中运行,但不知何故,我的 webview 不会根据我的应用程序主题自动应用暗模式。为什么会这样?

这是因为FORCE_DARK_AUTOwebview 的设置值不适用于主题(如文档中所述)。它检查Android 10 强制黑暗功能(应用程序的“快速修复”黑暗模式功能。它的名称类似,但与 WebView 强制黑暗没有直接关系)。

如果您没有使用强制黑暗,而是使用应用程序主题来处理黑暗模式(如推荐的那样),您必须自己检查何时应用 webview 的强制黑暗功能。使用 DayNight 主题的示例:

int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
   //Code to enable force dark using FORCE_DARK_ON and select force dark strategy 
}
于 2020-05-06T19:21:27.473 回答
8

根据您的问题代码,我所做的是根据当前状态强制执行:

int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) {
  webSettings.setForceDark(WebSettings.FORCE_DARK_ON);
}

这种方式@media (prefers-color-scheme: dark)有效,但@media (prefers-color-scheme: light)仍然无效(尝试使用FORCE_DARK_OFFand FORCE_DARK_AUTOin an else)

于 2019-10-20T14:32:05.833 回答
3

这里有两个相关的文档:

https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force_dark

https://developer.android.com/reference/android/view/View.html#setForceDarkAllowed(boolean)

关键点是

  1. WebView 必须允许强制变暗,它的所有父项也必须允许。
  2. 主题必须标记为浅色。

这意味着让 FORCE_DARK_AUTO 行为在 WebView 中起作用有点复杂。将以下内容添加到 AppCompat.DayNight 主题确实有效,但可能不是最佳解决方案,因为它可能会将 Android 强制黑暗应用于 WebView 以外的视图。

<item name="android:forceDarkAllowed">true</item>
<item name="android:isLightTheme">true</item>

另一种选择是手动处理此问题,方法是根据相关配置更改设置 FORCE_DARK_ON/OFF。

目前 WebView 不支持 prefers-color-scheme,部分原因是在 prefers-color-scheme 标准化之前实施了强制暗,部分原因是无法将其明智地(没有样式闪烁)与强制暗集成。目的是提供通过 androidx.webkit 选择强制黑暗或偏好颜色方案的能力。

于 2019-11-05T11:03:49.297 回答
1

我认为 WebView 还不支持 prefers-color-scheme CSS 媒体查询。

setForceDark 的新 API 具有三种状态:开、关或自动。

开 - 您的内容每次都会被渲染得更暗。

关闭 - 您的内容每次都将始终呈现光亮。

自动 - 如果您的应用程序的主题更暗或设备操作系统处于黑暗模式,则内容将呈现更暗,因为用户切换了操作系统级别开关或打开了省电模式。

我相信对旧版本 Android 的支持以及对是否使用偏好颜色方案而不是 WebView 的强制黑暗的控制即将通过 AndroidX 推出。截止日期目前未知。

现在我建议将 WebView 设置为 setForceDark Auto。这将适用于 Android Q 及更高版本。

我会密切关注 AndroidX 发行说明,了解您对 Android P 及以下设备所需的其余支持。

于 2019-08-20T07:22:21.200 回答
1
implementation 'androidx.webkit:webkit:1.4.0'


WebSettings settings = webView.getSettings();

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
   if (isNightMode) {
      WebSettingsCompat.setForceDark(settings, WebSettingsCompat.FORCE_DARK_ON);
   } else {
      WebSettingsCompat.setForceDark(settings, WebSettingsCompat.FORCE_DARK_OFF);
   }
}
于 2021-05-30T16:44:30.220 回答
0

对于最高 v93 的 Webview(实现 'androidx.webkit:webkit:1.4.0'),标志 DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING 在我使用此代码之前对我不起作用:

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
            if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)){            
            WebSettingsCompat.setForceDarkStrategy(
                webView.settings,
                WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY
            )
        }
        WebSettingsCompat.setForceDark(webView.settings, WebSettingsCompat.FORCE_DARK_ON)
    }    
webView.evaluateJavascript("document.documentElement.setAttribute('data-color-mode', 'dark');", null)

它请求网站的深色主题,但不强制颜色反转。

于 2021-09-27T08:18:52.013 回答