Flutter WebView與JS交互簡易指南

本文采用Flutter官方WebView插件:pub.dartlang.org/packages/we…javascript

  WebView與JS互相調用是一個剛需,可是貌似如今你們寫的文章講的都不是很清楚,我這個簡易指南簡單粗暴地分爲兩部分:JS調用FlutterFlutter調用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

  JS調用Flutter有兩種方法:使用javascriptChannels發送消息使用路由委託(navigationDelegate)攔截urlgit

方法1:使用javascriptChannels發送消息

  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

方法2:使用路由委託navigationDelegate攔截url

  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://webviewscheme的路由地址了: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:容許路由替換。

Flutter調用JS

  在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測試地址請本身生成!

相關文章
相關標籤/搜索