example java javafx webview javafx-webview

example - webview java netbeans



Silenciar una vista web en JavaFX, ¿es posible? (3)

En este momento, NO existe dicha API para el sistema de sonido en WebView o WebEngine Control.

Pero puedes inyectar JavaScript para silenciar / activar el sonido y controlar los sonidos. Este método solo funciona con elementos HTML5 <video> o <audio> , porque los elementos como el audio inicializado de Flash o JS son imposibles de restringir en general. He creado un programa de ejemplo para ti:

import javafx.application.Application; import javafx.event.ActionEvent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.VBox; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import javafx.stage.Stage; public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ WebView myWebView = new WebView(); WebEngine engine = myWebView.getEngine(); //dirty code xD Button btn = new Button("Load Youtube"); btn.setOnAction((ActionEvent event) -> engine.load("http://www.youtube.com/embed/A6hrw6KGdtM?autoplay=1")); Button btn2 = new Button("Mute"); btn2.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(true))); Button btn3 = new Button("Unmute"); btn3.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(false))); Button btn4 = new Button("+"); btn4.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.9))); Button btn5 = new Button("-"); btn5.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.1))); VBox root = new VBox(); root.getChildren().addAll(myWebView, btn, btn2, btn3, btn4, btn5); Scene scene = new Scene(root, 800, 500); primaryStage.setScene(scene); primaryStage.setTitle("Mute a WebView in JavaFX, is it possible?"); primaryStage.show(); } /** * @param mute * @return JS code for mute/unmute */ public String getJSAudioVideo(boolean mute){ return "var videos = document.querySelectorAll(''video''),/n" + " audios = document.querySelectorAll(''listen'');/n" + " [].forEach.call(videos, function(video) { video.muted = "+String.valueOf(mute)+"; });/n" + " [].forEach.call(audios, function(audio) { audio.muted = "+String.valueOf(mute)+"; });"; } /** * @param volume * @return JS code for setting volume sound */ public String getJSSoundVolume(double volume){ //max 1.0, min 0.0 Default: 1.0 double _volume = (volume > 1.0 || volume < 0.0) ? 1.0 : volume; return "var videos = document.querySelectorAll(''video''),/n" + " audios = document.querySelectorAll(''listen'');/n" + " [].forEach.call(videos, function(video) { video.volume = "+String.valueOf(_volume)+"; });/n" + " [].forEach.call(audios, function(audio) { audio.volume = "+String.valueOf(_volume)+"; });"; } public static void main(String[] args) { launch(args); } }

Muy simple. ¿Es posible silenciar o controlar el volumen de un JavaFX WebView? Busqué en Google por un tiempo, pero no puedo encontrar ninguna mención de esto. Miré el código para WebView y WebEngine y no parece haber nada sobre controlar el volumen.

Todavía necesito otros MediaPlayer en la misma aplicación para trabajar y producir sonido, por lo tanto, no puedo silenciar toda la aplicación.


Para decir sobre WebView , es una extensión de la clase Node. Encapsula un objeto WebEngine, incorpora contenido HTML en la escena de una aplicación y proporciona propiedades y métodos para aplicar efectos y transformaciones. El método getEngine () llamado en un objeto WebView devuelve un motor web asociado. Source

Por lo tanto, WebView no admite ninguna API para el control de silencio / volumen en este momento. Hay una API para silenciar el contenido cargado en el MediaPlayer (es decir,)

Para obtener el estado de muteProperty: enlace de origen

public BooleanProperty muteProperty()

Para verificar la condición de silencio: enlace de origen

public final boolean isMute()

Para silenciar el video, establezca el valor en verdadero: enlace de origen

public final void setMute(boolean value)

O use la API de JavaScript para silenciar el video / audio:

getElementById("Your video Id");

y establece el control en Silenciar por:

vid.muted = true;

Enlace de origen


Todos sabemos que es una parte faltante de API, entonces, ¿qué puedes hacer para implementarlo por tu cuenta? Pensemos en lo que realmente es WebView:

