[英]Flutter Webview two way communication with Javascript
我有一个 html 文件,我正在使用 flutter_webview_plugin 在 Flutter webview 中加载该文件。 我正在使用 evalJavascript 在我的 javascript 代码中调用 function,意思是颤振(飞镖)-> js。 但是,我还需要某种方式将某些内容传回 Flutter(dart) 层,即 js->flutter(dart)。
我尝试使用 - webkit.messageHandlers.native - window.native 来支持两个平台(Android,iOS),检查它们是否在 JS 中可用。 但是,这些都是未定义的。 使用以下代码在 JS 中获取本机处理程序的实例。
typeof webkit !== 'undefined' ? webkit.messageHandlers.native :
window.native;
即使我得到该实例并使用它发布消息,也不知道如何在颤振(飞镖)层中处理它。 我可能需要使用平台渠道。 不确定,如果我在正确的方向。
有什么办法可以做到吗? 我已经评估了 interactive_webview 插件。 它在 Android 上运行良好。 但是,它有 swift 版本控制问题,不想进一步处理。
任何帮助,将不胜感激。
这是一个从 Javascript 代码到 flutter 的通信示例。
在 Flutter 中构建您的 WebView,例如:
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;
},
)
并在您的 HTML 文件中:
<script type='text/javascript'>
Print.postMessage('Hello World being called from Javascript code');
</script>
当您运行此代码时,您将能够在 android studio 的 LogCat/Run 窗口中看到日志“ Hello World is called from Javascript code ”。
您可以尝试我的插件flutter_inappbrowser (编辑:它已重命名为flutter_inappwebview )并使用addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback})
方法( 在此处查看更多信息)。
下面给出一个例子。 在颤振方面:
...
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}");
},
),
...
在 JavaScript 端(例如资产文件夹内的本地文件assets/index.html
):
<!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>
在 Android Studio 日志中,您将获得:
I/flutter (20436): From JavaScript side:
I/flutter (20436): [12, 2, 50]
I/flutter (20436): console message: 64
我想告诉你如何从flutter WebView向JS发送消息:
const function = () => alert('hello from JS');
window.function = function;
WebView(
onWebViewCreated: (WebViewController controller) {},
initialUrl: 'https://url.com',
javascriptMode: JavascriptMode.unrestricted,
)
var _webViewController;
class App extends State<MyApp> {
final _webViewController;
}
onWebViewCreated: (WebViewController controller) {
_webViewController = controller;
},
然后你可以运行这样的代码:
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,
),
),
);
}
}
但是如果我们想将这个_webViewController
实例共享给其他像 drawer 这样的小部件怎么办?
在这种情况下,我决定实现Singleton pattern
并在其中存储_webViewController
实例。
所以
单例类
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();
}
然后
onWebViewCreated: (WebViewController controller) {
var singleton = new Singleton(controller);
},
最后在我们的抽屉小部件即(在这里你可以使用任何你想要的小部件)
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),
),
],
),
)),
],
),
);
}
}
如果你想从 JS 代码接收消息到你的 Flutter 应用程序,你需要:
window.CHANNEL_NAME.postMessage('Hello from JS');
CHANNEL_NAME
)将 flutter 绑定到您的窗口 WebView new MessageChannelwindow.CHANNEL_NAME.postMessage('Hello from JS');
我们收到一条我们发送的消息WebView(
javascriptChannels: [
JavascriptChannel(name: 'CHANNEL_NAME', onMessageReceived: (message) {
print(message.message);
})
].toSet(),
initialUrl: 'https://url.com',
)
所以我们来了。
我是颤振代码的新手
因此,如果您对此有其他更好的体验,可以在评论中写下以帮助其他人!
使用包 flutter_inappwebview 的 Javascript 回调的完整代码示例:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
InAppWebViewController _webViewController;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('InAppWebView Example'),
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: InAppWebView(
initialData: InAppWebViewInitialData(data: """
<!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">
</head>
<body>
<h1>JavaScript Handlers (Channels) TEST</h1>
<button id='test' onclick="window.flutter_inappwebview.callHandler('testFunc');">Test</button>
<button id='testargs' onclick="window.flutter_inappwebview.callHandler('testFuncArgs', 1);">Test with Args</button>
<button id='testreturn' onclick="window.flutter_inappwebview.callHandler('testFuncReturn').then(function(result) { alert(result);});">Test Return</button>
</body>
</html>
"""),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)),
onWebViewCreated: (InAppWebViewController controller) {
_webViewController = controller;
_webViewController.addJavaScriptHandler(
handlerName: 'testFunc',
callback: (args) {
print(args);
});
_webViewController.addJavaScriptHandler(
handlerName: 'testFuncArgs',
callback: (args) {
print(args);
});
_webViewController.addJavaScriptHandler(
handlerName: 'testFuncReturn',
callback: (args) {
print(args);
return '2';
});
},
onConsoleMessage: (controller, consoleMessage) {
print(consoleMessage);
},
),
),
])),
),
);
}
}
如果您使用支持 web、ios 和 android 的webviewx插件,那么我们可以进行两种方式的通信。
我有一个包含 index.html 和其他 js 的网页,以及我想在 webview 中显示并在 flutter 和 web 应用程序之间进行通信的 css 页面。
1.从flutter到js监听器
IconButton(
icon: Icon(Icons.developer_mode),
onPressed: () {
webviewController
.evalRawJavascript('window.myFunction()',
inGlobalContext: false)
.then((value) => print(value));
},
)
注意:myFunction 是在 javascript 或 html 页面中定义的函数,如下所示。
function myFunction() {
alert("I am an alert box!");
return 'working';
}
2.从js/html到flutter监听器
在 html/js 中添加带有监听器的按钮
function submitClick() {
var data = document.getElementById('data').value;
SubmitCallback(data) //defined in flutter
}
现在在颤振中(添加 dartCallback):
WebViewX(
javascriptMode: JavascriptMode.unrestricted,
initialContent: '<h2> Loading </h2>',
initialSourceType: SourceType.HTML,
onWebViewCreated: (controller) {
webviewController = controller;
_loadHtmlFromAssets();
webviewController.addListener(() {});
},
dartCallBacks: {
DartCallback(
name: 'SubmitCallback',
callBack: (msg) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Submitted $msg successfully')));
},
),
},
)
附注。 快乐编码
两种方式交流回答:
Flutter 到 webview(javascript,react...)
从颤振方面(使用按钮或颤振的触发方法):
webViewController.evaluateJavascript('fromFlutter("pop")');
这个“fromFlutter”将是你的javascript中方法的名称,react,不管你也可以发送文本,在这种情况下是“pop”。
从 html 内部的 javascript 端,在您的正文标签中:
<script type="text/javascript">
function fromFlutter(data) {
// Do something
console.log("This is working now!!!");
}
</script>
从你的 webview(javascript,react...)到 Flutter
在您的 Webview 属性 javascriptChannels 中,您可以添加:
javascriptChannels: Set.from([
JavascriptChannel(
name: 'comunicationname',
onMessageReceived: (JavascriptMessage message) async {
// Here you can take message.message and use
// your string from webview
},
)
]),
从使用相同通信名称“comunicationname”的 web 视图(您可以在两个地方使用另一个名称):
window.comunicationname.postMessage("native,,,pop,");
我希望这对你有用。 快乐编码。
Flutter 3.0.5 webview_flutter:^3.0.4 flutter_js:^0.5.0+6
使用 JavascriptChannels 的另一种方法是将数据从“应用程序”传输到您的网站。
Dart:
JavascriptChannel(
name: 'getFCMToken',
onMessageReceived: (JavascriptMessage message) async {
//print(message.message);
final token = (await FirebaseMessaging.instance.getToken())!;
final script = "var appToken =\"${token }\"";
_webViewController.runJavascript(script);
},
),
html:
<script type = "text/javascript">
window.onload = getFCMToken.postMessage('');
</script>
或飞镖(触发器):
OnPageFinished: (url) async {
try {
final token = (await FirebaseMessaging.instance.getToken())!;
var javascript = "var appToken=\"${token.toString()}\"";
} catch (_) {}
}
因此,在您的网站代码中,您有一个 js var“appToken”,您可以在 PHP 或其他任何地方使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.