本文采用Flutter官方WebView插件:pub.dartlang.org/packages/we…javascript
WebView與JS互相調用是一個剛需,可是貌似如今你們寫的文章講的都不是很清楚,我這個簡易指南簡單粗暴地分爲兩部分:JS調用Flutter
和Flutter調用JS
,拒絕花裏胡哨,保證一看就懂,一學就會。html
開始以前先簡單瞭解一下官方WebView所包含的API:java
onWebViewCreated
:在WebView建立完成後調用,只會被調用一次;initialUrl
:初始load的url;javascriptMode
:JS執行模式(是否容許JS執行);javascriptChannels
:JS和Flutter通訊的Channel;navigationDelegate
:路由委託(能夠經過在此處攔截url實現JS調用Flutter部分);gestureRecognizers
:手勢監聽;onPageFinished
:WebView加載完畢時的回調。 JS調用Flutter有兩種方法:使用javascriptChannels發送消息
和使用路由委託(navigationDelegate)攔截url
。git
javascriptChannels
參數能夠傳入一組Channels,咱們能夠定義一個_alertJavascriptChannel變量
,這個channel用來控制JS調用Flutter的toast功能:github
JavascriptChannel _alertJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toast',
onMessageReceived: (JavascriptMessage message) {
showToast(message.message);
});
}
WebView(
javascriptChannels: <JavascriptChannel>[
_alertJavascriptChannel(context),
].toSet(),
;
複製代碼
在上面的代碼中,咱們定義了一個_alertJavascriptChannel變量
,並給它起了個name叫Toast
,這個name屬性接收的是一個字符串,它表明了JS調用Flutter時,雙方共同商定好了的一個協議,JS經過這個name去post對應的信息給Flutter(API爲name.postMessage('xxxxxx')
)。咱們在網頁部分寫一個簡單的button,點擊後開始JS調用Flutter的邏輯:web
<button onclick="callFlutter()">callFlutter</button>
function callFlutter(){
Toast.postMessage("JS調用了Flutter");
}
複製代碼
onMessageReceived
爲Flutter接收到了JS的消息以後的回調,咱們能夠經過message.message
來獲取JS發給咱們的消息內容。JavascriptMessage
類暫時只有一個String類型的message成員變量,因此若是須要傳遞複雜數據,能夠經過傳遞json字符串來解決。json
代碼重點:JavascriptChannel中的name要與JS中的name.postMessage()相對應!!bash
navigationDelegate
回調在每次網頁路由地址發生變化的時候都會觸發,所以咱們能夠攔截特定的url來實現JS調用Flutter。
一樣的,咱們在網頁部分寫一個簡單的button,點擊後跳轉路由"js://webview?arg1=111&args2=222"
。咱們能夠和客戶端協商好一個scheme,好比這個例子裏面就是js://webview
,咱們能夠在query string上帶上咱們想要傳遞的參數:工具
<button onclick="callFlutter()">callFlutter</button>
function callFlutter(){
/*約定的url協議爲:js://webview?arg1=111&arg2=222*/
document.location = "js://webview?arg1=111&args2=222";
}
複製代碼
在Flutter端,咱們就能夠在navigationDelegate
回調中攔截這個符合js://webview
scheme的路由地址了:post
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('js://webview')) {
showToast('JS調用了Flutter By navigationDelegate');
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
複製代碼
咱們經過return不一樣的值,告訴WebView怎麼處理這個路由:
NavigationDecision.prevent
:阻止路由替換;NavigationDecision.navigate
:容許路由替換。 在WebView建立完成以後,咱們能夠拿到一個WebViewController,經過它的evaluateJavascript()
方法,咱們能夠執行JS語句:
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
······
floatingActionButton: FloatingActionButton(
onPressed: () {
_controller
?.evaluateJavascript('callJS("visible")')
?.then((result) {
// You can handle JS result here.
});
},
child: Text('call JS'),
),
複製代碼
<p id="p1" style="visibility:hidden;">
Flutter 調用了 JS.
Flutter 調用了 JS.
Flutter 調用了 JS.
</p>
function callJS(message){
document.getElementById("p1").style.visibility = message;
}
複製代碼
在上面的例子中,咱們點擊floatingActionButton後,就會去執行JS中的callJS()
方法了,具體UI體現爲:將隱藏的段落從新顯示。evaluateJavascript()
返回值是一個Future,所以咱們能夠接收JS給咱們的返回值,返回值格式請閱讀官方API註釋,要注意Android端和iOS端的返回值格式是不同的,Android端返回的是json字符串,iOS暫時只支持string和string格式的NSArray,其餘類型數據還不支持。
這裏要注意的是,evaluateJavascript()
方法,Flutter建議咱們在onPageFinished
回調以後去執行,以保證全部的HTML都已經加載完畢了。所以在實際開發中,我這裏展現的這種直接將onWebViewCreated
中的controller賦值的方法是不可取的,應該是使用FutureBuilder
之類的方式去實現比較優雅(我在Gist上有完整的例子,你們能夠看下)。
注意:源碼中的initialUrl
測試地址請本身生成!