前沿
作为移动端开发,免不了需要内嵌 H5网页 的需求。在 Flutter 中我们一般通过官方的 [webview_flutter]插件实现 WebView 的加载。[webview_flutter]插件是由官方维护,底层通过 WebView / WKWebView 原生组件实现,不管是稳定性还是可靠性上都有保障。但其在与 H5端 的 JSBridge 调用上却差强人意,目前只支持 H5端 到 App端 的单向调用,而且还不能直接获取返回值,这大大限制了我们对于 [webview_flutter]插件的使用。
为了解决 [webview_flutter]的 JS 调用问题,[NativeBridge] 插件应运而生。
效果展示
在介绍插件前,我们先看看集成后的效果:
image.pngNativeBridge 插件的优点
- 支持 H5端 调用 App端 的 JSBridge 方法,并可以 直接获取返回值。
- 支持 App端 调用 H5端 的 JSBridge 方法,并可以 直接获取返回值。
- 使用简单,集成插件后实现 NativeBridgeImpl 类,即可完成 App端 的 JS调用 能力的支持。
NativeBridge 的引入
NativeBridge 插件目前支持2种引入方式:1)本地代码引入 2)Git 依赖
- 本地代码引入。由于插件本身只引入了 webview_flutter 插件,所以可以直接拷贝相关代码到自己的项目即可。
- Git 依赖。目前由于插件还没有发布到 pub ,大家可以先通过 Git 依赖的方式引入。
dependencies:
native_bridge:
git:
url: https://github.com/Fitem/native_bridge.git
NativeBridge 的集成
1. App端。在 App端,插件的使用非常简单,只需要下面 两步 即可完成。
第一步,通过 implements NativeBridgeImpl 类,实现其对应的方法。例如 example 中的 NativeBridgeController 类的实现:
class NativeBridgeController implements NativeBridgeImpl {
NativeBridgeController({required this.controller});
// WebView控制器
final Future<WebViewController> controller;
/// 对应JS调用Function集合
@override
Map<String, Function?> get callMethodMap => {
// 版本号
"getVersionCode": (data) async {
return await AppUtil.getVersion();
},
// 版本名称
"getVersionName": (data) async {
return await AppUtil.getVersion();
},
//是否是App
"isApp": (data) {
return true;
},
//测试获取Web的值
"getWebValue": (data) async {
var isHome = await NativeBridgeHelper.sendMessage(
Message(api: "isHome"), this)
.future ??
false;
AppUtil.show("isHome:$isHome");
return true;
}
};
/// 指定JSChannel名称
@override
String get name => "nativeBridge";
/// 执行JS
@override
void runJavascript(String javaScriptString) {
controller.then((controller) =>
controller.runJavascript("receiveMessage($javaScriptString)"));
}
}
- NativeBridgeController 构造参数传入 WebView 的 Controller 对象,用于 runJavascript 的调用
- name 指定 H5 端生成的 window.nativeBridge 对象名称
- callMethodMap 定义 App端 可以支持的 JSBridge 方法和调用
第二步,在 WebView 组件中添加 NativeBridge。
//JS执行模式 是否允许JS执行
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: <JavascriptChannel>{
NativeBridge(
controller: _nativeBridgeController =
NativeBridgeController(controller: _controller.future),
)
}
2. H5端。H5端的实现也非常简单,1)引入 jsBridgeHelper.js 文件,2)window 对象添加 *receiveMessage 全局方法用于 App端消息的接收。
function receiveMessage(jsonStr) {
if(jsonStr != undefined && jsonStr != "") {
let data = JSON.parse(JSON.stringify(jsonStr));
window.jsBridgeHelper.receiveMessage(data);
}
}
NativeBridge 的使用
一、H5端 获取 App端 的值
- 在 App端 的 callMethodMap 中 定义方法名称 和 Function调用,比如获取 App 的版本号:
// 版本号
"getVersionCode": (data) async {
return await AppUtil.getVersion();
}
- 在 H5端 中调用对应方法:
async function getVersionName() {
// 获取 App 的值
let appVersionName = await window.jsBridgeHelper.sendMessage("getVersionName", null);
// 显示
document.getElementById("app_version_name").innerHTML = "app version name : " + appVersionName.toString();
}
展示效果:
[图片上传失败...(image-96709f-1669640787874)]
二、App端 获取 H5端 的值
- App端 先调用 sendMessage() 方法:
var isHome = await NativeBridgeHelper.sendMessage(
Message(api: "isHome"), _nativeBridgeController,
).future ?? false;
AppUtil.show("isHome:$isHome");
- H5端 在 jsBridgeHelper.js 类中的 receiveMessage() 方法中通过对 message.api 识别,通过 _postMessage() 方法发送App需要获取的值
receiveMessage(message) {
if (message.callbackId) {
// 通过callbackId 获取对应Promise
const cb = this._popCallback(message.callbackId);
if (cb) { //有值,则直接调用对应函数
cb(message.data);
} else { //没有值,则是App请求获取值
if (message.api === 'isHome') {
this._postMessage(message.api, true.toString(), message.callbackId)
}
}
}
}
展示效果:
[图片上传失败...(image-4024c5-1669640787874)]
总结
今天主要介绍了 Flutter 中基于 webview_flutter 插件实现 App端 和 H5端 的 JS 互调能力的插件 NativeBridge,以及 NativeBridge 的集成和使用,下一篇将介绍 NativeBridge 插件的实现原理和超时检测机制,感兴趣的同学可以关注后续文章。
本文转自 https://juejin.cn/post/7170557198701953038,如有侵权,请联系删除。
网友评论