Flutter WebView与JS交互插件webview_jsbridge_x的使用
webview_jsbridge_x
webview_jsbridge_x
是一个兼容 webview_flutter 的 Flutter jsbridge 包,并且没有原生依赖。它完全兼容 Android 上的 JsBridge 和 iOS 上的 WebViewJavascriptBridge。
使用方法
以下是一个完整的使用示例:
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_x/webview_jsbridge_x.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomeView('es5'), // 初始化时使用 es5 版本
);
}
}
class HomeView extends StatefulWidget {
final String title;
HomeView(this.title) : super();
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final jsBridge = WebViewJSBridgeX();
bool isListening = false;
String? address;
int? port;
@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
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
if (widget.title == 'es5') // 如果当前使用 es5 版本,则提供切换到 es7 的按钮
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(), // 构建 WebView
),
Expanded(
child: Column(
children: [
Text('native'),
TextButton(
child: Text('sendHello'), // 调用 JS 方法
onPressed: () => _sendHello(),
),
TextButton(
child: Text('callJSEcho'), // 调用带参数的 JS 方法
onPressed: () => _callJSEcho(),
),
TextButton(
child: Text('_callNotExist'), // 调用不存在的方法
onPressed: () => _callNotExist(),
),
],
),
),
],
)
: Center(child: CircularProgressIndicator()), // 加载中动画
);
}
WebView _buildWebView() {
final isEs5 = widget.title == 'es5'; // 判断是否使用 es5 版本
final jsVersion =
isEs5 ? WebViewXInjectJsVersion.es5 : WebViewXInjectJsVersion.es7; // 注入对应的 JS 版本
final htmlVersion = isEs5 ? 'default' : 'async'; // 对应的 HTML 文件版本
return WebView(
javascriptChannels: jsBridge.jsChannels, // 注册 JavaScriptChannel
javascriptMode: JavascriptMode.unrestricted, // 启用 JavaScript
onWebViewCreated: (controller) {
jsBridge.controller = controller; // 设置 WebView 控制器
jsBridge.defaultHandler = _defaultHandler; // 设置默认处理函数
jsBridge.registerHandler("NativeEcho", _nativeEchoHandler); // 注册 Native 回调
},
navigationDelegate: (NavigationRequest navigation) {
print('navigationDelegate ${navigation.url}'); // 打印导航请求
if (navigation.url.contains('__bridge_loaded__')) { // 检测 WebViewJavascriptBridge 加载完成
jsBridge.injectJs(esVersion: jsVersion); // 注入 JS 代码
return NavigationDecision.prevent; // 阻止默认导航
}
return NavigationDecision.navigate; // 允许导航
},
onPageFinished: (String url) {
jsBridge.injectJs(esVersion: jsVersion); // 页面加载完成后注入 JS
},
initialUrl: 'http://$address:$port/$htmlVersion.html', // 加载本地 HTML 文件
);
}
Future<void> _sendHello() async {
final res = await jsBridge.send('hello from native'); // 调用 JS 方法
print('_sendHello res: $res');
}
Future<void> _callJSEcho() async {
final res = await jsBridge.callHandler('JSEcho', data: 'callJs from native'); // 调用带参数的 JS 方法
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'; // 返回结果
}
}
默认 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);
}
});
更多关于Flutter WebView与JS交互插件webview_jsbridge_x的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter WebView与JS交互插件webview_jsbridge_x的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
webview_jsbridge_x
是一个用于在 Flutter 应用中实现 WebView 与 JavaScript 交互的插件。它允许你在 Flutter 和 WebView 中的 JavaScript 代码之间进行双向通信。以下是如何使用 webview_jsbridge_x
插件的基本步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 webview_jsbridge_x
插件的依赖:
dependencies:
flutter:
sdk: flutter
webview_jsbridge_x: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来获取依赖。
2. 导入插件
在你的 Dart 文件中导入 webview_jsbridge_x
插件:
import 'package:webview_jsbridge_x/webview_jsbridge_x.dart';
3. 创建 WebView 并初始化 JSBridge
使用 WebViewJsBridgeX
来创建 WebView 并初始化 JSBridge:
class MyWebView extends StatefulWidget {
@override
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late WebViewJsBridgeX _webViewJsBridge;
@override
void initState() {
super.initState();
_webViewJsBridge = WebViewJsBridgeX();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('WebView with JSBridge'),
),
body: WebView(
initialUrl: 'https://your-website.com',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webViewJsBridge.init(webViewController);
},
javascriptChannels: <JavascriptChannel>{
_webViewJsBridge.getJavascriptChannel(),
},
),
);
}
}
4. 注册 Flutter 方法供 JavaScript 调用
你可以注册 Flutter 方法,供 JavaScript 调用:
_webViewJsBridge.registerHandler('flutterMethod', (data) async {
print('Received data from JS: $data');
return 'Response from Flutter';
});
5. 在 JavaScript 中调用 Flutter 方法
在 WebView 中的 JavaScript 代码中,你可以调用 Flutter 注册的方法:
window.jsBridge.callHandler('flutterMethod', {key: 'value'}, function(response) {
console.log('Response from Flutter:', response);
});
6. 在 Flutter 中调用 JavaScript 方法
你也可以在 Flutter 中调用 JavaScript 方法:
_webViewJsBridge.callHandler('jsMethod', {'key': 'value'}).then((response) {
print('Response from JS: $response');
});
7. 在 JavaScript 中注册方法供 Flutter 调用
在 WebView 中的 JavaScript 代码中,你可以注册方法供 Flutter 调用:
window.jsBridge.registerHandler('jsMethod', function(data, callback) {
console.log('Received data from Flutter:', data);
callback('Response from JS');
});
8. 处理 WebView 的生命周期
确保在 WebView 的生命周期中正确处理 JSBridge 的初始化和销毁:
@override
void dispose() {
_webViewJsBridge.dispose();
super.dispose();
}
9. 处理 WebView 的页面加载事件
你可以在 WebView 的页面加载事件中执行一些初始化操作:
onPageFinished: (String url) {
_webViewJsBridge.injectJavascript();
},
10. 处理 WebView 的错误
你可以在 WebView 的错误事件中处理错误:
onWebResourceError: (WebResourceError error) {
print('WebView error: ${error.description}');
},