Flutter双向通信:从JS到Dart的通信以及从Dart回调结果到JS

3

我是flutter的新手。我使用webview_flutter开发了js到flutter dart通信,像这样:

Widget build(BuildContext context) {
   return MaterialApp(
      home: Scaffold(
      appBar: AppBar(
         title: const Text('Plugin example'),
         actions: <Widget>[
            MenuList(_controller.future),
         ],
      ),
      body: Builder(builder: (BuildContext context) {
         return WebView(
           initialUrl: localServerUrl,
           javascriptMode: JavascriptMode.unrestricted,
           onWebViewCreated: (WebViewController webViewController) {
             _controller.complete(webViewController);
           },
           javascriptChannels: <JavascriptChannel>[
             _scanBarcode(context),
           ].toSet(),
           onPageFinished: (String url) {
             //TODO : events after page loading finished
           },
        );
     }),
   ),
 );
}

JavascriptChannel _scanBarcode(BuildContext context) {
  return JavascriptChannel(
     name: 'Barcode',
     onMessageReceived: (JavascriptMessage message) {
       String result = scanBarcode(context);
       ******I got result of scanned barcode in result variable******
     });
}

服务器 HTML 文件
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="script.js"></script>
</head>
<body>
  <button id="btnBarcode" style="margin-top:20px; height:30px;">Scan Barcode</button>
</body>
</html>

这是JS文件

function scanBarcode(message) {
   if (window.Barcode && window.Barcode.postMessage) {
      Barcode.postMessage(message);
   }
}

window.onload = function () {
   document.getElementById('btnBarcode').onclick = function () {
     scanBarcode("Scan Barcode");
   }
}

我已经成功地在Dart文件的javascript通道_scanBarcode中获取了扫描条形码的结果。

现在我想要将这个条形码的结果回调到JS文件中的scanBarcode函数中。

我已经研究了很长时间,但是什么都没有得到。

我现在卡住了。 有人可以帮帮我吗?非常感谢您的帮助。

1个回答

6

您可以使用webViewctrl.evaluateJavascript方法。
您可以参考https://www.elasticfeed.com/7ee71117c626c2021eb919c182ec483a/中的代码片段。

onPressed: () {
          webViewctrl.evaluateJavascript(
              "scanBarcode('123')");
        }

我在JavaScript函数scanBarcode中添加了console.log(message);以证明它有效。

function scanBarcode(message) {
   console.log(message);
   if (window.Barcode && window.Barcode.postMessage) {
      console.log(document.documentElement.innerHTML);
      Barcode.postMessage(message);
   }
}

输出

I/chromium( 5209): [INFO:CONSOLE(2)] "123", source: http://yoursite/jschannel/script.js (2)

完整的测试代码

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'dart:async';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

WebViewController webViewctrl;

class _MyHomePageState extends State<MyHomePage> {
  final Completer<WebViewController> _controller =
      Completer<WebViewController>();

  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example'),
            actions: <Widget>[
              //MenuList(_controller.future),
            ],
          ),
          body: Builder(builder: (BuildContext context) {
            return WebView(
              initialUrl: 'http://yoursite/jschannel/index.html',
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (WebViewController webViewController) {
                _controller.complete(webViewController);
                webViewctrl = webViewController;
              },
              javascriptChannels: <JavascriptChannel>[
                _scanBarcode(context),
              ].toSet(),
              onPageFinished: (String url) {
                //TODO : events after page loading finished
              },
            );
          }),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              webViewctrl.evaluateJavascript(
                  "scanBarcode('123')");
            },
            child: Icon(Icons.navigation),
            backgroundColor: Colors.green,
          )),
    );
  }
}

JavascriptChannel _scanBarcode(BuildContext context) {
  return JavascriptChannel(
      name: 'Barcode',
      onMessageReceived: (JavascriptMessage message) {
        /*String result = scanBarcode(context);
        ******I got result of scanned barcode in result variable*******/
      });
}

谢谢你的回答。它有效了。我们不能直接像在Dart文件中一样返回结果,例如return result,然后我们可以使用Promise的then()方法在JavaScript函数中获取结果吗?就像这样:scanBarcode(..).then(function (barcodeResult) {// result from Dart}) - Ankit Sathvara
很高兴能够帮助。如果有帮到您,请标记为答案,谢谢。 - chunhunghan
你可以使用字符串拼接让 JavaScript 执行/评估该字符串。在此之前,你必须确保这个长字符串是有效的。 - chunhunghan
@chunhunghan 您好,感谢您的回答。我想问一下在 JavascriptChannel 参数名称中 Barcode 是什么意思?它是 js 文件的类名吗? 如果我在 JavaScript 函数中调用 window.postMessage(result);,我还能得到结果吗? - MNFS

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