App与Web的通讯方式
12147App和Web的通讯通道建立 (javascriptChannels)
在Flutter的WebView中,javascriptChannels也是一个重要的控制器。它是一个类型为Set的变量,允许Flutter应用和WebView之间进行javascript通信。该控制器用于定义自定义javascript通道,允许WebView调用Flutter代码中的指定方法并传递数据。Flutter代码可以在控制器中注册定义的通道,以便在WebView调用javascript时实现回调。这可以用于实现从JavaScript到Flutter的双向通信。通过使用javascriptChannels,开发人员可以在Flutter应用和WebView之间创建灵活的通信机制。
通信通道
- 定义 jsChannel
//代码来源:jianghuAppBrowser/jianghuBrowser/lib/common/Constants.dart
static String jsChannel = "JianghuBridge";
- 定义 JavascriptChannel,并在 onMessageReceived 中对事件做出响应。
//代码来源:jianghuAppBrowser/jianghuBrowser/lib/layout/WebViewHandler.dart
JavascriptChannel messagePost(BuildContext context, {Function? inputFocus}) {
return JavascriptChannel(
name: Constants.jsChannel, //JavascriptChannel的name指定为Constants.jsChannel(JianghuBridge),所以将通过JianghuBridge使用通信通道。
onMessageReceived: (JavascriptMessage message) async { //监听消息事件
Map result = jsonDecode(message.message);
if (result.containsKey('action')) {
//根据action判断需要做什么,如果没有定义并处理,则web端发送到app的消息是无响应的
switch (result['action']) {
case 'appUpdate':
VersionUtil.appUpdate(result, context);
break;
}
}
},
);
}
App发送消息到Web
有两种发送方式:
1、runJavascript,可以传递参数,无法接收回调
// web端定义一个全局方法,注册在window或直接使用function定义
function onAppResumed() {
//do something...
}
//App端调用
RenderKey.controller.value?.runJavascript("onAppResumed()");
2、runJavascriptReturningResult ,可以传递参数,可以接收回调
//web端定义方法
getReadyState: function () {
return 'complete';
},
//App端调用
String state = await RenderKey.controller.value!.runJavascriptReturningResult("getReadyState()");
以上两种方式,传递的参数只能是字符串,如果不是字符串,也会默认转换为字符串。回调里的返回结果也是字符串。
Web发送消息到App
jianghuJsBridge.js
jianghuJsBridge.js [文件目录:/jianghuAppBrowser/jianghuBrowser/assets/jianghuJsBridge.js]
定义了一些web端可使用的方法和变量。需要先注册jianghuJsBridge.js
,注册之后这些方法和变量将挂载在web端window上,web端可以调用和使用jianghuJsBridge.js
里的方法和变量。
//注册jianghuJsBridge.js,
//代码来源:jianghuAppBrowser/jianghuBrowser/lib/layout/WebViewHandler.dart
Future<void> registerJianghuJsBridge() async {
print("注册方法 registerJianghuJsBridge");
String jsStr = await rootBundle.loadString("assets/jianghuJsBridge.js");
RenderKey.controller.value!.runJavascript(jsStr);
RenderKey.controller.value!.runJavascript("checkReadyState()");
}
使用通信通道发送消息
有两种发送方式:
- 通过JianghuBridge.postMessage,postMessage是JavascriptChannel原生方法。postMessage只能发送字符串,如果是其他格式,需要转换一下。
//JianghuBridge.postMessage 发送消息
JianghuBridge.postMessage(JSON.stringify({ action: 'downloadFile', downloadPath, filename }));
- 通过jianghuBridgePostMessage,jianghuBridgePostMessage是在jianghuJsBridge.js中封装的一个方法,通过JianghuBridge.postMessage发送消息,对数据格式做了转换,并且注册了回调。
//代码来源:/jianghuAppBrowser/jianghuBrowser/assets/jianghuJsBridge.js
function jianghuBridgePostMessage(params, callback) {
try {
const actionTime = new Date().getTime();
params.actionTime = actionTime;
JianghuBridge.postMessage(`${JSON.stringify(params)}`);
if (callback != null) {
//注册回调,回调的具体实现见下文
window.jianghuBridgeCallbackMap[`${actionTime}`] = callback;
}
} catch (e) {
}
}
回调
App端接收到web端的消息,并处理完成之后,可以调用回调方法,将web端需要的数据返回给web端。
- 注册回调
//代码来源:/jianghuAppBrowser/jianghuBrowser/assets/jianghuJsBridge.js
window.jianghuBridgeCallbackMap[`${actionTime}`] = callback;
- 执行回调
//代码来源:/jianghuAppBrowser/jianghuBrowser/assets/jianghuJsBridge.js
function jianghuBridgeCallback(
actionTime,
data,
keepCallback = false
) {
console.log(`[jianghuBridgeCallbackMap]${actionTime} ${data}`)
if (window.jianghuBridgeCallbackMap.hasOwnProperty(`${actionTime}`)) {
try {
if(typeof data == 'string') {
console.log(`[jianghuBridgeCallbackMap]${actionTime} ${data}`)
window.jianghuBridgeCallbackMap[`${actionTime}`](JSON.parse(data));
} else {
console.log(`[jianghuBridgeCallbackMap]${actionTime} ${JSON.stringify(data)}`)
window.jianghuBridgeCallbackMap[`${actionTime}`](data);
}
} catch (err) {
window.jianghuBridgeCallbackMap[`${actionTime}`]();
}
if (keepCallback != true && keepCallback != 'true') {
delete window.jianghuBridgeCallbackMap[`${actionTime}`];
}
}
}
- 触发回调
//回调方法封装
void runJsCallback(methodName, {String? message}) {
if (_callBackId != null) {
String method = "jianghuBridgeCallback('$_callBackId', ${jsonEncode({'action': methodName, 'message': message})}, true)";
RenderKey.controller.value?.runJavascript(method);
}
}
//回调
runJsCallback('disconnected', message: "iceConnectionState disconnected");
示例
//jianghuJsBridge.js 中定义变量和方法
window.isBrowserApp = true;
window.jianghuBridge = {
forwardToChatSessionDone: (params, callBack) => {
jianghuBridgePostMessage({ action: 'forwardToChatSessionDone', ...params }, callBack)
},
};
//web端调用
if(window.isBrowserApp) {
window.jianghuBridge.forwardToChatSession({forwardUserId: '123'});
}