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.dartstatic String jsChannel = "JianghuBridge";
- 定义 JavascriptChannel,并在 onMessageReceived 中对事件做出响应。
//代码来源:jianghuAppBrowser/jianghuBrowser/lib/layout/WebViewHandler.dartJavascriptChannel 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.dartFuture<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.jsfunction 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.jswindow.jianghuBridgeCallbackMap[`${actionTime}`] = callback;
- 执行回调
//代码来源:/jianghuAppBrowser/jianghuBrowser/assets/jianghuJsBridge.jsfunction 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'});}