有模有樣解決Flutter裡Webview無法訪問HTTP頁面的問題

程式設計實驗室發表於2021-06-23

探索過程

Android9(好像是吧)開始谷歌就預設不讓開發者訪問不安全HTTP內容了,如果非要用HTTP,那必須在networkSecurityConfig裡配置cleartextTrafficPermitted才行。谷歌這個設計的出發點本是好的,HTTPS固然更安全我們都懂,但有時候這個後端介面你選擇不了要HTTP還是HTTPS,比如要使用沒有提供HTTPS的第三方服務,或者是本文的這種情況:在內嵌的webview裡訪問沒有HTTPS的網頁~

正常的Android應用,內嵌個webview,配置一下cleartextTrafficPermitted就可以正常訪問HTTP內容了,但是flutter官方的webview元件有點坑,你在flutter專案內的Android工程配置好cleartextTrafficPermitted之後他不管用……

每次遇到HTTP的網頁,就會報這個錯,很煩

然後這個問題我查了很久也沒啥好的解決方案,看到有人給flutter官方提了issues,但是還沒解決,那隻能自己來強行解決了……

知乎答主的無奈

我的思路是:遇到HTTP地址,直接轉成HTTPS來訪問,不過這隻能解決那些同時有HTTP和HTTPS的網站,遇到只有HTTP的網站就沒轍啦~

強行的實現過程

實現的程式碼很簡單,首先利用Webview的onWebViewCreated事件獲取WebViewController例項,然後在onPageFinished頁面載入完成事件裡判斷當前頁面地址是否http開頭,如果是的話就替換成HTTPS並且重新載入即可~

因為http的頁面載入在iOS上是白屏,Android上是錯誤資訊,所以為了提高使用者體驗,我們可以在onPageStarted事件里加入一個載入中的提示框。

做完的效果如下:

涉及的程式碼如下:

WebView(
  initialUrl: _url,
  allowsInlineMediaPlayback: true,
  javascriptMode: JavascriptMode.unrestricted,
  onWebViewCreated: (controller) => _webViewController = controller,
  onProgress: (value) => print('page progress: $value'),
  onPageStarted: (url) {
    print('onPageStarted: $url');
    if (url.contains('http://')) {
      _httpFlag = true;
      showLoading(context);
    }
  },
  onPageFinished: (value) {
    print('onPageFinished: $value');
    if (value.contains('http://')) {
      setState(() {
        _url = value.replaceAll('http://', 'https://');
      });
      _webViewController.loadUrl(_url);
    }
    if (value.contains('https://') && _httpFlag) {
      _httpFlag = false;
      Navigator.of(context).pop();
    }
  },
),

比較蠢的解決方法,通過效果圖可以看到,對使用者體驗的提升其實很有限,其實根本是治標不治本的,真要解決這問題還得靠官方~

真正的解決

其實前面說了這麼多,真正的解決方案還是靠的flutter官方填坑,好訊息是,在最新的flutter2版本中,flutter官方已經成功填坑,現在我們只需要在AndroidManifest.xml裡配置好usesCleartextTrafficnetwork_security_config即可!

具體操作就是在flutter專案下建立/android/app/src/main/res/xml/network_security_config.xml檔案,填上配置內容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>

然後修改/android/app/src/main/AndroidManifest.xml檔案,在application節點加入以下兩個屬性即可:

android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"

完成之後你的專案結構應該是類似這樣的

之後在控制檯執行flutter clean,重新run,就可以看到App裡的webview能正常開啟HTTP網站了,妙啊~

參考資料

歡迎交流

程式設計實驗室專注於網際網路熱門新技術探索與團隊敏捷開發實踐,在公眾號「程式設計實驗室」後臺回覆 linux、flutter、c#、netcore、android、kotlin、java、python 等可獲取相關技術文章和資料,同時有任何問題都可以在公眾號後臺留言~

相關文章