Flutter - o uso de WebView e interação com JS

O uso do WebView é relativamente comum, especialmente a interação com JS. Hoje, vou esclarecer algumas coisas sobre o uso do WebView em vibração ~ Concentre-se no
uso dos dois plug-ins principais a seguir:

Plug-in oficial: webview_flutter
pub Plug-in mais útil: flutter_webview_plugin

O uso de qualquer plug-in é um processo de duas etapas:
1. Importar dependências
2. Importar e usar componentes de aplicativos (widgets)

No entanto, durante o uso deste plug-in, um item separado precisa ser definido no IOS, caso contrário, um erro será relatado. Da seguinte forma, adicione em ios/Runner/Info.plist

1
2

<key>io.flutter.embedded_views_preview</key>
<string>SIM</string>*

Este artigo se concentra em praticar o uso de plug-ins oficiais primeiro.
Para facilitar a distinção, o uso dos dois plug-ins é colocado em um arquivo dart, conforme segue:

class WidgetWebview extends StatefulWidget {
  String remoteUrl = "https://www.baidu.com";
  String localUrl = "assets/html/login.html";
  bool useWebviewFlutter = true; // 是否使用 flutter 提供的插件

  @override
  _WidgetWebviewState createState() =>
      useWebviewFlutter ? _WebviewFlutterState() : _FlutterWebViewPluginState();
}
/// 方便将两个插件放在一起对比~
abstract class _WidgetWebviewState extends State<WidgetWebview> {}

class _WebviewFlutterState extends _WidgetWebviewState {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("WebViewFlutter 与 JS 交互"),
      ),
    );
  }
}

class _FlutterWebViewPluginState extends _WidgetWebviewState {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FlutterWebViewPlugin 与 JS 交互"),
      ),
    );
  }
}

Então este artigo   processará _WebviewFlutterState

uso básico

No ios, adicione-o em ios/Runner/Info.plist  ou a página não carregará...

1
2

<key>io.flutter.embedded_views_preview</key>
<string>SIM</string>*

Primeiro use o WebView para carregar uma página, é bem simples, basta  adicionar o  componente WebView no  método  build() , a seguir é o seu construtor

  const WebView({
    Key key,
    this.onWebViewCreated, //WebView 创建完成之后的回调
    this.initialUrl, // 初始化 URL
    this.javascriptMode = JavascriptMode.disabled, // JS执行模式 默认是不调用
    this.javascriptChannels, // JS可以调用Flutter 的通道
    this.navigationDelegate, // 路由委托(可以通过在此处拦截url实现JS调用Flutter部分) 拦截 URL
    this.gestureRecognizers, // 手势相关
    this.onPageFinished, // 页面加载完成的回调
    this.debuggingEnabled = false,
    this.userAgent,
    this.initialMediaPlaybackPolicy =
        AutoMediaPlaybackPolicy.require_user_action_for_all_media_types,
  })

Na verdade, através de um simples entendimento do construtor, aprendi basicamente como utilizá-lo, então como carregar uma URL da forma mais simples?

     body: WebView(
        initialUrl: widget.remoteUrl,
      ),

 

Não é muito simples? Este é o uso mais simples para carregar uma página.

uso avançado

O acima disse como simplesmente carregar uma página, então haverá alguns outros usos que podem ser usados ​​~
WebView tem um controlador chamado  WebViewController , que é usado para lidar com algumas coisas, e pode   ser obtido em WebView.onWebViewCreated .

Obter título da página

Muitas vezes, é necessário exibir o título da appbar da página flutuante atual como o título da página da web, então como obter esse título? O WebViewController citado acima possui um  método getTitle()  , que pode ser utilizado para obter o título da página web, conforme segue:

  /// 获取当前加载页面的 title
  _getTitle() async {
    String title = await _webViewController.getTitle();
    print("title---$title");
  }

 

Obtenha a sequência de título daqui e, em seguida, você pode usá-la para processamento.

Carregar um arquivo HTML local

Carregue o código diretamente, os pontos que precisam ser observados são:
1. Bundle.loadString() é executado de forma assíncrona, então você precisa usar o FutureBuilder para processar o componente de uma só vez.
2. Use Uri para transcodificar o arquivo, conforme mostrado no código
3. Ao adicionar dependências a arquivos locais, preste atenção à precisão do caminho! Aqui eu criei um diretório html no meu diretório assets, e coloquei o arquivo HTML aqui, então o caminho html específico deve ser usado na dependência.

