Flutter网页视图展示插件flutter_fai_webview的使用

Flutter网页视图展示插件flutter_fai_webview的使用

Flutter 加载 Html Flutter与JS的双向调用

Flutter是谷歌推出的最新的移动开发框架。

1. 基本使用说明

1.1 Flutter 项目中 pubspec.yaml 文件中 配置插件

dependencies:
  flutter_fai_webview: ^1.0.0

1.2 在使用到 WebView 页面中

引入头文件:

import 'package:flutter_fai_webview/flutter_fai_webview.dart';

1.3 通过url加载网页

如这里使用到的地址:

String htmlUrl = "https://blog.csdn.net/zl18603543572";

然后使用 FaiWebViewWidget 来加载显示这个H5链接,代码如下:

///通过url加载页面
FaiWebViewWidget buildFaiWebViewWidget() {
  return FaiWebViewWidget(
    //webview 加载网页链接
    url: htmlUrl,
    //webview 加载信息回调
    callback: callBack,
    //输出日志
    isLog: true,
  );
}

其中 callBack 是一个回调,如 webview 的加载完成、向上滑动、向下滑动等等,代码如下:

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

运行效果如下图所示:

在这里插入图片描述

完整代码在这里:

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

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

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

class _MyAppState extends State<MyApp> {
  String htmlUrl = "https://blog.csdn.net/zl18603543572";
  double webViewHeight = 1;
  
  void callBack(int ?code, String ?msg, content) {
    // 加载页面完成后 对页面重新测量的回调
    if (code == 201) {
      // 更新高度
      webViewHeight = content;
      print("webViewHeight " + content.toString());
    } else {
      // 其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }

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

  FaiWebViewWidget buildFaiWebViewWidget() {
    return FaiWebViewWidget(
      url: htmlUrl,
      callback: callBack,
      isLog: true,
    );
  }
}

1.4 关于回调中的 code 取值说明如下

code值 简述
201 测量webview 成功
202 JS调用
203 图片点击回调
301 滑动到顶部
302 向下滑动
303 向上滑动
304 滑动到底部
401 webview 开始加载
402 webview 加载完成
403 webview html中日志输出
404 webview 加载出错
501 webview 弹框回调
1000 操作失败

加载Html的过程中会实时回调Flutter,详细说明如下:

// 当前点击的图片 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) {
    // 加载页面完成后 对页面重新测量的回调
    webViewHeight = content;
  } else if (code == 202) {
    // Html 页面中 Js 的回调
    String jsJson = content;
  } else if (code == 203) {
    // 为 Html 页面中的图片添加 点击事件后,点击图片会回调此方法
    String jsJson = content;
  } 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 == 404) {
    // WebView 加载 Html 页面出错的回调
  } else if (code == 501) {
    // 当 Html 页面中有 Alert 弹框弹出时 回调消息
  } else if (code == 1000) {
    // 操作失败 例如 空指针异常 等等
  } else {
    // 其他回调
  }
  setState(() {
    message = call;
  });
}

2. Flutter 加载页面

2.1 通过 url 加载 Html 页面

在上述1.3 通过url加载网页已进行过描述。

2.2 通过 Html Data 加载 String类型的Html 页面

加载String类型的Html页面,一般先是将String类型的Html代码加载到内容中,如通过网络请求接口获取的,或者是在页面中定义好的代码如下:

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>";

或者是放在assets目录的静态Html,那么就需要先读取静态资源目录下的Html文件,代码如下:

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

当然你需要配制好目录依赖,如我这里的example中的html文件配置代码如下:

assets:
  - assets/html/

对应的文件目录如下所示:

在这里插入图片描述

然后就是使用 FaiWebViewWidget 来渲染Html页面了,如果是直接显示已加载好的String类型的Html,那么直接配置 FaiWebViewWidget 中的 htmlBlockData 就可以,如果是使用异步加载assets目录下的静态Html,那么可以结合 FutureBuilder 组件来实现加载,代码如下:

