我有一个使用flutter_webview_plugin在Flutter Webview中加载的html文件。我正在使用evalJavascript在我的JavaScript代码中调用函数,这意味着flutter(dart)-> js。但是,我还需要某种方法将某些东西传达回flutter(dart)层,这意味着js-> flutter(dart)。
我尝试使用 -webkit.messageHandlers.native -window.native 支持两个平台(Android,iOS),检查它们是否在JS中可用。但是,这些是不确定的。使用以下代码获取JS中本机处理程序的实例。
typeof webkit !== 'undefined' ? webkit.messageHandlers.native :
window.native;
即使我得到该实例并使用它发布消息,也不确定如何在flutter(dart)层中处理它。我可能需要使用平台渠道。不确定我的方向是否正确。
有什么办法可以做到这一点?我已经评估了Interactive_webview插件。它在Android上运行良好。但是,它存在快速的版本控制问题,因此不希望进一步进行。
任何帮助将不胜感激。
答案 0 :(得分:2)
这里是一个从Javascript代码到Flutter的通信示例。
在Flutter中,像这样构建WebView:
CFG_DATA_FILES := $(wildcard ../src/config/cfg_file*.csv)
CFG_DATA_MEM_FILES := $(addprefix bin/,$(notdir $(CFG_DATA_FILES:.csv=.mem)))
CFG_DATA_BIN_FILES := $(addprefix bin/,$(notdir $(CFG_DATA_MEM_FILES:.mem=.bin)))
COMBINED_BIN_FILES := $(subst cfg_file-,fw_,$(CFG_DATA_BIN_FILES))
COMBINED_BIN_FILES := $(subst .bin,_combined.bin,$(COMBINED_BIN_FILES))
ifdef CUSTOM_CONFIG
rom: build_images create_custom_binaries
else
rom: build_images create_binaries
endif
chk_custom_cfg:
ifdef CUSTOM_CONFIG
export CUSTOM_CONFIG
$(eval CUST_CFG_DATA_FILES=$(CUSTOM_CONFIG))
export CUST_CFG_DATA_FILES
$(eval CUST_CFG_DATA_MEM_FILES=$(addprefix bin/,$(notdir $(CUST_CFG_DATA_FILES:.csv=.mem))))
export CUST_CFG_DATA_MEM_FILES
$(eval CUST_CFG_DATA_BIN_FILES=$(addprefix bin/,$(notdir $(CUST_CFG_DATA_MEM_FILES:.mem=.bin))))
export CUST_CFG_DATA_BIN_FILES
$(eval CUST_COMBINED_BIN_FILES=$(subst .bin,_combined.bin,$(CUST_CFG_DATA_BIN_FILES)))
export CUST_COMBINED_BIN_FILES
@echo existing cfg files $(CUST_CFG_DATA_FILES)
@echo existing mem files $(CUST_CFG_DATA_MEM_FILES)
@echo existing bin files $(CUST_CFG_DATA_BIN_FILES)
@echo existing combined files $(CUST_COMBINED_BIN_FILES)
endif
build_images: copy_ops_imgs
create_binaries: config $(COMBINED_BIN_FILES)
create_custom_binaries: chk_custom_cfg cust_config
@echo custom config bin files $(CUST_CFG_DATA_BIN_FILES)
config: boot_partn_map_cfg $(CFG_DATA_BIN_FILES)
@echo Removing temporary files
@(cd bin; rm -rf *.mem)
cust_config: boot_partn_map_cfg $(CUST_CFG_DATA_BIN_FILES)
@echo Removing temporary files
@(cd bin; rm -rf *.mem)
$(CFG_DATA_BIN_FILES): $(CFG_DATA_FILES)
@echo Generating config data image $(subst /bin,,$@)
$(CUST_CFG_DATA_BIN_FILES):$(CUST_CFG_DATA_FILES)
@echo Generating config data image $(subst /bin,,$@)
并在您的HTML文件中:
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;
},
)
运行此代码时,您将能够在android studio的LogCat / Run窗口中看到日志“ 正在从Javascript代码调用Hello World ”。
答案 1 :(得分:2)
我想告诉您有关如何将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
实例怎么办?
在这种情况下,我决定实现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
)将WebView新的MessageChannel绑定window.CHANNEL_NAME.postMessage('Hello from JS');
时,我们会收到一条发送的邮件WebView(
javascriptChannels: [
JavascriptChannel(name: 'CHANNEL_NAME', onMessageReceived: (message) {
print(message.message);
})
].toSet(),
initialUrl: 'https://url.com',
)
就在这里。
我是Flutter代码的新手
因此,如果您对此还有其他更好的经验,可以在评论中写以帮助其他人!
答案 2 :(得分:2)
使用包 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);
},
),
),
])),
),
);
}
}
答案 3 :(得分:0)
您可以尝试使用我的插件flutter_inappbrowser(编辑:它已重命名为flutter_inappwebview)并使用loading
方法(请参阅更多here )。
下面是一个示例。 在Flutter方面:
loading:true
在JavaScript方面(例如,资产文件夹中的本地文件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}");
},
),
...
在Android Studio日志上,您将获得:
assets/index.html
答案 4 :(得分:0)
如果您使用的是支持 web、ios 和 android 的 webviewx 插件,那么我们可以进行双向通信。
我有一个包含 index.html 和其他 js 的网页,以及我想在 webview 中显示并在 flutter 和 web 应用程序之间进行通信的 css 页面。
1.从flutter到js监听器
created_at
注意:myFunction 是在 javascript 或 html 页面中定义的函数,如下所示。
IconButton(
icon: Icon(Icons.developer_mode),
onPressed: () {
webviewController
.evalRawJavascript('window.myFunction()',
inGlobalContext: false)
.then((value) => print(value));
},
)
2.从 js/html 到 flutter 监听器
在 html/js 中添加带有监听器的按钮
function myFunction() {
alert("I am an alert box!");
return 'working';
}
现在在颤振中(添加 dartCallback):
function submitClick() {
var data = document.getElementById('data').value;
SubmitCallback(data) //defined in flutter
}
附注。快乐编码