1
2
3

  ativos:
    - ativos/
    - ativos/html/

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: FutureBuilder(
        future: _loadHtmlFile(),
        builder: (context, snapshot) {
          return WebView(
            initialUrl: Uri.dataFromString(snapshot.data, mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
                      .toString(),
            onWebViewCreated: (WebViewController controller) {
              print("webview page: webview created...");
              _webViewController = controller;
              _webViewController.loadUrl(
                  new Uri.dataFromString(snapshot.data, mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
                      .toString());
            },
            onPageFinished: (url) {
              print("webview page: load finished...url=$url");
              _getTitle();
            },
          );
        },
      ),
    );
  }

 

JS chama o método flutter

Aqui vem o destaque, chame o método em flutter em HTML Como mencionado anteriormente, existem duas maneiras de o JS chamar o Flutter: use javascriptChannels  para enviar mensagens e use o delegado de roteamento navigationDelegate  para interceptar url para obter interação.
Não vou falar sobre a implementação da interceptação por enquanto. Pessoalmente, acho que é um tanto insípido. Amigos interessados ​​podem estudar por conta própria (rindo...)

Enviar mensagens usando javascriptChannels

O parâmetro javascriptChannels está na forma de um array, o que significa que um objeto correspondente (JavascriptChannel) pode ser criado para cada método a ser interagido e lançado no array. Mas acho que também é possível pensar em criar um objeto e depois usar a chave no JavascriptChannel para distinguir o processamento, mas não por enquanto, porque há apenas um parâmetro no JavascriptMessage, que ainda é do tipo string, por isso não é fácil de manusear. . . Este artigo usa o primeiro método.
Por exemplo, agora eu quero chamar um método toast em js para exibir um toast, então o primeiro passo é criar um JavascriptChannel da seguinte forma:

  // 创建 JavascriptChannel
  JavascriptChannel _toastJsChannel(BuildContext context) => JavascriptChannel(
      name: 'show_flutter_toast',
      onMessageReceived: (JavascriptMessage message) {
        print("get message from JS, message is: ${message.message}");
        T.show(message.message);
      });

 

1

javascriptChannels: [_toastJsChannel(contexto)].toSet(),

Os pontos a serem explicados são:
1. O parâmetro name corresponde a uma chave do tipo String, que é como se chama em JS (postMessage(“xxx”)), e deve ser consistente.
2. onMessageReceived chama de volta um objeto JavascriptMessage para receber informações de retorno de chamada de JS. Atualmente, há apenas um atributo message(String). Apenas os parâmetros do tipo String são suportados. Se houver muitos dados, você pode considerar os parâmetros do tipo String JSON.
A próxima etapa é escrever um código JS simples~~

<div class = "rect" style="margin-top: 50px;" onclick="flutterShowToast()">JS调用Flutter</div>

  /// 调用 flutter 的方法
  /// -name:show_flutter_toast
  function flutterShowToast() {
    show_flutter_toast.postMessage("message from JS...");
  }

 

O código no HTML é muito simples. É para definir um evento de clique para um div e ajustar o método de flutterShowToast. Uma coisa para prestar atenção especial é que show_flutter_toast  não deve ser escrito errado! (Você deve saber porque esta string deve ser usada aqui~)

Flutter chama JS

Após a criação do WebView, podemos obter um WebViewController e, por meio de seu método avaliaJavascript(), podemos executar instruções JS

WebViewController _webViewController;
...
onWebViewCreated: (WebViewController controller) {
              print("webview page: webview created...");
              _webViewController = controller;
              _webViewController.loadUrl(new Uri.dataFromString(snapshot.data,
                      mimeType: 'text/html',
                      encoding: Encoding.getByName('utf-8'))
                  .toString());
            }
...
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: (){
          _webViewController.evaluateJavascript("flutterCallJsMethod('message from Flutter!')");
        },
      ),

O evento de transferência é acionado adicionando um FloatingActionButton na página. Como mencionado acima, o método de avaliaçãoJavascript é chamado, o conteúdo é o método e os parâmetros em JS e, em seguida, uma função correspondente com o mesmo nome é escrita no HTML para realizar o conversão de flutter para jS passou, o código HTML é o seguinte:

  /// Flutter 调用 JS 的此方法
  /// 在 Flutter 中通过 _webViewController.evaluateJavascript("flutterCallJsMethod('message from Flutter!')") 调用
  function flutterCallJsMethod(message) {
      document.getElementById("show_info").innerText = message;
  }

 

Ao mesmo tempo, avaliaJavascript retorna um objeto Future, que pode ser usado para assumir o conteúdo retornado pelo JS.
Nota: o método avaliaJavascript() **, o Flutter recomenda que o executemos após o callback onPageFinished para garantir que todo o HTML foi carregado. Portanto, no desenvolvimento real, é recomendável consultar meu método de escrita e colocar o WebView no FutureBuilder ~

Guess you like

Origin blog.csdn.net/qq_27909209/article/details/130412141