[英]Flutter Webview two way communication with Javascript
I have an html file that I am loading in Flutter webview using flutter_webview_plugin.我有一个 html 文件,我正在使用 flutter_webview_plugin 在 Flutter webview 中加载该文件。 I am using evalJavascript to call function in my javascript code, meaning flutter(dart)->js.
我正在使用 evalJavascript 在我的 javascript 代码中调用 function,意思是颤振(飞镖)-> js。 However, I also need some way to communicate back something to flutter(dart) layer, meaning js->flutter(dart).
但是,我还需要某种方式将某些内容传回 Flutter(dart) 层,即 js->flutter(dart)。
I have tried using - webkit.messageHandlers.native - window.native to support both platforms(Android,iOS) checking if those are available in JS.我尝试使用 - webkit.messageHandlers.native - window.native 来支持两个平台(Android,iOS),检查它们是否在 JS 中可用。 But, those comes as undefined.
但是,这些都是未定义的。 Using following code to get instance of native handler in JS.
使用以下代码在 JS 中获取本机处理程序的实例。
typeof webkit !== 'undefined' ? webkit.messageHandlers.native :
window.native;
And even if I get that instance and post message using it, not sure how to handle it in flutter(dart) layer.即使我得到该实例并使用它发布消息,也不知道如何在颤振(飞镖)层中处理它。 I may need to use platform channels.
我可能需要使用平台渠道。 Not sure, if I am in the right direction.
不确定,如果我在正确的方向。
Is there any way through which I can do that?有什么办法可以做到吗? I have evaluated interactive_webview plugin.
我已经评估了 interactive_webview 插件。 It works fine on Android.
它在 Android 上运行良好。 But, it has swift versioning issue and don't want to proceed further with that.
但是,它有 swift 版本控制问题,不想进一步处理。
Any help would be appreciated.任何帮助,将不胜感激。
Here is an example of communication from Javascript code to flutter.这是一个从 Javascript 代码到 flutter 的通信示例。
In Flutter build your WebView like :在 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;
},
)
and in Your HTMLfile:并在您的 HTML 文件中:
<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.当您运行此代码时,您将能够在 android studio 的 LogCat/Run 窗口中看到日志“ Hello World is called from Javascript code ”。
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 ).您可以尝试我的插件flutter_inappbrowser (编辑:它已重命名为flutter_inappwebview )并使用
addJavaScriptHandler({@required String handlerName, @required JavaScriptHandlerCallback callback})
方法( 在此处查看更多信息)。
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):在 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>
On Android Studio logs you will get:在 Android Studio 日志中,您将获得:
I/flutter (20436): From JavaScript side:
I/flutter (20436): [12, 2, 50]
I/flutter (20436): console message: 64
I want to tell you about how to send messages from flutter WebView to JS:我想告诉你如何从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;
var _webViewController;
class App extends State<MyApp> {
final _webViewController;
}
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?但是如果我们想将这个
_webViewController
实例共享给其他像 drawer 这样的小部件怎么办?
In this case I decided to implement Singleton pattern
and store _webViewController
instance in it.在这种情况下,我决定实现
Singleton pattern
并在其中存储_webViewController
实例。
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 ie (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:如果你想从 JS 代码接收消息到你的 Flutter 应用程序,你需要:
window.CHANNEL_NAME.postMessage('Hello from JS');
CHANNEL_NAME
)CHANNEL_NAME
)将 flutter 绑定到您的窗口 WebView new MessageChannelwindow.CHANNEL_NAME.postMessage('Hello from JS');
window.CHANNEL_NAME.postMessage('Hello from JS');
we recieve a message we sentWebView(
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!因此,如果您对此有其他更好的体验,可以在评论中写下以帮助其他人!
Full code example of Javascript callbacks using package flutter_inappwebview:使用包 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);
},
),
),
])),
),
);
}
}
If you are using webviewx plugin which support web,ios and android than this is how we can do two way communication.如果您使用支持 web、ios 和 android 的webviewx插件,那么我们可以进行两种方式的通信。
I have webpage which has index.html and other js,and css pages which I want to display in webview and communicate between flutter and web app.我有一个包含 index.html 和其他 js 的网页,以及我想在 webview 中显示并在 flutter 和 web 应用程序之间进行通信的 css 页面。
1. From flutter to js listener 1.从flutter到js监听器
IconButton(
icon: Icon(Icons.developer_mode),
onPressed: () {
webviewController
.evalRawJavascript('window.myFunction()',
inGlobalContext: false)
.then((value) => print(value));
},
)
Note: myFunction is function defined in javascript or html page as below.注意:myFunction 是在 javascript 或 html 页面中定义的函数,如下所示。
function myFunction() {
alert("I am an alert box!");
return 'working';
}
2. From js/html to flutter listener 2.从js/html到flutter监听器
In html/js add button with listener在 html/js 中添加带有监听器的按钮
function submitClick() {
var data = document.getElementById('data').value;
SubmitCallback(data) //defined in flutter
}
Now In flutter(add dartCallback):现在在颤振中(添加 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')));
},
),
},
)
PS.附注。 Happy Coding
快乐编码
Two ways comunication answer:两种方式交流回答:
Flutter to webview (javascript, react...) Flutter 到 webview(javascript,react...)
From the flutter side (using a button or in a trigger method from flutter):从颤振方面(使用按钮或颤振的触发方法):
webViewController.evaluateJavascript('fromFlutter("pop")');
This "fromFlutter" will be the name of the method in your javascript, react, whatever and also you can send text, in this case is "pop".这个“fromFlutter”将是你的javascript中方法的名称,react,不管你也可以发送文本,在这种情况下是“pop”。
From the javascript side inside the html, in your body label:从 html 内部的 javascript 端,在您的正文标签中:
<script type="text/javascript">
function fromFlutter(data) {
// Do something
console.log("This is working now!!!");
}
</script>
From your webview (javascript, react...) to Flutter从你的 webview(javascript,react...)到 Flutter
In your Webview attribute javascriptChannels you can add:在您的 Webview 属性 javascriptChannels 中,您可以添加:
javascriptChannels: Set.from([
JavascriptChannel(
name: 'comunicationname',
onMessageReceived: (JavascriptMessage message) async {
// Here you can take message.message and use
// your string from webview
},
)
]),
From the webview using the same comunication name "comunicationname" (your can use another name in both places):从使用相同通信名称“comunicationname”的 web 视图(您可以在两个地方使用另一个名称):
window.comunicationname.postMessage("native,,,pop,");
I hope this work for your.我希望这对你有用。 Happy coding.
快乐编码。
Flutter 3.0.5 webview_flutter: ^3.0.4 flutter_js: ^0.5.0+6 Flutter 3.0.5 webview_flutter:^3.0.4 flutter_js:^0.5.0+6
Another way to use JavascriptChannels is to tranfer data from the "App" to your Website.使用 JavascriptChannels 的另一种方法是将数据从“应用程序”传输到您的网站。
Dart: 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: html:
<script type = "text/javascript">
window.onload = getFCMToken.postMessage('');
</script>
or Dart(Trigger):或飞镖(触发器):
OnPageFinished: (url) async {
try {
final token = (await FirebaseMessaging.instance.getToken())!;
var javascript = "var appToken=\"${token.toString()}\"";
} catch (_) {}
}
so in your website code you have a js var "appToken" wich you can use in PHP or whatever.因此,在您的网站代码中,您有一个 js var“appToken”,您可以在 PHP 或其他任何地方使用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.