flutter_fai_webview 0.0.2

  • Readme
  • Changelog
  • Example
  • Installing
  • new50

flutter_fai_webview #

更多文章请查看 flutter从入门 到精通

可以用来加载 Html 页面,以实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能。

Flutter中可用于来加载 Html 页面的插件 ,

  • flutter_WebView_plugin
  • webView_flutter
  • flutter_inappbrowser
  • html
  • flutter_html
  • flutter_html_view

这些多多少满足不了我项目中的需求,所以花了几天时间开发了 Flutter_Fai_Webview 插件,可实现 Android 中 WebView 或者 是 iOS 中的 UIWebView 中的功能,因为 Flutter_Fai_Webview 插件本质上是通过 PlatformView 功能将原生的 View 嵌套在 Flutter 中。

插件源码在这里

开发插件要具备的知识:

Flutter_Fai_Webview 插件可实现的功能:

  • 同时适配于 Android Ios 两个平台
  • 通过 url 来加载渲染一个Html 页面
  • 加载 Html 文本数据 如 <html> .... </html>
  • 加载 Html 标签数据 如 <p> ... </p>
  • 实现 WebView 加载完成后,自动测量 WebView 的高度,并回调 Flutter
  • 实现 WebView 加载完成监听
  • 实现 WebView 上下滑动、滑动到顶部兼听、滑动到底部兼听并回调 Flutter
  • 实现 兼听 WebView 输出日志并将日志回调 Flutter
  • 实现 为 Html 页面中所有的图片添加点击事件 并回调 Flutter
  • 实现 Html 中Js 调用 Flutter 页面功能
  • 实现 Flutter 页面中 触发 Html 页面中 Js 方法

本插件开发的过程将在这里详细论述

也就是说在这里将教会你 开发一个 Flutter 插件。 Flutter 加载 HTML 详细阐述(iOS 端实现) Flutter 加载 HTML 详细阐述(Android 端实现)


开始使用

1 基本使用说明

1.1 Flutter 项目中 pubspec.xml 文件中 配置插件
  flutter_fai_webview:
    git:
      url: https://github.com/zhaolongs/Flutter_Fai_Webview.git
      ref: master
1.2 在使用到 WebView 页面中

引入头文件

import 'package:flutter_fai_webview/flutter_fai_webview.dart';
1.3 创建 WebView 组件

    //使用插件 FaiWebViewWidget
    webViewWidget = FaiWebViewWidget(
      //webview 加载网页链接
      url: htmlUrl,
      //webview 加载信息回调
      callback: callBack,
      //输出日志
      isLog: true,
    );
    
1.4 FaiWebViewWidget 构造参数说明
  FaiWebViewWidget({
    //webview 加载网页链接
    this.url,
    //webview 加载 完整的 html 文件数据  如 <html> .... </html>
    // 不完整的 html 文件数据 如 <p></p> 配置到此项,用此属性来加载,只会渲染 <p> ... </p> 中已有的样式 不会适配移动端显示
    this.htmlData,
    //webview 加载完整的 html 文件数据 或者是 不完整的 html 文件数据 如 <p></p>
    //不完整的 html 文件数据 如 <p></p> 配置到此项,会自动将不完整的 html 文件数据 添加 <html><head> .. </head> <body> 原来的内容 </body></html>,并适配移动端
    this.htmlBlockData,
    //输出 Log 日志功能
    this.isLog,
    // 为 Html 页面中所有的图片添加 点击事件 并通过回调 通知 Flutter 页面
    // 只有使用 htmlBlockData 属性加载的页面才会有此效果
    this.htmlImageIsClick = false,
    // Html 页面中图片点击回调
    this.imageCallBack,
    // Html 页面中所有的消息回调
    this.callback,
  });

1.5 原生回调 Flutter 的 callback 以及 Html 页面中 图片 点击回调说明
  /**
   * code 原生 Android iOS 回调 Flutter 的消息类型标识
   * message 消息类型日志
   * content 回调的基本数据
   */
  Function(int code, String message, dynamic content) callback;

