Flutter webview two way communication

前端 未结 3 656
终归单人心
终归单人心 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: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 {
      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: [
              SizedBox(
                  width: 200,
                  child: FlatButton(
                    onPressed: () {
                      singleton.webViewController.evaluateJavascript('window.function()');
                      Navigator.pop(context); // exit drawer
                    },
                    child: Row(
                      children: [
                        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!

提交回复
热议问题