Tengo una aplicación de Android que usa webview, y últimamente estoy tratando de descubrir cómo agregar un tema oscuro usando la nueva sintaxis CSS @media (prefers-color-scheme: dark) . Tengo el CSS correcto escrito en mi página, y si lo abro en Chrome con el modo oscuro de Chrome activado, funciona. También tengo mi AppTheme heredando Theme.AppCompat.DayNight , y mi aplicación muestra un cuadro de diálogo de carga oscuro, etc. cuando enciendo el modo oscuro para todo el sistema operativo en mi dispositivo. Incluso las opciones de autocompletar para los elementos <input> se oscurecen. Pero aún así, la página web cargada con mi vista web no se oscurece. De acuerdo con esta página , las vistas web deberían admitir esta función, pero simplemente no puedo hacer que funcione. ¿Que me estoy perdiendo aqui?
También descubrí que en la API 29 existe este método WebSettings.setForceDark() ; ¿podría ser lo que estoy buscando? Sin embargo, espero encontrar una solución que funcione con un nivel de API más bajo.
Por cierto, mi solución actual es inyectar una interfaz de JavaScript como esta:
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; } } Y luego, en mi página web, llame al método jsInterface.isNightMode() y cargue dinámicamente diferentes archivos CSS según el resultado. Ciertamente funciona y responde a la configuración del modo oscuro global como se desea, pero todavía me pregunto si puedo hacer que funcione prefers-color-scheme .
No creo que WebView respete la consulta de medios CSS de esquema de color preferido todavía.
La nueva API para setForceDark tiene tres estados: activado, desactivado o automático.
ENCENDIDO: su contenido siempre se volverá más oscuro cada vez.
APAGADO: su contenido siempre se volverá ligero cada vez.
AUTO: el contenido se volverá más oscuro si el tema de su aplicación es más oscuro O si el sistema operativo del dispositivo está en modo oscuro porque el usuario activa el interruptor de nivel del sistema operativo o el modo de ahorro de batería.
Creo que la compatibilidad con versiones anteriores de Android y también el control sobre si se usa el esquema de color preferido en lugar de Force Dark de WebView llegará pronto a través de AndroidX. La fecha de vencimiento es desconocida en la actualidad.
Por ahora, recomendaría configurar WebView en setForceDark Auto. Esto funcionará en Android Q y superior.
Estaría atento a las notas de la versión de AndroidX para obtener el resto del soporte que necesita para los dispositivos con Android P e inferior.
Lo que hago, según su código de pregunta, es forzar según el estado actual:
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) { webSettings.setForceDark(WebSettings.FORCE_DARK_ON); } De esta manera, @media (prefers-color-scheme: dark) funciona, pero @media (prefers-color-scheme: light) todavía no funciona (intenté usar FORCE_DARK_OFF y FORCE_DARK_AUTO en otra parte)
Hay dos piezas relevantes de documentación aquí:
https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force_dark
https://developer.android.com/reference/android/view/View.html#setForceDarkAllowed(booleano)
Los puntos clave son
Esto significa que lograr que el comportamiento FORCE_DARK_AUTO funcione en WebView es un poco complejo. Agregar lo siguiente a un tema AppCompat.DayNight funciona, pero tal vez no sea la mejor solución, ya que puede aplicar la oscuridad de Android a otras vistas que no sean WebView.
<item name="android:forceDarkAllowed">true</item> <item name="android:isLightTheme">true</item>La otra opción es manejar esto manualmente, configurando FORCE_DARK_ON/OFF según el cambio de configuración relevante.
Actualmente, WebView no es compatible con el esquema de color preferido en parte porque se implementó la oscuridad forzada antes de la estandarización del esquema de color preferido, y en parte porque no hay forma de integrar eso de manera sensata (sin destellos de estilo) con la oscuridad forzada. La intención es proporcionar la capacidad de elegir forzar la oscuridad o el esquema de color preferido a través de androidx.webkit.
Android Webview maneja el modo día/noche de forma un poco diferente al resto de las vistas. Configurar su tema en oscuro cambiará los componentes de WebView (barra de desplazamiento, botones de zoom, etc.) a una versión de modo oscuro, pero no cambiará el contenido que cargó.
Para cambiar el contenido, debe usar el método setForceDark de la configuración de la vista web para que también cambie su contenido. Se puede encontrar una versión de compatibilidad de este método en el paquete webkit de AndroidX.
Agregue la siguiente dependencia a su compilación de gradle:
implementation 'androidx.webkit:webkit:1.3.0'(1.3.0 es la versión mínima requerida de este paquete. Pero las versiones superiores también deberían funcionar).
Y agregue las siguientes líneas de código a la inicialización de su vista web:
if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { WebSettingsCompat.setForceDark(myWebView.getSettings(), WebSettingsCompat.FORCE_DARK_ON); } La verificación isFeatureSupported está ahí para asegurarse de que la versiónWebView del sistema Android que el usuario instaló en su dispositivo admita el modo oscuro (ya que esto se puede actualizar o degradar independientemente de la versión de Android a través de Google Play).
Nota: La función setForceDark requiere que el sistema Android WebView v76 o superior esté instalado en el dispositivo en ejecución.
La característica de forzar la oscuridad para el contenido webview tiene dos estrategias:
Oscurecimiento del agente de usuario: la vista web configurará su contenido en modo oscuro invirtiendo u oscureciendo automáticamente los colores de su contenido.
Oscurecimiento basado en el tema: la vista web cambiará al modo oscuro según el tema del contenido (que incluye la consulta @media (prefers-color-scheme: dark) ).
Para establecer qué estrategia debe usar la vista web para aplicar fuerza oscura, puede usar el siguiente código:
if(WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { WebSettingsCompat.setForceDarkStrategy(myWebView.getSettings(), WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY); } Nota: La selección de estrategia requiere que el sistema Android WebView v83 o superior esté instalado en el dispositivo en ejecución. Las versiones de WebView que admiten setForceDark pero no admiten selecciones de estrategia (v76 a v81) usarán el oscurecimiento del agente de usuario
Las opciones de estrategia admitidas son:
¿Cómo funcionan las comprobaciones de Javascript para vistas web oscurecidas?
La llamada de JavaScript window.matchMedia('(prefers-color-scheme: dark)') coincidirá tanto en el oscurecimiento del agente de usuario como en la estrategia de oscurecimiento del tema web.
Tengo mi vista web configurada en FORCE_DARK_AUTO y mi aplicación se ejecuta en un tema de día y noche, pero de alguna manera mi vista web no aplica el modo oscuro automáticamente según el tema de mi aplicación. ¿Por qué pasó esto?
Es porque el valor de configuración FORCE_DARK_AUTO de la vista web no funciona según los temas (como se indica en la documentación ). Comprueba la función Force Dark de Android 10 (una función de modo oscuro de "solución rápida" para aplicaciones. Tiene un nombre similar, pero no está directamente relacionado con WebView force dark).
Si no está usando forzar oscuridad sino un tema de aplicación para manejar el modo oscuro (como se recomienda), debe implementar su propia verificación para saber cuándo aplicar la función forzar oscuridad de la vista web. Un ejemplo cuando se usa un tema 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 }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); } }para Webview hasta v93 (implementación 'androidx.webkit:webkit:1.4.0'), la bandera DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING no me funcionaba hasta que usé este código:
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)que solicita el tema oscuro del sitio, pero no fuerza la inversión de color.