///异步加载静态资源目录下的Html
FutureBuilder<String> buildFutureBuilder() {
  return FutureBuilder<String>(
    ///异步加载数据
    future: loadingLocalAsset(),
    ///构建
    builder: (BuildContext context, var snap) {
      ///加载完成的html数据
      String htmlData = snap.data;
      //使用插件 FaiWebViewWidget
      if (htmlData == null) {
        return CircularProgressIndicator();
      }
      ///通过配置 htmlBlockData 来渲染
      return FaiWebViewWidget(
        //webview 加载本地html数据
        htmlBlockData: htmlData,
        //webview 加载信息回调
        callback: callBack,
        //输出日志
        isLog: true,
      );
    },
  );
}

完整的代码在这里:

import 'package:flutter/material.dart';
import 'package:flutter_fai_webview/flutter_fai_webview.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: buildFutureBuilder(),
      ),
    );
  }

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

  FutureBuilder<String> buildFutureBuilder() {
    return FutureBuilder<String>(
      future: loadingLocalAsset(),
      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
        if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
          return FaiWebViewWidget(
            htmlBlockData: snapshot.data!,
            callback: callBack,
            isLog: true,
          );
        } else if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else {
          return Text("加载失败");
        }
      },
    );
  }

  void callBack(int ?code, String ?msg, content) {
    if (code == 201) {
      // 加载页面完成后 对页面重新测量的回调
      webViewHeight = content;
      print("webViewHeight " + content.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<DefaultHexRefreshPage> {
  String message = "--";
  String htmlUrl = "https://blog.csdn.net/zl18603543572";
  double webViewHeight = 1;

  @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: buildRefreshHexWidget(),
    );
  }

  Widget buildRefreshHexWidget() {
    return RefreshIndicator(
      onRefresh: _onRefresh,
      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: FaiWebViewWidget(
                url: htmlUrl,
                callback: callBack,
                isLog: true,
              ),
            ),
          ],
        ),
      ),
    );
  }

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

  void callBack(int ?code, String ?msg, content) {
    if (code == 201) {
      webViewHeight = content;
      print("webViewHeight " + content.toString());
    } else {
      // 其他回调
    }
    setState(() {
      message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
    });
  }
}

3. Flutter与Html中JS的双向互调

3.1 Flutter中调用JS中的方法

Flutter中调用JS方法,需要使用到 FaiWebViewController,代码如下:

///webView控制器
FaiWebViewController faiWebViewController = new FaiWebViewController();
///构建webview组件
FaiWebViewWidget buildFaiWebViewWidget(String htmlData) {
  return FaiWebViewWidget(
    controller: faiWebViewController,
    //webview 加载本地html数据
    htmlBlockData: htmlData,
    //webview 加载信息回调
    callback: callBack,
    //输出日志
    isLog: true,
  );
}

然后在点击按钮的时候调用HTML中JS的方法,代码如下:

RaisedButton(
  child: Text("Flutter调用JS方法"),
  onPressed: () {
    ///向JS方法中传的参数
    Map<String, dynamic> map = new Map();
    map["test"] = "这是Flutter中传的参数";

    ///参数一为调用JS的方法名称
    ///参数二为向JS中传递的参数
    faiWebViewController.toJsFunction(
      jsMethodName: "testAlert2",
      parameterMap: map,
    );
  },
)

这里使用到的 testAlert2 就是JS中声明的方法。

3.2 JS中调用Flutter的方法

在上述描述到的Html文件中,声明了一个按钮,然后在点击按钮时调用 toFlutter 方法,然后在Flutter中对应的 FaiWebViewWidget 设置的 callback 监听中会收到这个回调,处理代码如下:

///FaiWebViewWidget 的回调处理
void callBack(int ?code, String ?msg, content) {
  if (code == 202) {
    /// json.encode(mapData); //Map转化JSON字符串
    /// json.decode(strData); //JSON 字符串转化为Map类型
    Map<String, dynamic> map = json.decode(content);

    String name = map["name"];
    int age = map["age"];
    print('这里是Js调用到Flutter中的数据 name $name  age $age');
  } else {
    // 其他回调
  }
  setState(() {
    message = "回调:code[" + code.toString() + "]; msg[" + msg.toString() + "]";
  });
}

然后在这里接收到JS中的调用以及参数后,就可以在Flutter中做任何想要的操作。

4. Flutter操作Html的其他方法简述

4.1 刷新页面加载

通过 FaiWebViewControllerrefresh 方法就可实现,代码如下:

faiWebViewController.refresh();

4.2 浏览器的后退

///判断是否可退 如果可退
bool back = await _faiWebViewController.canBack();
print("是否可后退 $back");
if (back) {
  /// 如果可退 后退浏览器的历史
  _faiWebViewController.back();
} else {
  ///如果不可就退出当前页面
  Navigator.of(context).pop();
}

4.3 浏览器的前进

///判断是否可前进
bool forword = await _faiWebViewController.canForword();
print("是否可前进$forword");
if (forword) {
  /// 如果可退 后退浏览器的历史
  _faiWebViewController.forword();
} else {}

更多关于Flutter网页视图展示插件flutter_fai_webview的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter网页视图展示插件flutter_fai_webview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_fai_webview插件来展示网页视图的代码示例。请注意,flutter_fai_webview可能不是一个广泛认知的插件,我假设你提到的插件类似于webview_flutter,因为webview_flutter是Flutter官方推荐使用的Web视图插件。如果flutter_fai_webview有特定的API差异,请参考其官方文档进行调整。以下示例基于webview_flutter,你可以根据flutter_fai_webview的文档进行相应修改。

首先,确保你已经在pubspec.yaml文件中添加了依赖项(这里以webview_flutter为例,请替换为flutter_fai_webview的实际依赖项):

dependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^3.0.4  # 请替换为flutter_fai_webview的实际版本

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中创建一个新的Dart文件(例如webview_page.dart),并在其中实现WebView的展示:

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart'; // 请替换为flutter_fai_webview的实际import路径

class WebViewPage extends StatefulWidget {
  final String url;

  WebViewPage({required this.url});

  @override
  _WebViewPageState createState() => _WebViewPageState();
}

class _WebViewPageState extends State<WebViewPage> {
  late WebViewController _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('WebView Demo'),
      ),
      body: WebView(
        initialUrl: widget.url,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webViewController) {
          _controller = webViewController;
        },
        onPageFinished: (String url) {
          print("Page finished loading: $url");
        },
        navigationDelegate: (NavigationRequest request) {
          if (request.url.startsWith("https://your-domain.com/")) {
            return NavigationDecision.navigate;
          } else if (request.isForMainFrame) {
            return NavigationDecision.prevent;
          }
          return NavigationDecision.navigate;
        },
      ),
    );
  }

  // 示例:加载新的URL
  void _loadUrl(String url) async {
    if (await _controller.canGoBack()) {
      _controller.goBack();
    } else {
      _controller.loadUrl(url);
    }
  }
}

在你的主应用程序文件(例如main.dart)中,导航到这个新创建的WebView页面:

import 'package:flutter/material.dart';
import 'webview_page.dart'; // 导入你创建的WebView页面

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter WebView Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter WebView Demo Home'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => WebViewPage(url: 'https://www.example.com')),
            );
          },
          child: Text('Open WebView'),
        ),
      ),
    );
  }
}

这个示例展示了如何在Flutter应用中集成并使用WebView来显示一个网页。如果你使用的是flutter_fai_webview,请参考其官方文档来调整import路径和API调用。通常,WebView插件的使用模式大同小异,主要区别在于具体的API细节。

回到顶部