Flutter webview two way communication

前端 未结 3 647
终归单人心
终归单人心 2020-12-03 14:31

I have an html file that I am loading in Flutter webview using flutter_webview_plugin. I am using evalJavascript to call function in my javascript code, meaning flutter(dart

相关标签:
3条回答
  • 2020-12-03 15:05

    Here is an example of communication from Javascript code to flutter.

    In Flutter build your WebView like :

    WebView(
                  initialUrl: url,
                  javascriptMode: JavascriptMode.unrestricted,
                  javascriptChannels: Set.from([
                    JavascriptChannel(
                        name: 'Print',
                        onMessageReceived: (JavascriptMessage message) {
                          //This is where you receive message from 
                          //javascript code and handle in Flutter/Dart
                          //like here, the message is just being printed
                          //in Run/LogCat window of android studio
                          print(message.message);
                        })
                  ]),
                  onWebViewCreated: (WebViewController w) {
                    webViewController = w;
                  },
                )
    

    and in Your HTMLfile:

    <script type='text/javascript'>
        Print.postMessage('Hello World being called from Javascript code');
    </script>
    

    When you run this code, you shall be able to see log "Hello World being called from Javascript code" in the LogCat/Run window of android studio.

    0 讨论(0)
  • 2020-12-03 15:11

    You can try my plugin flutter_inappbrowser (EDIT: it has been renamed to flutter_inappwebview) and use addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback}) method (see more here).

    An example is presented below. On Flutter side:

    ...
    
    child: InAppWebView(
      initialFile: "assets/index.html",
      initialHeaders: {},
      initialOptions: InAppWebViewWidgetOptions(
        inAppWebViewOptions: InAppWebViewOptions(
            debuggingEnabled: true,
        )
      ),
      onWebViewCreated: (InAppWebViewController controller) {
        webView = controller;
    
        controller.addJavaScriptHandler(handlerName: "mySum", callback: (args) {
          // Here you receive all the arguments from the JavaScript side 
          // that is a List<dynamic>
          print("From the JavaScript side:");
          print(args);
          return args.reduce((curr, next) => curr + next);
        });
      },
      onLoadStart: (InAppWebViewController controller, String url) {
    
      },
      onLoadStop: (InAppWebViewController controller, String url) {
    
      },
      onConsoleMessage: (InAppWebViewController controller, ConsoleMessage consoleMessage) {
        print("console message: ${consoleMessage.message}");
      },
    ),
    
    ...
    

    On JavaScript side (for example a local file assets/index.html inside the assets folder):

    <!doctype html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Flutter InAppBrowser</title>
    
            ...
    
        </head>
        <body>
    
            ...
    
            <script>
               // In order to call window.flutter_inappwebview.callHandler(handlerName <String>, ...args) 
               // properly, you need to wait and listen the JavaScript event flutterInAppWebViewPlatformReady. 
               // This event will be dispatched as soon as the platform (Android or iOS) is ready to handle the callHandler method. 
               window.addEventListener("flutterInAppWebViewPlatformReady", function(event) {
                 // call flutter handler with name 'mySum' and pass one or more arguments
                 window.flutter_inappwebview.callHandler('mySum', 12, 2, 50).then(function(result) {
                   // get result from Flutter side. It will be the number 64.
                   console.log(result);
                 });
               });
            </script>
        </body>
    </html>
    

    On Android Studio logs you will get:

    I/flutter (20436): From JavaScript side:
    I/flutter (20436): [12, 2, 50]
    I/flutter (20436): console message: 64
    
    0 讨论(0)
  • 2020-12-03 15:17

    I want to tell you about how to send messages from flutter WebView to JS:

    1. In JS code you need to bind your function you need to fire to window
    const function = () => alert('hello from JS');
    window.function = function;
    
    1. In your code in WebView widget implementation you need to declare onWebViewCreated method like this
    WebView(
      onWebViewCreated: (WebViewController controller) {},
      initialUrl: 'https://url.com',
      javascriptMode: JavascriptMode.unrestricted,
    )
    
    1. In class widget declare var _webViewController;
    class App extends State<MyApp> {
      final _webViewController;
    }
    
    1. In onWebViewCreated write this code
    onWebViewCreated: (WebViewController controller) {
        _webViewController = controller;
    },
    

    Then you can run code like this:

    class App extends StatelessWidget {
      var _webViewController;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          home: Scaffold(
            body: WebView(
              onWebViewCreated: (WebViewController controller) {
                _webViewController = controller;
              },
              initialUrl: 'https://url.com',
              javascriptMode: JavascriptMode.unrestricted,
            ),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                // When you click at this button youll run js code and youll see alert
                _webViewController
                    .evaluateJavascript('window.function ()');
              },
              child: Icon(Icons.add),
              backgroundColor: Colors.green,
            ),
          ),
        );
      }
    }
    

    But what if we want to share this _webViewController instance to other widgets like drawer?
    In this case I decided to implement Singleton pattern and store _webViewController instance in it.
    So
    Singleton class

    class Singleton {
      WebViewController webViewController;
    
      static final Singleton _singleton = new Singleton._internal();
    
      static Singleton get instance => _singleton;
    
      factory Singleton(WebViewController webViewController) {
        _singleton.webViewController = webViewController;
        return _singleton;
      }
    
      Singleton._internal();
    }
    

    Then

    onWebViewCreated: (WebViewController controller) {
      var singleton = new Singleton(controller);
    },
    

    And finally in our Drawer widget i.e. (here you can use whatever widget you want)

    class EndDrawer extends StatelessWidget {
      final singleton = Singleton.instance;
    
      @override
      Widget build(BuildContext context) {
        return Drawer(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              SizedBox(
                  width: 200,
                  child: FlatButton(
                    onPressed: () {
                      singleton.webViewController.evaluateJavascript('window.function()');
                      Navigator.pop(context); // exit drawer
                    },
                    child: Row(
                      children: <Widget>[
                        Icon(
                          Icons.exit_to_app,
                          color: Colors.redAccent,
                        ),
                        SizedBox(
                          width: 30,
                        ),
                        Text(
                          'Exit',
                          style: TextStyle(color: Colors.blueAccent, fontSize: 20),
                        ),
                      ],
                    ),
                  )),
            ],
          ),
        );
      }
    }
    

    If you want to receive messages from JS code to your flutter App you need:

    1. In your js code
    window.CHANNEL_NAME.postMessage('Hello from JS');
    
    1. In your flutter code.
      When you're running JavascriptChannel(name: 'CHANNEL_NAME', ...)
      flutter bind to your window WebView new MessageChannel with name you wrote in constructor (in this case CHANNEL_NAME)
      so when we call window.CHANNEL_NAME.postMessage('Hello from JS'); we recieve a message we sent
    WebView(
       javascriptChannels: [
         JavascriptChannel(name: 'CHANNEL_NAME', onMessageReceived: (message) {
           print(message.message);
           })
       ].toSet(),
      initialUrl: 'https://url.com',
    )
    

    So here we are.
    I'm new in flutter code
    So if you have another better experience about this you can write in comments to help other people!

    0 讨论(0)
提交回复
热议问题