如何在Flutter Webview中监听事件?

13

当用户在Webview中点击一个按钮时,我希望关闭Flutter应用程序中的Webview

这里是显示Webview的代码

class WebViewApp extends StatefulWidget {
  @override
  _WebViewAppState createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  @override
  Widget build(BuildContext context) {
    return  WebviewScaffold(url: 'https://google.com',
        appBar: AppBar(
          title: Text('Test'),
          centerTitle: true,
          backgroundColor: kBlue,
          leading: BackButton(
            onPressed: (){
              Router.navigator.pop();
            },
          )
        ),
      );
  }
}

这是一张示例图片,我想检测其中的运动物体


请展示您在Webview中使用的URL,并指定您希望在其中按下哪个按钮以关闭它? - Alok
假设我想检测用户是否点击了“运动”选项。 - Harshvardhan R
3个回答

18
请按照以下步骤检查如何在WebView中点击按钮时触发操作:
  • Add webview plugin

    webview_flutter: ^3.0.4

  • Added the reference of asset in the pubspec.yaml

     assets:   
        assets/about_us.html
    
  • Added the html file in the assets folder

about_us.html

<html>

<head>
    <script type="text/javascript">
        function invokeNative() {
            MessageInvoker.postMessage('Trigger from Javascript code');
        }
    </script> </head>

<body>
    <form>
        <input type="button" value="Click me!" onclick="invokeNative()" />
    </form> </body>

</html>
  • 添加了加载 WebView 的代码。

As per the below statement, you can see I am loading a WebView and when I click on the button named Click me! in WebView the JavascriptChannel in flutter will get invoked with a message "Trigger from Javascript code"

import 'dart:convert';
import 'package:flutter/material.dart'; 
import 'package:flutter/services.dart'; 
import 'package:webview_flutter/webview_flutter.dart';

class WebViewApp extends StatefulWidget {
  WebViewApp({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _WebViewAppState createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  WebViewController _controller;
  Future<void> loadHtmlFromAssets(String filename, controller) async {
    String fileText = await rootBundle.loadString(filename);
    controller.loadUrl(Uri.dataFromString(fileText,
            mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
        .toString());
  }
  Future<String> loadLocal() async {
    return await rootBundle.loadString('assets/about_us.html');
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: FutureBuilder<String>(
        future: loadLocal(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return WebView(
              initialUrl:
                  new Uri.dataFromString(snapshot.data, mimeType: 'text/html')
                      .toString(),
              javascriptMode: JavascriptMode.unrestricted,
              javascriptChannels: <JavascriptChannel>[
                JavascriptChannel(
                    name: 'MessageInvoker',
                    onMessageReceived: (s) {
                    Scaffold.of(context).showSnackBar(SnackBar(
                       content: Text(s.message),
                    ));
                    }),
              ].toSet(),
            );
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          }
          return CircularProgressIndicator();
        },
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

从代码中可以看到,当用户在webview中单击按钮时,会调用JavascriptChannel。有一个关键字来标识通道,在我的情况下是MessageInvoker

希望这样做就可以解决问题了... enter image description here


1
感谢您的回答。从技术上讲,这个问题回答了我的问题。但是我的意图是监听任何网站上的任何事件,而不仅仅是我添加的HTML。 - Harshvardhan R
1
据我所知,jschannel/jsinterface是唯一可用的选项,可以实现JavaScript代码和客户端Flutter代码之间的通信。 - Rissmon Suresh
非常感谢这个绝佳的例子,但是当我尝试使用它时,在调试模式下运行良好,但在生产环境中却不起作用。有什么想法吗? - Firas Nizam
@FirasNizam 它不应该依赖于构建类型。您在生产和调试中加载的是同一个网页吗? - Rissmon Suresh

10

您可以通过检查即将打开的 WebView 的 URL 来监听点击事件:

WebView(
  initialUrl: 'https://google.com',
  navigationDelegate: (request) {
    if (request.url.contains('mail.google.com')) {
      print('Trying to open Gmail');
      Navigator.pop(context); // Close current window
      return NavigationDecision.prevent; // Prevent opening url
    } else if (request.url.contains('youtube.com')) {
      print('Trying to open Youtube');
      return NavigationDecision.navigate; // Allow opening url
    } else {
      return NavigationDecision.navigate; // Default decision
    }
  },
),

2
在Webview构造函数中使用navigationDelegate参数。

WebView(
  initialUrl: 'https://flutter.dev',
  navigationDelegate: (action) {
    if (action.url.contains('google.com')) {
      // Won't redirect url
      print('Trying to open google');
      Navigator.pop(context); 
      return NavigationDecision.prevent; 
    } else if (action.url.contains('youtube.com')) {
     // Allow opening url
      print('Trying to open Youtube');
      return NavigationDecision.navigate; 
    } else {
      return NavigationDecision.navigate; 
    }
  },
),

就是这样!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接