让Android上的WebView使用Preferreds-Color-Scheme:Dark

Mu-*_*sai 6 css android android-webview android-studio android-night-mode

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

我还发现在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Leo*_*die 43

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

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

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

implementation 'androidx.webkit:webkit:1.3.0'
Run Code Online (Sandbox Code Playgroud)

(1.3.0 是这个包的最低要求版本。但更高的版本应该也能工作。)

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

if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(myWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON);
}
Run Code Online (Sandbox Code Playgroud)

isFeatureSupported检查是有,以确保安卓系统WebView版本的用户已经安装在他们的设备支持深色模式(因为这可以更新或通过谷歌播放Android版本独立降级)。

注意:setForceDark功能需要在运行设备上安装Android 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);
}
Run Code Online (Sandbox Code Playgroud)

注:策略选择要求运行设备安装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 检查如何处理变暗的 webview?

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

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

这是因为FORCE_DARK_AUTOwebview的设置值不能基于主题工作(如文档所述)。它会检查Android 10 Force Dark功能(应用程序的“快速修复”暗模式功能。它的名称类似,但与 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 
}
Run Code Online (Sandbox Code Playgroud)

  • 您在该主题上的全面知识和专业知识令人难以置信。尽管您的答案涉及 alpha 版本包,但它确实可以按要求工作。 (5认同)

jce*_*ile 8

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

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

这种方式@media (prefers-color-scheme: dark)有效,但@media (prefers-color-scheme: light)仍然无效(尝试在其他情况下使用FORCE_DARK_OFFFORCE_DARK_AUTO

  • 我检查了 webview 并检查了与 `window.matchMedia("(prefers-color-scheme: ...)")` 匹配的媒体查询(可能的值为 `light`、`dark` 和 `no-preference`)。当模式最初设置为“DARK_ON”时,它与“dark”方案匹配。任何其他模式都匹配“无偏好”方案。此外,一旦我将模式设置为“DARK_OFF”或“DARK_AUTO”,稍后将其设置为“DARK_ON”就不会正确传播到 Web 视图。但反过来(即先“DARK_ON”,然后“DARK_OFF”)也有效。 (2认同)
  • 更准确地说:“getForceDark()”返回的值始终是预期值(即,当最后一个设置操作为“DARK_ON”时返回“2”,当最后一个设置操作为“DARK_OFF”时返回“0”)。但是在设置了“DARK_OFF”或“DARK_AUTO”之后设置“DARK_ON”,不再有任何可见的效果。 (2认同)