詳解Flutter WebView與JS互相調(diào)用簡(jiǎn)易指南
本文采用Flutter官方WebView插件:https://pub.dartlang.org/packages/webview_flutter
WebView與JS互相調(diào)用是一個(gè)剛需,但是貌似現(xiàn)在大家寫的文章講的都不是很清楚,我這個(gè)簡(jiǎn)易指南簡(jiǎn)單粗暴地分為兩部分:JS調(diào)用Flutter和Flutter調(diào)用JS,拒絕花里胡哨,保證一看就懂,一學(xué)就會(huì)。
開始之前先簡(jiǎn)單了解一下官方WebView所包含的API:
- onWebViewCreated:在WebView創(chuàng)建完成后調(diào)用,只會(huì)被調(diào)用一次;
- initialUrl:初始load的url;
- javascriptMode:JS執(zhí)行模式(是否允許JS執(zhí)行);
- javascriptChannels:JS和Flutter通信的Channel;
- navigationDelegate:路由委托(可以通過在此處攔截url實(shí)現(xiàn)JS調(diào)用Flutter部分);
- gestureRecognizers:手勢(shì)監(jiān)聽;
- onPageFinished:WebView加載完畢時(shí)的回調(diào)。
JS調(diào)用Flutter
JS調(diào)用Flutter有兩種方法:使用javascriptChannels發(fā)送消息和使用路由委托(navigationDelegate)攔截url。
方法1:使用javascriptChannels發(fā)送消息
javascriptChannels參數(shù)可以傳入一組Channels,我們可以定義一個(gè)_alertJavascriptChannel變量,這個(gè)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(),
;
在上面的代碼中,我們定義了一個(gè)_alertJavascriptChannel變量,并給它起了個(gè)name叫Toast,這個(gè)name屬性接收的是一個(gè)字符串,它代表了JS調(diào)用Flutter時(shí),雙方共同商定好了的一個(gè)協(xié)議,JS通過這個(gè)name去post對(duì)應(yīng)的信息給Flutter(API為name.postMessage('xxxxxx'))。我們?cè)诰W(wǎng)頁(yè)部分寫一個(gè)簡(jiǎn)單的button,點(diǎn)擊后開始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類暫時(shí)只有一個(gè)String類型的message成員變量,所以如果需要傳遞復(fù)雜數(shù)據(jù),可以通過傳遞json字符串來解決。
代碼重點(diǎn):JavascriptChannel中的name要與JS中的name.postMessage()相對(duì)應(yīng)??!
方法2:使用路由委托navigationDelegate攔截url
navigationDelegate回調(diào)在每次網(wǎng)頁(yè)路由地址發(fā)生變化的時(shí)候都會(huì)觸發(fā),因此我們可以攔截特定的url來實(shí)現(xiàn)JS調(diào)用Flutter。
同樣的,我們?cè)诰W(wǎng)頁(yè)部分寫一個(gè)簡(jiǎn)單的button,點(diǎn)擊后跳轉(zhuǎn)路由"js://webview?arg1=111&args2=222"。我們可以和客戶端協(xié)商好一個(gè)scheme,比如這個(gè)例子里面就是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)中攔截這個(gè)符合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怎么處理這個(gè)路由:
- NavigationDecision.prevent:阻止路由替換;
- NavigationDecision.navigate:允許路由替換。
Flutter調(diào)用JS
在WebView創(chuàng)建完成之后,我們可以拿到一個(gè)WebViewController,通過它的evaluateJavascript()方法,我們可以執(zhí)行JS語(yǔ)句:
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;
}
在上面的例子中,我們點(diǎn)擊floatingActionButton后,就會(huì)去執(zhí)行JS中的callJS()方法了,具體UI體現(xiàn)為:將隱藏的段落重新顯示。evaluateJavascript()返回值是一個(gè)Future,因此我們可以接收J(rèn)S給我們的返回值,返回值格式請(qǐng)閱讀官方API注釋。
這里要注意的是,evaluateJavascript()方法,F(xiàn)lutter建議我們?cè)趏nPageFinished回調(diào)之后去執(zhí)行,以保證所有的HTML都已經(jīng)加載完畢了。因此在實(shí)際開發(fā)中,我這里展示的這種直接將onWebViewCreated中的controller賦值的方法是不可取的,應(yīng)該是使用FutureBuilder之類的方式去實(shí)現(xiàn)比較優(yōu)雅(我在Gist上有完整的例子,大家可以看下)。
源碼
調(diào)試工具推薦使用 Amaze UI ,一個(gè)神奇的網(wǎng)站,一鍵生成調(diào)試網(wǎng)頁(yè),你值得擁有
注意:源碼中的initialUrl測(cè)試地址請(qǐng)自己生成!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android利用EditText如何實(shí)現(xiàn)搜索框詳解
EditText 在開發(fā)中也是經(jīng)常用到的控件,也是一個(gè)比較必要的組件,下面這篇文章主要給大家介紹了關(guān)于Android利用EditText如何實(shí)現(xiàn)搜索框的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-07-07
Android中App字體大小不隨系統(tǒng)改變而改變
這篇文章主要介紹了Android中App字體大小不隨系統(tǒng)改變而改變,需要的朋友可以參考下2017-04-04
教你如何搭建android源代碼repo倉(cāng)庫(kù)
這篇文章主要介紹了如何搭建android源代碼repo倉(cāng)庫(kù),如果你的開發(fā)是基于AOSP源碼來建倉(cāng),那么搭建repo服務(wù)器和部署自己的repo倉(cāng)庫(kù)就是非常必要的工作了,本文給大家詳細(xì)介紹搭建過程,感興趣的朋友一起看看吧2022-07-07
Kotlin圖文并茂講解續(xù)體與續(xù)體攔截器和調(diào)度器
這篇文章主要介紹了Kotlin開發(fā)中續(xù)體與續(xù)體攔截器和調(diào)度器的相關(guān)使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Android仿QQ好友列表實(shí)現(xiàn)列表收縮與展開
這篇文章主要介紹了Android仿QQ好友列表實(shí)現(xiàn)列表收縮與展開,感興趣的小伙伴們可以參考一下2015-12-12
Android控件BottomSheet實(shí)現(xiàn)底邊彈出選擇列表
這篇文章主要介紹了Android控件BottomSheet實(shí)現(xiàn)底邊彈出選擇列表,比較常用的選擇條件或跳轉(zhuǎn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
ShareSDK造成App崩潰的一個(gè)BUG原因分析以及Fix方法
這篇文章主要介紹了ShareSDK造成App崩潰的一個(gè)BUG原因分析以及Fix方法,使用的是Cocos2d-x專用ShareSDK組件,需要的朋友可以參考下2014-04-04
Android中用RxJava和ViewPager實(shí)現(xiàn)輪播圖
現(xiàn)在App中實(shí)現(xiàn)一個(gè)輪播圖已經(jīng)是很多產(chǎn)品的標(biāo)配了,這篇文章給大家詳細(xì)介紹了如何利用RxJava和ViewPager實(shí)現(xiàn)輪播圖,有需要的朋友們可以參考借鑒,下面來一起看看吧。2016-09-09
android ocr——身份證識(shí)別的功能實(shí)現(xiàn)
本篇文章主要介紹了android ocr——身份證識(shí)別的功能實(shí)現(xiàn),具有一定的參考價(jià)值,有需要的可以了解一下。2016-11-11

