Ответ 1
Мы все знаем, что это недостающая часть API, поэтому что вы можете сделать для ее реализации самостоятельно? Подумайте, что такое WebView:
Встроенный компонент браузера основан на WebKit [...] По умолчанию WebKit не поддерживает рендеринг веб-страниц. Чтобы отображать и отображать HTML-контент, Oracle должен был написать собственный рендеринг с использованием Java Graphics 2D API.
Это означает, что двигатель должен иметь реализацию. Реализация WebKit находится в пакете com.sun.webkit
(значительная часть классов - это всего лишь оболочка для собственных вызовов). Конечно, в большинстве случаев вы не хотите использовать com.sun.*
, Но в настоящее время вы работаете с JavaFX, поэтому это не имеет большого значения.
Если мы немного подпрыгиваем в источниках солнца, мы можем найти WCMediaPlayer.class
с некоторыми абстрактными аудио методами, такими как:
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);
C'mon Java, позвольте мне позвонить вам:
volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class);
volumeMethod.setAccessible(true);
Я ценю вашу помощь, но как я могу получить экземпляры WCMediaPlayer
? Мы должны посмотреть ссылки на new WCMediaPlayerImpl()
. Попался! WCGraphicsManager.class
создает MediaPlayer методом fwkCreateMediaPlayer()
, в конце концов, он помещает указатель и экземпляр в refMap
:
Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap");
refMapField.setAccessible(true);
К счастью, менеджер разоблачил getGraphicsManager()
чтобы получить экземпляр:
WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager();
refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);
Сопряженная карта содержит экземпляры Ref
(есть и другие экземпляры WC*
), поэтому вам необходимо их отфильтровать:
Collection<WCMediaPlayer> mediaPlayers = refMap.values().stream()
.filter(ref -> ref instanceof WCMediaPlayer)
.map(ref -> (WCMediaPlayer) ref)
.collect(Collectors.toList());
Вероятно, вы ожидаете рабочего примера, поэтому вот код, который я использовал:
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());
}
}
Наконец, вспомните о порядке этих вызовов. Например, refMap
не содержит всех Refs
, пока состояние двигателя не является SUCCEEDED
или WCGraphicsManager.getGraphicsManager()
возвращает null
, если графический элемент не создается вообще.
Вероятно, наилучшим способом является объединение этих решений. Трудно поддерживать соединение веб-технологий без scenerio и плохой API, предоставляемый JavaFX. Вы также можете попробовать внедрить другой браузер, например, Chromium.