在 Flutter 中使用 WebView

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

前言

咱們知道在開發 Native App 時常常會有打開網頁的需求,可供的選擇一般只有兩種:java

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

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

image-20190807100211727

簡單的介紹下 Android 中的 WebView

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

在 Android 中咱們須要先在一個 Layout 中放入 WebView 這個控件,而後在對應的 Activity 或者 Fragment 或者各類 Custom View 中執行一個個的 findViewById……瀏覽器

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

WebView in Flutter

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

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

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

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

在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,或者在終端輸入 Flutter package get,順序以下圖所示:

新建一個 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,所以咱們想使用他的時候只須要跳轉到該頁面,並傳入標題和網址便可。這裏以某個 RaisedButtononPressed() 舉例

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 設備上運行!

運行效果以下圖所示:

這裏只是簡單介紹 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 文件中添加以下字段:

<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」查看下載

參考

  1. 如何在 Flutter 中使用 WebView?- 小女 Android 工程師實驗筆記
  2. WebViews in Flutter – What an Amazing Breakthrough!
  3. Android 9: Cleartext HTTP traffic not permitted in webview

相關文章
相關標籤/搜索