詳解Flutter WebView與JS互相調(diào)用簡易指南
本文采用Flutter官方WebView插件:https://pub.dartlang.org/packages/webview_flutter
WebView與JS互相調(diào)用是一個剛需,但是貌似現(xiàn)在大家寫的文章講的都不是很清楚,我這個簡易指南簡單粗暴地分為兩部分:JS調(diào)用Flutter和Flutter調(diào)用JS,拒絕花里胡哨,保證一看就懂,一學(xué)就會。
開始之前先簡單了解一下官方WebView所包含的API:
- onWebViewCreated:在WebView創(chuàng)建完成后調(diào)用,只會被調(diào)用一次;
- initialUrl:初始load的url;
- javascriptMode:JS執(zhí)行模式(是否允許JS執(zhí)行);
- javascriptChannels:JS和Flutter通信的Channel;
- navigationDelegate:路由委托(可以通過在此處攔截url實現(xiàn)JS調(diào)用Flutter部分);
- gestureRecognizers:手勢監(jiān)聽;
- onPageFinished:WebView加載完畢時的回調(diào)。
JS調(diào)用Flutter
JS調(diào)用Flutter有兩種方法:使用javascriptChannels發(fā)送消息和使用路由委托(navigationDelegate)攔截url。
方法1:使用javascriptChannels發(fā)送消息
javascriptChannels參數(shù)可以傳入一組Channels,我們可以定義一個_alertJavascriptChannel變量,這個channel用來控制JS調(diào)用Flutter的toast功能:
JavascriptChannel _alertJavascriptChannel(BuildContext context) { return JavascriptChannel( name: 'Toast', onMessageReceived: (JavascriptMessage message) { showToast(message.message); }); } WebView( avascriptChannels: <JavascriptChannel>[ _alertJavascriptChannel(context), ].toSet(), ;
在上面的代碼中,我們定義了一個_alertJavascriptChannel變量,并給它起了個name叫Toast,這個name屬性接收的是一個字符串,它代表了JS調(diào)用Flutter時,雙方共同商定好了的一個協(xié)議,JS通過這個name去post對應(yīng)的信息給Flutter(API為name.postMessage('xxxxxx'))。我們在網(wǎng)頁部分寫一個簡單的button,點擊后開始JS調(diào)用Flutter的邏輯:
<button onclick="callFlutter()">callFlutter</button> function callFlutter(){ Toast.postMessage("JS調(diào)用了Flutter"); }
onMessageReceived為Flutter接收到了JS的消息之后的回調(diào),我們可以通過message.message來獲取JS發(fā)給我們的消息內(nèi)容。JavascriptMessage類暫時只有一個String類型的message成員變量,所以如果需要傳遞復(fù)雜數(shù)據(jù),可以通過傳遞json字符串來解決。
代碼重點:JavascriptChannel中的name要與JS中的name.postMessage()相對應(yīng)!!
方法2:使用路由委托navigationDelegate攔截url
navigationDelegate回調(diào)在每次網(wǎng)頁路由地址發(fā)生變化的時候都會觸發(fā),因此我們可以攔截特定的url來實現(xiàn)JS調(diào)用Flutter。
同樣的,我們在網(wǎng)頁部分寫一個簡單的button,點擊后跳轉(zhuǎn)路由"js://webview?arg1=111&args2=222"。我們可以和客戶端協(xié)商好一個scheme,比如這個例子里面就是js://webview,我們可以在query string上帶上我們想要傳遞的參數(shù):
<button onclick="callFlutter()">callFlutter</button> function callFlutter(){ /*約定的url協(xié)議為:js://webview?arg1=111&arg2=222*/ document.location = "js://webview?arg1=111&args2=222"; }
在Flutter端,我們就可以在navigationDelegate回調(diào)中攔截這個符合js://webviewscheme的路由地址了:
navigationDelegate: (NavigationRequest request) { if (request.url.startsWith('js://webview')) { showToast('JS調(diào)用了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:允許路由替換。
Flutter調(diào)用JS
在WebView創(chuàng)建完成之后,我們可以拿到一個WebViewController,通過它的evaluateJavascript()方法,我們可以執(zhí)行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 調(diào)用了 JS. Flutter 調(diào)用了 JS. Flutter 調(diào)用了 JS. </p> function callJS(message){ document.getElementById("p1").style.visibility = message; }
在上面的例子中,我們點擊floatingActionButton后,就會去執(zhí)行JS中的callJS()方法了,具體UI體現(xiàn)為:將隱藏的段落重新顯示。evaluateJavascript()返回值是一個Future,因此我們可以接收JS給我們的返回值,返回值格式請閱讀官方API注釋。
這里要注意的是,evaluateJavascript()方法,F(xiàn)lutter建議我們在onPageFinished回調(diào)之后去執(zhí)行,以保證所有的HTML都已經(jīng)加載完畢了。因此在實際開發(fā)中,我這里展示的這種直接將onWebViewCreated中的controller賦值的方法是不可取的,應(yīng)該是使用FutureBuilder之類的方式去實現(xiàn)比較優(yōu)雅(我在Gist上有完整的例子,大家可以看下)。
源碼
調(diào)試工具推薦使用 Amaze UI ,一個神奇的網(wǎng)站,一鍵生成調(diào)試網(wǎng)頁,你值得擁有
注意:源碼中的initialUrl測試地址請自己生成!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android RecyclerView添加頭部和底部的方法
這篇文章主要為大家詳細介紹了Android RecyclerView添加頭部和底部的方法,感興趣的小伙伴們可以參考一下2016-05-05Android檢測Activity或者Service是否運行的方法
下面小編就為大家分享一篇Android檢測Activity或者Service是否運行的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03Android開發(fā)中類加載器DexClassLoader的簡單使用講解
這篇文章主要介紹了Android開發(fā)中類加載器DexClassLoader的簡單使用講解,DexClassLoader可以看作是一個特殊的Java中的ClassLoader,需要的朋友可以參考下2016-04-04Android編程使用ListView實現(xiàn)數(shù)據(jù)列表顯示的方法
這篇文章主要介紹了Android編程使用ListView實現(xiàn)數(shù)據(jù)列表顯示的方法,實例分析了Android中ListView控件的使用技巧,需要的朋友可以參考下2016-01-01Flutter使用NetworkImage實現(xiàn)圖像顯示效果
這篇文章主要為大家介紹了如何在Flutter中使用NetworkImage實現(xiàn)圖像顯示效果,文中的示例代碼講解詳細,快跟隨小編一起學(xué)習(xí)一下吧2022-04-04詳解Flutter WebView與JS互相調(diào)用簡易指南
這篇文章主要介紹了詳解Flutter WebView與JS互相調(diào)用簡易指南,分為JS調(diào)用Flutter和Flutter調(diào)用JS,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04