在 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

相关文章
相关标签/搜索