likes
comments
collection
share

flutter_inappwebview+getx 实现H5通讯

作者站长头像
站长
· 阅读数 0

前言

在实际的APP开发过程中,我们有很多业务都是使用H5来实现的,使用H5就需要用到webview的功能,这个组件实际上就是在APP中加载H5页面并且完成一些H5页面和APP的交互,我十分推荐使用flutter_inappwebview插件来处理webview的问题,它的功能比较强大,我在这里仅做一点点在getx中使用的介绍

引入

官方地址:pub.dev/packages/fl…

文档地址:inappwebview.dev/docs/webvie…

flutter pub add flutter_inappwebview
// 或者在pubspec.yaml文件中添加
flutter_inappwebview: ^6.0.0

插件使用

1. 创建html文件

我们需要加载的H5页面可以使用任意前端技术栈完成,最终只需要加载一个链接即可,我这里就使用最简单的html单文件添加serverlive完成访问

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>这是webview的内置页面</title>
</head>
<style>
  .box {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
  }

  button {
    width: 100px;
    height: 30px;
    margin: 20px 0;
  }
</style>

<body>
  <div class="box">
    <p>这是H5页面</p>
  </div>
</body>

</html>

建议使用vscode 默认的live-server插件将网页打开,当然直接打开html的地址也没有问题,这里我使用vscode的server打开获得这个地址:[http://127.0.0.1:5500/lib/pages/webview/webview.html](http://127.0.0.1:5500/lib/pages/webview/webview.html),如下所示:

flutter_inappwebview+getx 实现H5通讯

2. Flutter代码集成webview

2.1. 页面渲染view集成

import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:miaohu_course/common/index.dart';
import 'package:miaohu_course/common/widgets/index.dart';
import 'package:url_launcher/url_launcher.dart';

import 'index.dart';

class WebviewPage extends GetView<WebviewController> {
  const WebviewPage({super.key});

  // 主视图
  Widget _buildView() {
    return Stack(
      children: [
        InAppWebView(
          key: controller.webViewKey,
          initialUrlRequest: URLRequest(
              url: WebUri(
                  "http://127.0.0.1:5500/lib/pages/webview/webview.html")),
          onWebViewCreated: (webViewcontroller) async {
            controller.setWebViewController(webViewcontroller);
            print(await webViewcontroller.getUrl());
          },
          onLoadStop: (webViewcontroller, url) {
            controller.onloadFunction(webViewcontroller);
          },
          initialSettings: controller.settings,
          shouldOverrideUrlLoading: (controller, navigationAction) async {
            var uri = navigationAction.request.url!;

            if (![
              "http",
              "https",
              "file",
              "chrome",
              "data",
              "javascript",
              "about"
            ].contains(uri.scheme)) {
              if (await canLaunchUrl(uri)) {
                // Launch the App
                await launchUrl(
                  uri,
                );
                // and cancel the request
                return NavigationActionPolicy.CANCEL;
              }
            }

            return NavigationActionPolicy.ALLOW;
          },
          onProgressChanged: (webviewController, progress) {
            controller.setProgress(progress);
          },
          // initialOptions: ,
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return GetBuilder<WebviewController>(
      init: WebviewController(),
      id: "webview",
      builder: (_) {
        return Scaffold(
            appBar: AppBar(title: const Text("webview")),
            body: SafeArea(
              child: _buildView(),
            ),
            floatingActionButton: <Widget>[
              SizedBox(
                height: 10.h,
              ),
              IconButton(
                      color: Colors.white,
                      onPressed: () {
                        // controller.onclickDownloadFile();
                      },
                      icon: const Icon(Icons.replay_outlined))
                  .backgroundColor(const Color(0xFF9982FF))
                  .clipOval()
            ].toColumn().height(100.h).marginOnly(bottom: 50.h));
      },
    );
  }
}

2.2. webview属性

我们简单看一下webview提供的属性,有以下几点

  1. initialUrlRequest:加载url的请求
  2. initialUserScripts:初始化设置的script
  3. initialOptions:初始化设置的配置
  4. onWebViewCreated:webview创建后的callback回调
  5. onTitleChanged:网页title变换的监听回调
  6. onLoadStart:网页开始加载
  7. shouldOverrideUrlLoading:确定路由是否可以替换,比如可以控制某些连接不允许跳转。
  8. onLoadStop:网页加载结束
  9. onProgressChanged:页面加载进度progress
  10. onLoadError:页面加载失败
  11. onUpdateVisitedHistory;更新访问的历史页面回调
  12. onConsoleMessage:控制台消息,用于输出console.log信息

2.3. APP端向H5传递专属信息

先创建controller

import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:get/get.dart';

class WebviewController extends GetxController {
  WebviewController();
  GlobalKey webViewKey = GlobalKey();
  InAppWebViewController? webViewController;

  InAppWebViewSettings settings = InAppWebViewSettings(
      clearCache: true,
      cacheEnabled: false,
      mediaPlaybackRequiresUserGesture: false,
      allowsInlineMediaPlayback: true,
      iframeAllow: "camera; microphone",
      iframeAllowFullscreen: true);

  int progress = 0;

  _initData() {
    update(["webview"]);
  }

  void onTap() {}

  // @override
  // void onInit() {
  //   super.onInit();
  // }

  @override
  void onReady() {
    super.onReady();
    _initData();
  }

  Future onloadFunction(InAppWebViewController webViewcontroller) async {
    var source = GetPlatform.isAndroid
        ? "window.top.localStorage.setItem('H5_key','111111')"
        : "window.localStorage.setItem('H5_key','1111111')";
    await webViewcontroller.evaluateJavascript(
      source: source,
    );
  }
}

我们在onLoadStop之后给H5页面设置一个缓存数据存储在localStroage中,我们可以在H5中使用Vconsole插件,如下我们便获得了APP传递的数据。

flutter_inappwebview+getx 实现H5通讯

2.4. H5向APP传递数据

2.4.1. 传递数据触发弹窗事件

在H5中向App传递数据主要是我们使用的flutter_inappwebview 在H5的window对象中混入了flutter_inappwebview属性,因此我们可以使用window.flutter_inappwebview.callHandler来向APP传递数据,如下

// 在html标签中添加按钮
<button onclick="click1()">点击触发事件</button>
// 在script标间中触发事件
function click1() {
  window.flutter_inappwebview.callHandler("clickEvent", {
    data: "11111",
  });
}

然后再APP端进行监听

  Future setWebViewController(InAppWebViewController controller) async {
    webViewController = controller;

    controller.addJavaScriptHandler(
        handlerName: "clickEvent",
        callback: (args) async {
          if (args[0]["data"] != null) {
            showToastView(args[0]["data"]);
          }
        });
  }

这样我们就将H5中的 11111 传递给APP 并进行了弹窗展示

flutter_inappwebview+getx 实现H5通讯

2.4.2. 传递事件后获取处理结果

很多时候我们在H5点击触发APP事件之后还需要等待APP返回数据,比如H5的上传下载在APP中需要使用APP的文件操作才能处理,我这里只展示一个简单的事件传递之后获取结果的例子,代码如下

H5代码:

// html标签内的代码
<button onclick="click4()">获取APP数据</button>
// script 标签的代码
function click4() {
  window.flutter_inappwebview.callHandler("getText").then(res => {
    document.getElementById("textButton").innerText = res;
  });
}

APP内部代码

controller.addJavaScriptHandler(
  handlerName: "getText",
  callback: (args) async {
    return "这是APP返回的消息";
});

这样就完成了如下的操作,我们获取了APP 的数据,并且修改了H5的值,这样就完成了H5从APP获取参数的功能

flutter_inappwebview+getx 实现H5通讯

总结

目前使用flutter_inappwebview完成了大部分我们在软件开发中的H5和APP交互的功能,选择这个插件的原因就是因为整体的使用十分的简单,能够更加快速高效的进行开发,但是在我们实际使用下来,插件的坑也有,比如缓存清理不及时或者设置清理之后整个的回收机制比较迷茫,需要以来H5的一部分缓存处理机制来处理,但是总体而言,还是非常好用的。

flutter_inappwebview+getx 实现H5通讯

代码仓库:

当前全部代码已上传git:github.com/lixiaoblack…