Search code examples
flutterflutter-web

Flutter web: The communication between Flutter web and Flutter APP fails


APP : Developed with Flutter

Web: Develop with Flutter

Use the webview_flutter plugin to load web pages in app.

Now the web page wants to communicate with the APP.

It is possible to use JavaScript methods to interact with flutter.

JavaScript code

function toast() { 
    Toast.postMessage("message from web page");
}

Flutter APP code

  JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
    return JavascriptChannel(
        name: 'Toast',
        onMessageReceived: (JavascriptMessage message) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text(message.message)),
          );
        });
  }

The above method is possible.

But now Flutter web tries to interact with Flutter APP and fails, code show as below

Flutter web code

  void toast() {
    html.window.postMessage("message from web page", "Toast");
  }

Flutter APP code same as above.

The error message is as follows

I/chromium(25735): [INFO:CONSOLE(14560)] "SyntaxError: Failed to execute 'postMessage' on 'Window': Invalid target origin 'Toast' in a call to 'postMessage'."

Is there something wrong with my calling method?


Solution

  • There's a way, but it doesn't feel good.

    1. Define a JavaScript file in the web directory, here called toast.js. This file defines the methods to communicate with Dart.

      function makeToast(msg) {
         Toast.postMessage(msg);
      }
      
    2. Import toast.js in index.html in the web directory

      <head>
       // ...
        <!-- This script adds the flutter initialization JS code -->
        <script src="flutter.js" defer></script>
        <!-- new line -->
        <script src="toast.js"></script>
      </head>
      
    3. Go back to the Flutter project and create a dart file in the lib directory, called js_channel.dart here, declare a method in this file for Dart to call JavaScript methods

      import 'package:js/js.dart';
      
      @JS('makeToast')
      external void makeToast(String msg);
      
    4. Call makeToast method

      void toast() {
       makeToast("msg from flutter web")
      }
      

    The above steps are all done in the flutter web project.

    Next, you need to use the webview in the Flutter native (android or ios) project to load the web page built by the Flutter web project, and then listen to the message sent by the Toast object in the webview.

    Here I am using the webview_flutter plugin

    Widget _buildWebView() {
      return WebView(
          debuggingEnabled: true,
          initialUrl: "your web url",
          javascriptMode: JavascriptMode.unrestricted,
          javascriptChannels: <JavascriptChannel>{
          JavascriptChannel(
            name: 'Toast',
            onMessageReceived: (JavascriptMessage message) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text(message.message)),
              );
            },
          ),
        },
      ),
    }