Flutter项目和Flutter Web交互

这几天刚研究用完了UniApp和flutter项目的交互,FlutterWeb已经逐渐稳定下来,想到以后可能会有Flutter项目和Flutter Web项目的交互,所以研究了一下交互方式。

困扰我最大的问题就是,Flutter Web(以下简称web项目)以dart的写法,如何去和Flutter交互,如果依然是前端代码交互也就算了,至少还有个js的样子,可是flutter的web项目和uniapp或者vue完全不同,完全是另一套写法,让人摸不到头脑。说到底就是要解决一个问题,写的方法如何相互调用?

目的

我们要做的事情是什么?

在flutter项目中以嵌入h5的方式打开web项目,并且进行交互。交互具体内容是
点击web项目中的获取token按钮,获取到存放在flutter项目中的token,并且弹窗显示出来。

如果你有类似的需求,希望接下来的内容能让你找到答案

预备工作

看本篇内容需要掌握,flutter项目和js相互调用
可以参考这两篇内容:

https://www.jianshu.com/p/86916cab2cf3

https://www.cnblogs.com/lizhanqi/p/13502763.html

简单来说我们要用的知识点,如何把自己写在web项目的方法,可以在js中调用,就像是flutter项目调用其他js方法那样调用。

import 'dart:js' as js;

void testMethod(){
    // do something
}

// 起到一个类似注册的作用,这样在js的上下文中,
// 就可以使用testMethod方法了,没有这么写的话,
// 直接调用会告知未找到方法。
// 同时也意味着,flutter项目可以使用webview_flutter插件
// 提供的evaluateJavascript方法调用到这个方法了
js.context["testMethod"] = testMethod

开发环境:

flutter 2.2.3

开始

接下来接直接以web项目来说了。

这事涉及到两个项目,我们先来创建好两个项目
我分别创建了
simple_webview_project
simple_web_project

再次明确一下我们要做的事情:
现在我们要达到的目的是在webview项目中以嵌入h5的方式打开web项目,并且进行交互。交互具体内容是
点击web项目中的获取token按钮,获取到存放在webview项目中的token,并且弹窗显示出来。

web项目

首先来看web项目:
和其他web框架一样,首先需要写两个方法,一个是用来调用webview项目的方法, 一个是用来让webview调用的方法。
通过

// 点击获取Token,完成和flutter项目的交互(调用webview项目方法)
void getToken() {
    js.context.callMethod("callFlutterMethod", [
      json.encode({
        "api": "getToken",
        "data": {
          "name": 'getToken',
          "needCallback": true,
          "needToken": true,
          "callbackName": 'getTokenCallback',
          "callbackArgs": 'msg'
        },
      })
    ]);
  }
// 这里是让flutter调用的回调方法。(用来让webview调用的方法)
  void getTokenCallback(msg, token) {
    showDialog(
        context: context,
        builder: (c) {
          return AlertDialog(
            title: Text(token),
          );
        });
  }

需要特别说明的一点是 callFlutterMethod 这个方法是不存在的,是自己写的,写在一个js文件中,然后在web项目中的index.html中引入。方法内容很简单,

// 就是起到一个桥接的作用。我也尝试过,js.context["nativeBridge"].callMethod,但是调用被告知未找到这个对象。
// 因为nativeBridge是flutter项目来管理的,我分析可能是初始化时机的问题,望有懂的大佬,不吝赐教。
function callFlutterMethod(args){
        nativeBridge.postMessage(args)
}

webview 项目

webview项目需要做的事情多一点,主要是要写webview的内容,和交互操作。就像服务端一样,脏活累活都是服务端来干。
如果你之前有过和其他项目交互,那么什么都不用改,直接用就行。这里发一下我用的。

// webview组件
import 'dart:async';
import 'dart:io';

import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'js_flutter.dart';

class WebViewPage extends StatefulWidget {
  static String routeName = "/web_view";
  String url;

  WebViewPage(this.url, {Key? key}) : super(key: key);

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

class _WebViewPageState extends State<WebViewPage> {
  final _webViewController = Completer<WebViewController>();

  @override
  void initState() {
    super.initState();
    // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.close),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
      body: WebView(
        javascriptChannels:
            [NativeBridge(context, _webViewController.future)].toSet(),
        initialUrl: widget.url,
        javascriptMode: JavascriptMode.unrestricted, // 使用JS没限制
        onWebViewCreated: (WebViewController webViewController) {
          // 在WebView创建完成后会产生一个 webViewController
          _webViewController.complete(webViewController);
        },
      ),
    );
  }
}

js交互类

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class NativeBridge implements JavascriptChannel {
  BuildContext context; //来源于当前widget, 便于操作UI
  Future<WebViewController> _controller; //当前webView 的 controller

  NativeBridge(this.context, this._controller);

  // api 与具体函数的映射表,可通过 _functions[key](data) 调用函数
  get _functions => <String, Function>{"getToken": _getToken};
  @override
  String get name =>
      "nativeBridge"; // js 通过 nativeBridge.postMessage(msg); 调用flutter

  // 处理js请求
  @override
  get onMessageReceived => (msg) async {
        // 将收到的string数据转为json
        Map<String, dynamic> message = json.decode(msg.message);
        // 异步是因为有些api函数实现可能为异步,如inputText,等待UI相应
        // 根据 api 字段,调用具体函数
        final data = await _functions[message["api"]](message["data"]);
      };
  //拿token 
  _getToken(data) async {
    handlerCallback(data);
  }

  handlerCallback(data) {
    if (data['needCallback']) {
      var args = data['callbackArgs'];
      if (data['needToken']) {
        args = "'${data['callbackArgs']}','ttttttoken'";
      }
      doCallback(data['callbackName'], args);
    }
  }

  doCallback(name, args) {
    _controller.then((value) => value.evaluateJavascript("$name($args)"));
  }
}

ps:web项目如何部署,这里就不说了,大家各凭本事吧。我这里用的是springboot。
打web包的时候 要指定渲染器,否则的话中文渲染不出来,而且会一直报错。
但是在pc端没问题,原因是pc使用的渲染器是canvaskit本身就可以。
但是手机默认是使用html渲染,为什么中文会报错,还不知道,但是在统一了渲染器之后,中文就可以了,
这是打包命令:
flutter build web --web-renderer canvaskit --release

附上demo链接,github有时候连不上,就放gitee上了。
https://gitee.com/gotosleep7/share.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351