El componente de navegador integrado se basa en WebKit [...] Por defecto, WebKit no admite el procesamiento de páginas web. Para representar y visualizar el contenido HTML, Oracle tuvo que escribir su propio renderizador utilizando la API Java Graphics 2D.

Significa que el motor debe tener implementación. La implementación de WebKit se encuentra en el paquete com.sun.webkit (una parte considerable de las clases es solo un contenedor para llamadas nativas) . Por supuesto, en la mayoría de los casos no quiere usar clases com.sun.* , Pero actualmente está trabajando con JavaFX, por lo que realmente no importa.

Si WCMediaPlayer.class un poco en las fuentes del sol, podemos encontrar WCMediaPlayer.class con algunos métodos de audio abstractos como:

protected abstract void setRate(float rate); protected abstract void setVolume(float volume); protected abstract void setMute(boolean mute); protected abstract void setSize(int w, int h); protected abstract void setPreservesPitch(boolean preserve);

Vamos, Java, déjame llamarte:

volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class); volumeMethod.setAccessible(true);

Agradezco tu ayuda, pero ¿cómo puedo obtener WCMediaPlayer instancias de WCMediaPlayer ? Tenemos que mirar las referencias al new WCMediaPlayerImpl() . Gotcha! WCGraphicsManager.class crea MediaPlayer por el método fwkCreateMediaPlayer() , después de todo, pone el puntero y la instancia en refMap :

Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap"); refMapField.setAccessible(true);

Afortunadamente, el administrador ha expuesto el método getGraphicsManager() para obtener una instancia:

WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager(); refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);

El mapa capturado contiene instancias Ref (también hay otras instancias WC* ) por lo que debe filtrarlas:

Collection<WCMediaPlayer> mediaPlayers = refMap.values().stream() .filter(ref -> ref instanceof WCMediaPlayer) .map(ref -> (WCMediaPlayer) ref) .collect(Collectors.toList());

Probablemente esperas un ejemplo de trabajo así que aquí está el código que utilicé:

public class WebEngineTest extends Application { private Map<Integer, Ref> refMap; private Method volumeMethod; @Override @SuppressWarnings("unchecked") public void start(Stage primaryStage) throws Exception { WebView webView = new WebView(); WebEngine engine = webView.getEngine(); engine.load("https://www.youtube.com/watch?v=hRAZBSoAsgs"); Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap"); refMapField.setAccessible(true); volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class); volumeMethod.setAccessible(true); WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager(); refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager); Button button = new Button("Volume"); button.setOnAction(event -> setVolume(0.1f)); Group group = new Group(); group.getChildren().addAll(webView, button); Scene scene = new Scene(group, 625, 625); primaryStage.setScene(scene); primaryStage.show(); } public void setVolume(float volume) { Collection<WCMediaPlayer> mediaPlayers = this.getMediaPlayers(); mediaPlayers.forEach(mediaPlayer -> setVolumeMethod(mediaPlayer, volume)); } private void setVolumeMethod(Object instance, Object... args) { try { volumeMethod.invoke(instance, args); } catch (Exception e) { e.printStackTrace(); } } private Collection<WCMediaPlayer> getMediaPlayers() { return refMap.values().stream() .filter(ref -> ref instanceof WCMediaPlayer) .map(ref -> (WCMediaPlayer) ref) .collect(Collectors.toList()); } }

Finalmente, recuerde el orden de estas llamadas. Por ejemplo, refMap no contiene todas las Refs hasta que el estado del motor no sea SUCCEEDED o WCGraphicsManager.getGraphicsManager() devuelve null si el elemento gráfico no se crea en absoluto.

Probablemente, la mejor manera es combinar estas soluciones. Es difícil admitir la combinación de tecnología web sin scenerio y API pobre proporcionada por JavaFX. También puede intentar insertar otro navegador, como Chromium.