最近的业务需要使用Flutter开发App应用,其中打算将部分已有的Web应用进行复用,因此需要研究一下Flutter的Hybird应用开发,对JSBridge的简单封装,最终react中调用效果如下:
AppSDK.Test({
text: 'Test!!',
onSuccess: (e) => {
setTest((state) => e.text);
},
onFail: (e) => {
console.log('inFail',e);
},
});
需满足以下条件:
- 方法调用方式类似于wx的写法
- 实现双向通信
- 可以传入回调函数,this指向定义它的上下文对象
1. flutter项目配置文件pubspec.yaml中引入依赖:
dependencies:
webview_flutter: ^4.2.2
2. flutter中使用
main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
void main() => runApp(MaterialApp(
title: '',
home: WebViewExample(),
));
class WebViewExample extends StatefulWidget {
const WebViewExample({super.key});
State<WebViewExample> createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late final WebViewController _controller;
void initState() {
super.initState();
late final PlatformWebViewControllerCreationParams params;
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
} else {
params = const PlatformWebViewControllerCreationParams();
}
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);
controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..loadRequest(Uri.parse('https://www.baidu.com/'));
// #docregion platform_features
if (controller.platform is AndroidWebViewController) {
AndroidWebViewController.enableDebugging(true);
(controller.platform as AndroidWebViewController)
.setMediaPlaybackRequiresUserGesture(false);
}
_controller = controller;
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body:WebViewWidget(controller: _controller)
);
}
}
3. JSBridge封装
3.1 webview发送消息给Native
let callbackId = 1;
function callAppMethod(config) {
// 注册全局回调函数
const callbackName = `${config.method}_${callbackId}`;
const params = config.params;
for (let key in params) {
if (typeof params[key] === 'function') {
params[key].bind(config);
}
}
window[callbackName] = params;
//向Native发送消息
AppSDK.postMessage(
JSON.stringify({ ...config, callbackName }),
);
}
export const Test = (params) => {
callAppMethod({
method: 'Test',
params,
});
};
3.2 Native接收webview发送的消息
main.dart
import 'app_sdk/web_call_app.dart';
...
controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
//
..addJavaScriptChannel(
'AppSDK',
onMessageReceived: (JavaScriptMessage message) async {
Map messageData = jsonDecode(message.message);
//处理接收到的参数
handerWebMessage(messageData, _controller);
},
)
web_call_app.dart
import 'dart:convert';
import 'package:answer/app_sdk/gromore_sdk.dart';
import 'package:flutter/cupertino.dart';
import 'app_sdk.dart';
void handerWebMessage(message, controller) {
debugPrint('handerWebMessage接收到的message: $message');
String method = message['method'];
String callbackName = message['callbackName'];
Map params = new Map();
if (message['params'] is Map) {
params.addAll(message['params']);
}
// 所有的API均通过handlers进行映射,键值对应前端传入的method
Map handlers = getHandlers();
if (handlers.containsKey(method)) {
try {
handlers[method](
params: params,
runJSFunction: (String fn, [e = '']) {
//执行webview定义的回调函数
controller.runJavaScript('''
window.$callbackName.$fn(${jsonEncode(e)})
delete window[$callbackName]
''');
});
} catch (e) {
debugPrint('$method:$e');
}
} else {
debugPrint('无$method对应接口实现');
}
}
Map getHandlers() {
return {
'Test': ({params, runJSFunction}) {
debugPrint('-----Test-------');
runJSFunction('onSuccess', {
'type': 'success',
'text': params['text']
});
}
};
}