详细说明


  //当前点击的图片 URL
  String imageUrl = null;
  //是否显示浮动按钮
  bool isShowFloat = false;
  /**
   * code 当前点击图片的 位置
   * url 当前点击图片对应的 链接
   * images 当前 Html 页面中所有的图片集合
   */
  void imageCallBack(int code, String url, List<String> images) {
    imageUrl = url;
    setState(() {});
  }

  void callBack(int code, String msg, content) {
    String call = "回调 code:" +
        code.toString() +
        " msg:" +
        msg.toString() +
        " content:" +
        content.toString();
    if (code == 201) {
      //加载页面完成后 对页面重新测量的回调
      //这里没有使用到
      //当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度
      //设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBox
      webViewHeight = content;
    } else if (code == 202) {
      // Html 页面中 Js 的回调
      // Html 页面中的开发需要使用 Js 调用  【 Android 中 使用 controll.otherJsMethodCall( json )】 【iOS中 直接调用 otherJsMethodCall( json ) 】
      // 在 Flutter 中解析 json 然后加载不同的功能
      String jsJson = content;
    } else if (code == 203) {
      // 为 Html 页面中的图片添加 点击事件后,点击图片会回调此方法
      // content 为当前点击图片的 地址
      // 实现更多功能 比如 一个 Html 页面中 有5张图片,点击放大查看并可右右滑动
      // 这个功能可以在 imageCallBack 回调中处理

    } else if (code == 301) {
      //当 WebView 滑动到顶部的回调
    } else if (code == 302) {
      //当 WebView 开始向下滑动时的回调
      //隐藏按钮
      isShowFloat = true;
    } else if (code == 303) {
      //当 WebView 开始向上滑动时的回调
      //显示按钮
      isShowFloat = false;
    } else if (code == 304) {
      //当 WebView 滑动到底部的回调
    } else if (code == 401) {
      //当 WebView 开始加载的回调
    } else if (code == 402) {
      //当 WebView 加载完成的回调
    } else if (code == 403) {
      // WebView 中 Html中日志输出回调
    } else if (code == 401) {
      // WebView 加载 Html 页面出错的回调
    } else if (code == 501) {
      // 当 Html 页面中有 Alert 弹框弹出时 回调消息

    } else if (code == 1000) {
      // 操作失败 例如 空指针异常 等等
    } else {
      //其他回调
    }
    setState(() {
      message = call;
    });
  }
1.6 Flutter 刷新页面
//调用此方法 便可刷新(重新加载页面)
webViewWidget.refresh();
1.7 Flutter 调用 JS 方法
//testAlert() 就是我们要调用的 Html 页面中 JS的方法
// testAlert() 可以自定义与 Html 中的 JS 开发约定
webViewWidget.loadJsMethod("testAlert()");

2 Flutter 加载页面

2.1 通过 url 加载 Html 页面

在这里插入图片描述

import 'package:flutter/material.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';

/**
 *  加载地址 
 *  通过 url 加载了一个 Html页面 是取常用的方法
 */
class DefaultLoadingWebViewUrlPage extends StatefulWidget {
  @override
  MaxUrlState createState() => MaxUrlState();
}

class MaxUrlState extends State<DefaultLoadingWebViewUrlPage> {

  //要显示的页面内容
  Widget childWidget;
  //加载Html的View
  FaiWebViewWidget webViewWidget;
  //原生 发送给 Flutter 的消息
  String message = "--";
  // 页面
  String htmlUrl = "https://blog.csdn.net/zl18603543572";

