sexta-feira, 11 de junho de 2021

🌐 Visão Geral do JavaFX WebView: Como Embutir um Navegador em Aplicações Desktop

Visão Geral do JavaFX WebView

Neste blog, será analisada a forma como o JavaFX pode renderizar páginas da web e o componente responsável por isso – conhecido como WebView.


O JavaFX é uma:

  • Plataforma de software para criar e entregar aplicações desktop, bem como aplicações ricas para a internet (RIAs) que podem ser executadas em uma ampla variedade de dispositivos.
  • Conjunto de pacotes de gráficos e mídia que permite aos desenvolvedores projetar, criar, testar, depurar e implementar aplicações clientes ricas que operam de forma consistente em diversas plataformas.

Principais Características do JavaFX:

WebView: Um componente web que usa a tecnologia HTML WebKit para possibilitar a incorporação de páginas da web dentro de uma aplicação JavaFX. O JavaScript em execução no WebView pode chamar APIs Java, e as APIs Java podem chamar JavaScript em execução no WebView. Suporte para recursos adicionais do HTML5, incluindo Web Sockets, Web Workers e Web Fonts, e capacidades de impressão foram adicionados no JavaFX.


JavaFX WebView:

  • O JavaFX WebView é um mini navegador (também chamado de navegador embutido) que fornece um visualizador web e funcionalidade completa de navegação por meio de sua API em aplicações JavaFX.
  • Este navegador é baseado no WebKit, um mecanismo de navegador web de código aberto que suporta HTML5, JavaScript, CSS, renderização DOM e gráficos SVG.
  • A classe WebView é uma extensão da classe Node.
  • O navegador embutido herda todos os campos e métodos da classe Node e, portanto, possui todas as suas características.
  • Ele encapsula um objeto WebEngine, incorpora conteúdo HTML na cena de uma aplicação e fornece propriedades e métodos para aplicar efeitos e transformações.
  • O método getEngine() chamado em um objeto WebView retorna um WebEngine associado a ele.
  • As classes que constituem o navegador embutido residem no pacote javafx.scene.web.
  • O WebView permite que os desenvolvedores implementem os seguintes recursos em suas aplicações Java:
    • Renderizar conteúdo HTML de URLs locais ou remotas
    • Suportar histórico e fornecer navegação para Trás e Avançar
    • Recarregar o conteúdo
    • Aplicar efeitos ao componente web
    • Editar o conteúdo HTML
    • Executar comandos JavaScript
    • Realizar "upcalls" do JavaScript para o JavaFX
    • Manipular eventos

🔧 Funcionalidades Suportadas

O componente WebView suporta os seguintes recursos do HTML5, além de suportar CSS3 e ecmascript6 (ES6):

  • DOM3
  • Canvas
  • Reprodução de Mídia
  • Controles de Formulário (exceto para <input type="color">)
  • Conteúdo editável
  • Manutenção de histórico
  • Suporte para as tags <meter>, <progress>, <details> e <summary>
  • SVG
  • Web Sockets
  • Web Workers
  • Suporte para nomes de domínio escritos em idiomas nacionais

O diagrama abaixo descreve a arquitetura do navegador embutido e sua relação com outras classes JavaFX:

Web Engine:

  • É um objeto não visual capaz de gerenciar uma página Web por vez.
  • Fornece funcionalidade básica de página web por meio de sua API.
  • Suporta interação do usuário, como navegar por links e enviar formulários HTML, embora não interaja diretamente com os usuários.
  • Carrega páginas Web, cria seus modelos de documento, aplica estilos conforme necessário e executa JavaScript nas páginas.
  • Fornece acesso ao modelo de documento da página atual e permite comunicação bidirecional entre uma aplicação Java e o código JavaScript da página.
  • Envolve um objeto WebPage, que fornece interação com o núcleo WebKit nativo.

🔄 Relação entre as Classes WebView e WebEngine


Snippets de Código para Carregar Conteúdo no JavaFX WebView:

1️⃣ Criar objetos WebView, WebEngine e carregar via URL Remota

WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webEngine.load("https://www.example.com");

2️⃣ Carregar Conteúdo HTML Estático

WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webEngine.loadContent("<html><body><h1>Olá, Mundo!</h1></body></html>");

3️⃣ Carregar conteúdo HTML a partir de um arquivo local

WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
File file = new File("caminho/para/seu/arquivo.html");
webEngine.load(file.toURI().toString());

4️⃣ Rastrear o Progresso de Carregamento com a ajuda do LoadWorker

Worker<Void> loadWorker = webEngine.getLoadWorker();
loadWorker.stateProperty().addListener((obs, oldState, newState) -> {
    if (newState == Worker.State.SUCCEEDED) {
        System.out.println("Página carregada com sucesso!");
    }
});

O carregamento sempre acontece em uma thread em segundo plano. Métodos que iniciam o carregamento retornam imediatamente após agendar um trabalho em segundo plano.

Para rastrear o progresso e/ou cancelar um trabalho, pode-se usar a instância Worker disponível do método getLoadWorker().

O exemplo a seguir altera o título do palco quando o carregamento é concluído com sucesso:

loadWorker.stateProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue == Worker.State.SUCCEEDED) {
        stage.setTitle(webEngine.getTitle());
    }
});

5️⃣ Acesso ao Modelo de Documento

Os objetos WebEngine criam e gerenciam um Modelo de Objeto de Documento (DOM) para suas páginas Web. O modelo pode ser acessado e modificado usando as classes Java DOM Core.

O método getDocument() fornece acesso à raiz do modelo. Além disso, a especificação DOM Event é suportada para definir manipuladores de eventos em código Java.

O exemplo a seguir anexa um listener de evento Java a um elemento de uma página Web. Clicar no elemento faz com que a aplicação seja encerrada:

EventListener listener = (Event ev) -> {
    Platform.exit();
};

Document doc = webEngine.getDocument();
Element el = doc.getElementById("sair");
((EventTarget) el).addEventListener("click", listener, false);

6️⃣ Chamar JavaScript a partir do JavaFX

Após o WebView carregar um site, é possível executar código JavaScript arbitrário no contexto da página atual usando o método executeScript(java.lang.String).

webEngine.executeScript("alert('Olá do JavaFX!');");

Mapeamento entre Java e JavaScript

7️⃣ Mapear Valores JavaScript para Objetos Java

  • Valores JavaScript são representados usando as classes Java óbvias: null se torna null em Java; um booleano se torna um java.lang.Boolean; e uma string se torna um java.lang.String.
  • Se o resultado for um objeto JavaScript, ele é empacotado como uma instância da classe JSObject.
  • A classe JSObject é um proxy que fornece acesso a métodos e propriedades de seu objeto JavaScript subjacente.
  • Os métodos JSObject mais comumente usados são getMember (para ler uma propriedade nomeada), setMember (para definir uma propriedade) e call (para chamar uma propriedade de valor de função).
  • Um DOM Node é mapeado para um objeto que estende JSObject e implementa as interfaces DOM apropriadas. Para obter um objeto JSObject para um Node, basta fazer um cast:
    JSObject jdoc = (JSObject) webEngine.getDocument();

8️⃣ Mapear Objetos Java para Valores JavaScript

  • Os argumentos dos métodos JSObject setMember e call passam objetos Java para o ambiente JavaScript.
  • Este é aproximadamente o inverso do mapeamento JavaScript para Java descrito acima: Objetos Java String, Number ou Boolean são convertidos para os valores JavaScript óbvios.
  • Um objeto JSObject é convertido para o objeto JavaScript empacotado original. Caso contrário, um JavaRuntimeObject é criado.
  • Este é um objeto JavaScript que atua como um proxy para o objeto Java, no sentido de que acessar propriedades do JavaRuntimeObject faz com que o campo ou método Java com o mesmo nome seja acessado.

Atualização do WebKit no JDK

O mecanismo WebKit do WebView é baseado na porta Apple Safari. Esta porta também é usada por iOS, GTK, WinCairo, EFL etc.

O ciclo de lançamento do WebKit GTK é seguido e o WebKit será atualizado a cada 6 meses.

O objetivo de atualizar o WebKit é ter correções de vulnerabilidades de segurança, além de novos recursos e adesão aos padrões mais recentes.