How to listen to events in flutter webview?

Viewed 12564

I want to close the webview in my flutter app when the user clicks on a button which is present in the webview

Here is the code which displays the 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();
            },
          )
        ),
      );
  }
}

example image and i want to detect if the sports

3 Answers

Please check the below steps for getting a trigger when the button in a WebView is clicked:

  • 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>
  • Added the code for loading 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.
    );
  }
}

As you can see in the code there is a JavascriptChannel which will get invoked when the user clicks a button in webview. There is a key to identify the channel which in my case was MessageInvoker.

Hopes this will do the trick... enter image description here

You can listen to the clicks by checking the url WebView is about to open:

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
    }
  },
),

Use navigationDelegate parameter in Webview constroctor.

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; 
    }
  },
),

That's it!

Related