  @override
  void initState() {
    super.initState();
    //使用插件 FaiWebViewWidget
    webViewWidget = FaiWebViewWidget(
      //webview 加载网页链接
      url: htmlUrl,
      //webview 加载信息回调
      callback: callBack,
      //输出日志
      isLog: true,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          leading: IconButton(
            onPressed: () {
              Navigator.pop(context);
            },
            icon: Icon(Icons.arrow_back_ios),
          ),
          title: Container(
            padding: EdgeInsets.only(left: 10, right: 10),
            height: 28,
            alignment: Alignment(0, 0),
            color: Color.fromARGB(90, 0, 0, 0),
            child: Text(
              message,
              style: TextStyle(color: Colors.white, fontSize: 12),
            ),
          ),
        ),
        body: webViewWidget,
      );

  }

  void callBack(int code, String msg, content) {
    //加载页面完成后 对页面重新测量的回调
    //这里没有使用到
    //当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度
    //设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBox
    if (code == 201) {
      //页面加载完成后 测量的 WebView 高度
      int webViewHeight = content;
      print("webViewHeight " + webViewHeight.toString());
    } else {
      //其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }
}

2.2 加载本地资源目录assets下的html

** 通过 Html Data 加载 Html 页面 **

2.2.1 加载模拟的html数据

在这里插入图片描述

import 'package:flutter/material.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';

/**
 *  通过 htmlBlockData 加载 Html 数据 并添加移动适配
 */
class DefaultHtmlBlockDataPage2 extends StatefulWidget {
  @override
  DefaultHtmlBlockDataPageState createState() =>
      DefaultHtmlBlockDataPageState();
}

class DefaultHtmlBlockDataPageState extends State<DefaultHtmlBlockDataPage2> {


  FaiWebViewWidget webViewWidget;
  //原生 发送给 Flutter 的消息
  String message = "--";
  double webViewHeight = 100;

  //要显示的页面内容
  Widget childWidget;
  String htmlBlockData = "<!DOCTYPE html><html> <head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1\"> </head> <body><p><br/></p><p>生物真题&nbsp;</p><p><img src=\"https://images.gitee.com/uploads/images/2020/0602/203000_9fa3ddaa_568055.png\" title=\"\" alt=\"\"/></p><p><img src=\"https://images.gitee.com/uploads/images/2020/0602/203000_9fa3ddaa_568055.png\" title=\"\" alt=\"\"/></p><p><br/></p><p><br/></p><p><br/></p></body></html>";

  @override
  void initState() {
    super.initState();

    //使用插件 FaiWebViewWidget
    webViewWidget = FaiWebViewWidget(
      //webview 加载网页链接
      htmlBlockData: htmlBlockData,
      //webview 加载信息回调
      callback: callBack,
      //输出日志
      isLog: true,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () {
            Navigator.pop(context);
          },
          icon: Icon(Icons.arrow_back_ios),
        ),
        title: Container(
          padding: EdgeInsets.only(left: 10, right: 10),
          height: 28,
          alignment: Alignment(0, 0),
          color: Color.fromARGB(90, 0, 0, 0),
          child: Text(
            message,
            style: TextStyle(color: Colors.white, fontSize: 12),
          ),
        ),
      ),
      body: Container(child: webViewWidget,),
    );
  }

  callBack(int code, String msg, content) {
    //加载页面完成后 对页面重新测量的回调
    //这里没有使用到
    //当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度
    //设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBox
    if (code == 201) {
      webViewHeight = content;
      print("webViewHeight " + webViewHeight.toString());
    } else {
      //其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }
}


2.2.2 加载资源目录下assets的html数据

第一步是配制资源目录下assets的html的依赖,在项目的pubspec.yaml中添加依赖

assets:
  - assets/html/

第二步是加载对应的html静态文件然后渲染出来

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';

/**
 *  通过 htmlBlockData 加载 Html 数据 并添加移动适配
 */
class DefaultHtmlBlockDataPage2 extends StatefulWidget {
  @override
  DefaultHtmlBlockDataPageState createState() =>
      DefaultHtmlBlockDataPageState();
}

class DefaultHtmlBlockDataPageState extends State<DefaultHtmlBlockDataPage2> {
  //原生 发送给 Flutter 的消息
  String message = "--";
  double webViewHeight = 100;

  //要显示的页面内容
  Widget childWidget;
  String htmlBlockData =
      "<!DOCTYPE html><html> <head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1\"> </head> <body><p>加载中</p></body></html>";

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () {
            Navigator.pop(context);
          },
          icon: Icon(Icons.arrow_back_ios),
        ),
        title: Container(
          padding: EdgeInsets.only(left: 10, right: 10),
          height: 28,
          alignment: Alignment(0, 0),
          color: Color.fromARGB(90, 0, 0, 0),
          child: Text(
            message,
            style: TextStyle(color: Colors.white, fontSize: 12),
          ),
        ),
      ),
      body: Container(
        ///使用异步来加载
        child: FutureBuilder<String>(
          ///异步加载数据
          future: loadingLocalAsset(),
          ///构建
          builder: (BuildContext context, var snap) {
            String htmlData = snap.data;
            //使用插件 FaiWebViewWidget
            if (htmlData == null) {
              return CircularProgressIndicator();
            }
            return FaiWebViewWidget(
              //webview 加载本地html数据
              htmlBlockData: htmlData,
              //webview 加载信息回调
              callback: callBack,
              //输出日志
              isLog: true,
            );
          },
        ),
      ),
    );
  }

  callBack(int code, String msg, content) {
    //加载页面完成后 对页面重新测量的回调
    //这里没有使用到
    //当FaiWebViewWidget 被嵌套在可滑动的 widget 中,必须设置 FaiWebViewWidget 的高度
    //设置 FaiWebViewWidget 的高度 可通过在 FaiWebViewWidget 嵌套一层 Container 或者 SizeBox
    if (code == 201) {
      webViewHeight = content;
      print("webViewHeight " + webViewHeight.toString());
    } else {
      //其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }

  Future<String> loadingLocalAsset() async {
    String htmlData = await rootBundle.loadString('assets/html/test.html');
    print("加载数据完成 $htmlData");
    return htmlData;
  }
}


2.3 加载混合页面

也就是说 一个页面中,一部分是 Flutter Widget 一部分是 webview 加载。

在这里插入图片描述

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter_fai_webview/flutter_fai_webview.dart';

/**
 *   混合页面加载
 *
 */
class DefaultHexRefreshPage extends StatefulWidget {
  @override
  MaxUrlHexRefreshState createState() => MaxUrlHexRefreshState();
}

class MaxUrlHexRefreshState extends State<DefaultHexRefreshPage> {
  FaiWebViewWidget webViewWidget;

  //原生 发送给 Flutter 的消息
  String message = "--";
  String htmlUrl = "https://blog.csdn.net/zl18603543572";
  double webViewHeight = 1;

  @override
  void initState() {
    super.initState();

    //使用插件 FaiWebViewWidget
    webViewWidget = FaiWebViewWidget(
      //webview 加载网页链接
      url: htmlUrl,
      //webview 加载信息回调
      callback: callBack,
      //输出日志
      isLog: true,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () {
            Navigator.pop(context);
          },
          icon: Icon(Icons.arrow_back_ios),
        ),
        title: Container(
          padding: EdgeInsets.only(left: 10, right: 10),
          height: 28,
          alignment: Alignment(0, 0),
          color: Color.fromARGB(90, 0, 0, 0),
          child: Text(
            message,
            style: TextStyle(color: Colors.white, fontSize: 12),
          ),
        ),
      ),
      body: buildRefreshHexWidget(),
    );
  }

  /**
   * 需要注意的是 
   * RefreshIndicator 会覆盖 WebView 的滑动事件
   * 所有关于 监听 WebView 的滑动监听将会失效
   */
  Widget buildRefreshHexWidget() {
    
    return RefreshIndicator(
      //下拉刷新触发方法
      onRefresh: _onRefresh,
      //设置webViewWidget
      child: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Container(
              color: Colors.grey,
              height: 220.0,
              child: Column(mainAxisSize: MainAxisSize.min,children: <Widget>[
                  Center(child: Text("这里是 Flutter widget  "),)
              ],),
            ),
            Align(
              alignment: Alignment(0, 0),
              child: Text("以下是 Html 页面 "),
            ),
            Container(
              color: Colors.redAccent,
              height: 1.0,
            ),
            Container(
              height: webViewHeight,
              child: webViewWidget,
            )
          ],
        ),
      ),
    );
  }

  Future<Null> _onRefresh() async {
    return await Future.delayed(Duration(seconds: 1), () {
      print('refresh');
      webViewWidget.refresh();
    });
  }

  callBack(int code, String msg, content) {
    //加载页面完成后 对页面重新测量的回调
    if (code == 201) {
      //更新高度
      webViewHeight = content;
      print("webViewHeight " + content.toString());
    } else {
      //其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }
}

0.0.2 #

  • 添加加载资源目录assets下静态html文件

0.0.1 #

  • TODO: Describe initial release.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'exampl_default_url_max.dart';
import 'exampl_index.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("FaiWebViewWidget 加载 html"),
        ),
        body: IndexPage(),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flutter_fai_webview: ^0.0.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_fai_webview/flutter_fai_webview.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
