Flutter WebView与JS交互插件webview_jsbridge的使用
Flutter WebView与JS交互插件webview_jsbridge的使用
webview_jsbridge
中文文档
webview_jsbridge
是一个与 webview_flutter
兼容的 Flutter jsbridge 包,无需任何原生依赖。它完全兼容 Android 的 JsBridge
和 iOS 的 WebViewJavascriptBridge
。
使用
WebView _buildWebView() {
return WebView(
javascriptChannels: jsBridge.jsChannels,
// 必须启用js
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) {
jsBridge.controller = controller;
jsBridge.defaultHandler = _defaultHandler;
jsBridge.registerHandler("NativeEcho", _nativeEchoHandler);
},
navigationDelegate: (NavigationRequest navigation) {
// 这在Android上无效
if (navigation.url.contains('__bridge_loaded__')) {
jsBridge.injectJs();
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
onPageFinished: (String url) {
jsBridge.injectJs();
},
initialUrl: 'https://example.com',
);
}
Future<void> _send() async {
final res = await jsBridge.send('send from native');
print('_send res: $res');
}
Future<void> _callJs() async {
final res = await jsBridge.callHandler('JSEcho', data: 'callJs from native');
print('callJs res: $res');
}
Future<Object?> _defaultHandler(Object? data) async {
await Future.delayed(Duration(seconds: 1), () {});
return '_defaultHandler from native';
}
Future<Object?> _nativeEchoHandler(Object? data) async {
await Future.delayed(Duration(seconds: 1), () {});
return '_nativeEchoHandler from native';
}
默认JS实现
默认的JS实现是ES5版本。使用这个版本,Web客户端无需做任何更改。
异步JS实现
如果Web客户端正在使用ES7,这里有一个异步实现。你只需要选择ES7版本进行注入。例如:
Dart客户端
jsBridge.injectJs(esVersion: WebViewInjectJsVersion.es7);
JS客户端
setupWebViewJavascriptBridge(function (bridge) {
console.log('setupWebViewJavascriptBridge done');
async function defaultHandler(message) {
console.log('defaultHandler JS got a message', message);
return new Promise(resolve => {
let data = {
'Javascript Responds': 'defaultHandler Wee!'
};
console.log('defaultHandler JS responding with', data);
setTimeout(() => resolve(data), 0);
});
}
bridge.init(defaultHandler);
async function JSEcho(data) {
console.log("JS Echo called with:", data);
return new Promise(resolve => setTimeout(() => resolve(data), 0));
}
bridge.registerHandler('JSEcho', JSEcho);
});
async function sendHello() {
let responseData = await window.WebViewJavascriptBridge.send('hello');
console.log("repsonseData from java, data = ", responseData);
}
async function callHandler() {
let responseData = await window.WebViewJavascriptBridge.callHandler('NativeEcho', { 'key': 'value' });
console.log("JS received response:", responseData);
}
完整示例Demo
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:local_assets_server/local_assets_server.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_jsbridge/webview_jsbridge.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// 这个小部件是您的应用的根。
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeView('es5'),
);
}
}
class HomeView extends StatefulWidget {
final String title;
HomeView(this.title) : super();
[@override](/user/override)
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final jsBridge = WebViewJSBridge();
bool isListening = false;
String? address;
int? port;
[@override](/user/override)
initState() {
_initServer();
super.initState();
}
Future<void> _initServer() async {
final server = LocalAssetsServer(
address: InternetAddress.loopbackIPv4,
assetsBasePath: 'assets/',
logger: DebugLogger(),
);
final address = await server.serve();
setState(() {
this.address = address.address;
port = server.boundPort!;
isListening = true;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
if (widget.title == 'es5')
TextButton(
child: Text(
'es7',
style: TextStyle(color: Colors.red),
),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (ctx) => HomeView('es7'),
),
),
),
],
),
body: isListening
? Row(
children: [
Expanded(
child: _buildWebView(),
),
Expanded(
child: Column(
children: [
Text('native'),
TextButton(
child: Text(
'sendHello',
),
onPressed: () => _sendHello(),
),
TextButton(
child: Text(
'callJSEcho',
),
onPressed: () => _callJSEcho(),
),
TextButton(
child: Text(
'_callNotExist',
),
onPressed: () => _callNotExist(),
),
],
),
),
],
)
: Center(child: CircularProgressIndicator()),
);
}
WebView _buildWebView() {
final isEs5 = widget.title == 'es5';
final jsVersion = isEs5 ? WebViewInjectJsVersion.es5 : WebViewInjectJsVersion.es7;
final htmlVersion = isEs5 ? 'default' : 'async';
return WebView(
javascriptChannels: jsBridge.jsChannels,
// 必须启用js
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) {
jsBridge.controller = controller;
jsBridge.defaultHandler = _defaultHandler;
jsBridge.registerHandler("NativeEcho", _nativeEchoHandler);
},
navigationDelegate: (NavigationRequest navigation) {
print('navigationDelegate ${navigation.url}');
// 这在Android上无效
if (navigation.url.contains('__bridge_loaded__')) {
jsBridge.injectJs(esVersion: jsVersion);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
onPageFinished: (String url) {
jsBridge.injectJs(esVersion: jsVersion);
},
initialUrl: 'http://$address:$port/$htmlVersion.html',
);
}
Future<void> _sendHello() async {
final res = await jsBridge.send('hello from native');
print('_sendHello res: $res');
}
Future<void> _callJSEcho() async {
final res = await jsBridge.callHandler('JSEcho', data: 'callJs from native');
print('_callJSEcho res: $res');
}
Future<void> _callNotExist() async {
final res = await jsBridge.callHandler('NotExist', data: 'callJs from native');
print('_callNotExist res: $res');
}
Future<Object?> _defaultHandler(Object? data) async {
await Future.delayed(Duration(seconds: 1), () {});
return '_defaultHandler res from native';
}
Future<Object?> _nativeEchoHandler(Object? data) async {
await Future.delayed(Duration(seconds: 1), () {});
return '_nativeEchoHandler res from native';
}
}
更多关于Flutter WebView与JS交互插件webview_jsbridge的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter WebView与JS交互插件webview_jsbridge的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中使用webview_jsbridge
插件可以实现WebView与JavaScript之间的交互。这个插件允许你在Flutter中嵌入WebView,并通过桥接机制在Flutter和JavaScript之间进行双向通信。
1. 添加依赖
首先,你需要在pubspec.yaml
文件中添加webview_jsbridge
插件的依赖:
dependencies:
flutter:
sdk: flutter
webview_jsbridge: ^2.0.0 # 请使用最新版本
然后运行flutter pub get
来获取依赖。
2. 创建WebView并初始化JsBridge
在Flutter中创建一个WebView并初始化JsBridge
:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_jsbridge/webview_jsbridge.dart';
class MyWebView extends StatefulWidget {
@override
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late WebViewController _webViewController;
late JsBridge _jsBridge;
@override
void initState() {
super.initState();
_jsBridge = JsBridge();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView with JsBridge'),
),
body: WebView(
initialUrl: 'about:blank',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewController = webViewController;
_jsBridge.initialize(webViewController);
_webViewController.loadUrl('file:///path_to_your_html_file/index.html');
},
javascriptChannels: {
// 在这里定义JavaScript通道
},
),
);
}
}
3. 在JavaScript中注册方法
在HTML或JavaScript文件中,你可以注册一些方法供Flutter调用。例如:
<!DOCTYPE html>
<html>
<head>
<title>WebView JsBridge Demo</title>
<script>
// 注册一个JavaScript方法供Flutter调用
function showMessage(message) {
alert("Message from Flutter: " + message);
}
</script>
</head>
<body>
<h1>WebView JsBridge Demo</h1>
</body>
</html>
4. Flutter调用JavaScript方法
在Flutter中,你可以通过JsBridge
调用JavaScript中的方法:
_jsBridge.callJsMethod('showMessage', ['Hello from Flutter!']);
5. JavaScript调用Flutter方法
你也可以在JavaScript中调用Flutter中的方法。首先,在Flutter中注册一个方法:
_jsBridge.registerHandler('callFlutterMethod', (data) {
// 处理从JavaScript传来的数据
print('Received from JS: $data');
return 'Response from Flutter';
});
然后在JavaScript中调用这个方法:
// 调用Flutter中的方法
JsBridge.callHandler('callFlutterMethod', {key: 'value'}, function(response) {
console.log('Response from Flutter:', response);
});
6. 完整示例
以下是一个完整的示例,展示了如何在Flutter中使用webview_jsbridge
进行双向通信:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_jsbridge/webview_jsbridge.dart';
class MyWebView extends StatefulWidget {
@override
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late WebViewController _webViewController;
late JsBridge _jsBridge;
@override
void initState() {
super.initState();
_jsBridge = JsBridge();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView with JsBridge'),
),
body: WebView(
initialUrl: 'about:blank',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewController = webViewController;
_jsBridge.initialize(webViewController);
_webViewController.loadUrl('file:///path_to_your_html_file/index.html');
},
javascriptChannels: {
// 在这里定义JavaScript通道
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_jsBridge.callJsMethod('showMessage', ['Hello from Flutter!']);
},
child: Icon(Icons.message),
),
);
}
}
void main() => runApp(MaterialApp(
home: MyWebView(),
));
7. 注意事项
- 确保你在Android和iOS项目中启用了WebView和JavaScript支持。
- 在iOS上,你可能需要在
Info.plist
中添加以下配置以启用网络请求:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>