在 Flutter 中使用 WebView

在 Flutter 中使用 WebView

本文示例代碼可在微信公眾號「01二進制」後臺回覆「WebView」查看下載

前言

我們知道在開發 Native App 時經常會有打開網頁的需求,可供的選擇通常只有兩種:

  1. 在 App 內部打開網頁
  2. 通過調用系統自帶瀏覽器打開網頁

以「微信」舉例,我們在微信內閱讀公眾號的時候就是第一種情況,但是微信同時也提供了Open with Browser 這一選項,這就是第二種情況了。

在 Flutter 中使用 WebView

簡單的介紹下 Android 中的 WebView

想實現第一種效果,我們需要使用一個名為 WebView 的東西,先來看看在 Android 中如何實現一個 WebView 吧。

在 Flutter 中使用 WebView

在 Android 中我們需要先在一個 Layout 中放入 WebView 這個控件,然後在對應的 Activity 或者 Fragment 或者各種 Custom View 中執行一個個的 findViewById……

在 Flutter 中使用 WebView

額,Android 開發者一定知道我在說什麼(真的很麻煩)

WebView in Flutter

Flutter 的 WebView 出現已經有一段時間了,在 Flutter 插件社區官網搜索 WebView 即可搜索到比較流行的插件,如下圖所示:

在 Flutter 中使用 WebView

其中 webview_flutter 是官方維護的 WebView 插件,特性是基於原生和 Flutter SDK 封裝,繼承 StatefulWidget,因此支持內嵌於 flutter Widget 樹中,這是比較靈活的;

flutter_webview_plugin 則是基於原生 WebView 封裝的 Flutter 插件,將原生的一些基本使用 API 封裝好提供給 Flutter 調用,因此並不能內嵌於 Flutter Widget 樹中,因此在界面的跳轉必須得先釋放掉,返回後又要重新初始化,所以顯示會有很多限制性;

interactive_webview 則是基於 webview_flutter 封裝的 Flutter 插件,因此原理特性上基本與官方 WebView 一致的;

在2018年 Flutter 發展初期,官方的 webview_flutter 插件有很多問題,不過好在官方一直沒有放棄,現在的插件已經修復了很多 bug 了,基本功能也在不斷完善中。

flutter_webview_plugin 插件由於其特性原因使用不靈活,因此本文我將會選擇官方提供的 webview_flutter 作為加載網頁的 WebView 插件。

使用

webview_flutter 插件的地址為https://pub.flutter-io.cn/packages/webview_flutter

導包

和任何一個 Flutter package 一樣,我們需要在 pubspec.yml 中的 dependencies 下加入 webview_flutter 的 package

<code>dependencies:
webview_flutter: ^0.3.10+4
/<code>

然後點擊標籤欄出現的 Packages get,或者在終端輸入 Flutter package get,順序如下圖所示:

在 Flutter 中使用 WebView

新建一個 Widget

接下來我們新建一個 WebViewWidget,這個 Widget 接收兩個參數,分別是瀏覽器頁面標題和瀏覽頁面的 Url,我將其命名為 Browser ,並存放在 browser.dart 文件中。

<code>import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class Browser extends StatelessWidget {
const Browser({Key key, this.url, this.title}) : super(key: key);

final String url;
final String title;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
),
);
}
}
/<code>

使用該頁面

在這裡我們用一個新的頁面來盛放 WebView,因此我們想使用他的時候只需要跳轉到該頁面,並傳入標題和網址即可。這裡以某個 RaisedButton 的 onPressed() 舉例

<code>onPressed: () {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (_) {
return new Browser(
url: "https://flutter-io.cn/",
title: "Flutter 中文社區",
);
}));
}
/<code>

對了別忘了要在 IOS 模塊的 Runner 中的 info.plist

文件中加入:

<code>io.flutter.embedded_views_preview
<string>YES/<string>
/<code>

不然這個 package 可沒辦法在 iOS 設備上運行!

運行效果如下圖所示:

在 Flutter 中使用 WebView

這裡只是簡單介紹 webview 在 Flutter 中的使用,其中的高級特性比如與 JavaScript 交互並沒有介紹到,有興趣的讀者可以自行查找資料閱讀。

這就結束了嗎?

其實到這裡的時候應該是就已經結束了,但是我在使用過程中發現了一個很嚴重的問題,如果我們的 URL 是 HTTP 而不是 HTTPS 的話,那麼就只可以在 Android 9.0 以下的設備運行(iOS同樣不可以)。

如果運行在 iOS 上會出現白屏,如果運行在 Android 9.0+ 的設備上就會出現 net::ERR_CLEARTEXT_NOT_PERMITTED 的錯誤。

其實原因很簡單,因為無論是 iOS 還是 Android 9.0+ 都對非 HTTPS 的請求做了一些限制,下面給出我的解決方案。

iOS

我們需要在 IOS 模塊的 Runner 中的 info.plist 文件中添加如下字段:

<code>NSAppTransportSecurity
<dict>
NSAllowsArbitraryLoads
<true>
/<dict>/<code>

然後執行 flutter clean 後重新運行即可訪問 HTTP 網頁了。

Android

很抱歉,其實到現在我也沒找到在 Android 9.0+ 上通過 flutter 的 webview 訪問 HTTP 網站的辦法,我寫在這裡也是希望如果我的讀者找到了解決方案的話歡迎在評論區留言。這裡就說一下我嘗試的一些解決辦法。

其實如果是 Android 原生想解決 HTTP 限制問題有以下幾種方案:

  1. 切換到 HTTPS
  2. targetSdkVersion 的版本號改到 28 以下
  3. 在 AndroidManifest.xml 文件中增加 android:usesCleartextTraffic="true" 配置項

第一個解決方法通常是針對自己的網站的,畢竟你總不能讓第三方網站申請 HTTPS 證書吧。

第二個解決方案在 Flutter 中是無法實現的,因為 Flutter 的運行是需要 Android SDK 28 以上的。

第三種方法我也試了,但是並沒有效果。

我查閱了很多資料,也發現了一個曲線救國的做法,就是檢測要訪問的網頁,如果是 HTTPS 的就利用 WebView 訪問,如果是 HTTP 的就調用第三方瀏覽器訪問。

額,這個做法吧,不好評價。

我已經在 StackOverflow 和 Flutter 的 issue 提交了問題,如果後續有解決方案,我會持續更新的。

總結

總的來說,隨著 Google 對 WebView 控件的不斷更新,其體驗越來越好了,使用起來相對於原生的 WebView 也更加簡便,如果你有在你的 App 內使用 WebView 的想法不妨嘗試一下

本文示例代碼可在微信公眾號「01二進制」後臺回覆「WebView」查看下載


在 Flutter 中使用 WebView


分享到:


相關文章: