Flutter加载Html并实现与JS 的双向调用

https://blog.csdn.net/zl18603543572/article/details/96585707

2019-07-20 16:01:01 早起的年轻人 阅读数 2025  收藏 更多

分类专栏: flutter  flutter 从入门 到精通 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 

本文链接:https://blog.csdn.net/zl18603543572/article/details/96585707

更多文章请查看 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 与 原生 Android iOS 双向通信

Flutter通过MethodChannel实现Flutter 与Android iOS 的双向通信

Flutter通过BasicMessageChannel实现Flutter 与Android iOS 的双向通信

Flutter 中内嵌 Android iOS 原生View的编程基础

flutter调用android 原生TextView 

flutter调用ios 原生View 

最重要的一点是 具备 Android iOS 原生语言的开发能力

Flutter_Fai_Webview 插件可实现的功能:

同时适配于 Android Ios 两个平台

通过 url 来加载渲染一个Html 页面

加载 Html 文本数据 如  .... 等

加载 Html 标签数据 如  

...

实现 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

1.3 创建 WebView 组件

    //使用插件 FaiWebViewWidget

    webViewWidget = FaiWebViewWidget(

      //webview 加载网页链接

      url: htmlUrl,

      //webview 加载信息回调

      callback: callBack,

      //输出日志

      isLog: true,

    );

1.4 FaiWebViewWidget 构造参数说明

  FaiWebViewWidget({

    //webview 加载网页链接

    this.url,

    //webview 加载 完整的 html 文件数据  如 ....

    // 不完整的 html 文件数据 如

配置到此项,用此属性来加载,只会渲染

...

中已有的样式 不会适配移动端显示

    this.htmlData,

    //webview 加载完整的 html 文件数据 或者是 不完整的 html 文件数据 如

    //不完整的 html 文件数据 如

配置到此项,会自动将不完整的 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 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 {

  //要显示的页面内容

  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 通过 Html Data 加载 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 {

  FaiWebViewWidget webViewWidget;

  //原生 发送给 Flutter 的消息

  String message = "--";

  double webViewHeight = 100;

  //要显示的页面内容

  Widget childWidget;

  String htmlBlockData = "  


生物真题 

\"\"/

\"\"/




";

  @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.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 {

  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: [

            Container(

              color: Colors.grey,

              height: 220.0,

              child: Column(mainAxisSize: MainAxisSize.min,children: [

                  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 _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() + "]";

    });

  }

}

文章最后发布于: 2019-07-20 16:01:01

你可能感兴趣的:(Flutter加载Html并实现与JS 的双向调用)