天天看點

在 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

dependencies:  webview_flutter: ^0.3.10+4           

複制

然後點選标簽欄出現的 Packages get,或者在終端輸入

Flutterpackageget

,順序如下圖所示:

在 Flutter 中使用 WebView

建立一個 Widget

接下來我們建立一個 WebViewWidget,這個 Widget 接收兩個參數,分别是浏覽器頁面标題和浏覽頁面的 Url,我将其命名為

Browser

,并存放在

browser.dart

檔案中。

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,      ),    );  }}           

複制

使用該頁面

在這裡我們用一個新的頁面來盛放 WebView,是以我們想使用他的時候隻需要跳轉到該頁面,并傳入标題和網址即可。這裡以某個 RaisedButton 的

onPressed()

舉例

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

複制

對了别忘了要在 IOS 子產品的 Runner 中的 info.plist 檔案中加入:

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

複制

不然這個 package 可沒辦法在 iOS 裝置上運作!

運作效果如下圖所示:

在 Flutter 中使用 WebView
這裡隻是簡單介紹 webview 在 Flutter 中的使用,其中的進階特性比如與 JavaScript 互動并沒有介紹到,有興趣的讀者可以自行查找資料閱讀。

這就結束了嗎?

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

如果運作在 iOS 上會出現白屏,如果運作在 Android 9.0+ 的裝置上就會出現 net::ERRCLEARTEXTNOT_PERMITTED 的錯誤。

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

iOS

我們需要在 IOS 子產品的 Runner 中的 info.plist 檔案中添加如下字段:

<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict>           

複制

然後執行

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」檢視下載下傳