22
Health:
Code health derived from static analysis. [more]
97
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
50
Overall:
Weighted score of the above. [more]
50
Learn more about scoring.

We analyzed this package on Jul 9, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.14
  • Flutter: 1.17.5

Analysis suggestions

Package does not support Flutter platform linux

Because:

  • package:flutter_fai_webview/flutter_fai_webview.dart that declares support for platforms: android, ios

Package does not support Flutter platform macos

Because:

  • package:flutter_fai_webview/flutter_fai_webview.dart that declares support for platforms: android, ios

Package does not support Flutter platform web

Because:

  • package:flutter_fai_webview/flutter_fai_webview.dart that declares support for platforms: android, ios

Package does not support Flutter platform windows

Because:

  • package:flutter_fai_webview/flutter_fai_webview.dart that declares support for platforms: android, ios

Package not compatible with SDK dart

Because:

  • flutter_fai_webview that is a package requiring null.

Health suggestions

Fix lib/src/native_webview.dart. (-2.96 points)

Analysis of lib/src/native_webview.dart reported 6 hints, including:

line 10 col 7: This class (or a class that this class inherits from) is marked as '@immutable', but one or more of its instance fields aren't final: FaiWebViewWidget.url, FaiWebViewWidget.htmlData, FaiWebViewWidget.htmlBlockData, FaiWebViewWidget.isLog, FaiWebViewWidget.htmlImageIsClick, FaiWebViewWidget.callback, FaiWebViewWidget.imageCallBack, FaiWebViewWidget.viewState

line 46 col 3: Prefer using /// for doc comments.

line 53 col 3: Prefer using /// for doc comments.

line 190 col 3: Prefer using /// for doc comments.

line 207 col 35: This function has a return type of 'Future

Format lib/src/native_webview_event.dart.

Run flutter format to format lib/src/native_webview_event.dart.

Maintenance issues and suggestions

The description contains too many non-ASCII characters. (-20 points)

The site uses English as its primary language. The value of the description field in your package's pubspec.yaml field should primarily contain characters used in English.

The package description is too short. (-20 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.12 1.14.13
meta 1.1.8 1.2.2
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8 2.1.0-nullsafety
Dev dependencies
flutter_test