Flutter項(xiàng)目和Flutter Web交互

這幾天剛研究用完了UniApp和flutter項(xiàng)目的交互,F(xiàn)lutterWeb已經(jīng)逐漸穩(wěn)定下來,想到以后可能會有Flutter項(xiàng)目和Flutter Web項(xiàng)目的交互,所以研究了一下交互方式。

困擾我最大的問題就是,F(xiàn)lutter Web(以下簡稱web項(xiàng)目)以dart的寫法,如何去和Flutter交互,如果依然是前端代碼交互也就算了,至少還有個(gè)js的樣子,可是flutter的web項(xiàng)目和uniapp或者vue完全不同,完全是另一套寫法,讓人摸不到頭腦。說到底就是要解決一個(gè)問題,寫的方法如何相互調(diào)用?

目的

我們要做的事情是什么?

在flutter項(xiàng)目中以嵌入h5的方式打開web項(xiàng)目,并且進(jìn)行交互。交互具體內(nèi)容是
點(diǎn)擊web項(xiàng)目中的獲取token按鈕,獲取到存放在flutter項(xiàng)目中的token,并且彈窗顯示出來。

如果你有類似的需求,希望接下來的內(nèi)容能讓你找到答案

預(yù)備工作

看本篇內(nèi)容需要掌握,flutter項(xiàng)目和js相互調(diào)用
可以參考這兩篇內(nèi)容:

http://www.itdecent.cn/p/86916cab2cf3

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

簡單來說我們要用的知識點(diǎn),如何把自己寫在web項(xiàng)目的方法,可以在js中調(diào)用,就像是flutter項(xiàng)目調(diào)用其他js方法那樣調(diào)用。

import 'dart:js' as js;

void testMethod(){
    // do something
}

// 起到一個(gè)類似注冊的作用,這樣在js的上下文中,
// 就可以使用testMethod方法了,沒有這么寫的話,
// 直接調(diào)用會告知未找到方法。
// 同時(shí)也意味著,flutter項(xiàng)目可以使用webview_flutter插件
// 提供的evaluateJavascript方法調(diào)用到這個(gè)方法了
js.context["testMethod"] = testMethod

開發(fā)環(huán)境:

flutter 2.2.3

開始

接下來接直接以web項(xiàng)目來說了。

這事涉及到兩個(gè)項(xiàng)目,我們先來創(chuàng)建好兩個(gè)項(xiàng)目
我分別創(chuàng)建了
simple_webview_project
simple_web_project

再次明確一下我們要做的事情:
現(xiàn)在我們要達(dá)到的目的是在webview項(xiàng)目中以嵌入h5的方式打開web項(xiàng)目,并且進(jìn)行交互。交互具體內(nèi)容是
點(diǎn)擊web項(xiàng)目中的獲取token按鈕,獲取到存放在webview項(xiàng)目中的token,并且彈窗顯示出來。

web項(xiàng)目

首先來看web項(xiàng)目:
和其他web框架一樣,首先需要寫兩個(gè)方法,一個(gè)是用來調(diào)用webview項(xiàng)目的方法, 一個(gè)是用來讓webview調(diào)用的方法。
通過

// 點(diǎn)擊獲取Token,完成和flutter項(xiàng)目的交互(調(diào)用webview項(xiàng)目方法)
void getToken() {
    js.context.callMethod("callFlutterMethod", [
      json.encode({
        "api": "getToken",
        "data": {
          "name": 'getToken',
          "needCallback": true,
          "needToken": true,
          "callbackName": 'getTokenCallback',
          "callbackArgs": 'msg'
        },
      })
    ]);
  }
// 這里是讓flutter調(diào)用的回調(diào)方法。(用來讓webview調(diào)用的方法)
  void getTokenCallback(msg, token) {
    showDialog(
        context: context,
        builder: (c) {
          return AlertDialog(
            title: Text(token),
          );
        });
  }

需要特別說明的一點(diǎn)是 callFlutterMethod 這個(gè)方法是不存在的,是自己寫的,寫在一個(gè)js文件中,然后在web項(xiàng)目中的index.html中引入。方法內(nèi)容很簡單,

// 就是起到一個(gè)橋接的作用。我也嘗試過,js.context["nativeBridge"].callMethod,但是調(diào)用被告知未找到這個(gè)對象。
// 因?yàn)閚ativeBridge是flutter項(xiàng)目來管理的,我分析可能是初始化時(shí)機(jī)的問題,望有懂的大佬,不吝賜教。
function callFlutterMethod(args){
        nativeBridge.postMessage(args)
}

webview 項(xiàng)目

webview項(xiàng)目需要做的事情多一點(diǎn),主要是要寫webview的內(nèi)容,和交互操作。就像服務(wù)端一樣,臟活累活都是服務(wù)端來干。
如果你之前有過和其他項(xiàng)目交互,那么什么都不用改,直接用就行。這里發(fā)一下我用的。

// 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創(chuàng)建完成后會產(chǎn)生一個(gè) 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; //來源于當(dāng)前widget, 便于操作UI
  Future<WebViewController> _controller; //當(dāng)前webView 的 controller

  NativeBridge(this.context, this._controller);

  // api 與具體函數(shù)的映射表,可通過 _functions[key](data) 調(diào)用函數(shù)
  get _functions => <String, Function>{"getToken": _getToken};
  @override
  String get name =>
      "nativeBridge"; // js 通過 nativeBridge.postMessage(msg); 調(diào)用flutter

  // 處理js請求
  @override
  get onMessageReceived => (msg) async {
        // 將收到的string數(shù)據(jù)轉(zhuǎn)為json
        Map<String, dynamic> message = json.decode(msg.message);
        // 異步是因?yàn)橛行゛pi函數(shù)實(shí)現(xiàn)可能為異步,如inputText,等待UI相應(yīng)
        // 根據(jù) api 字段,調(diào)用具體函數(shù)
        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項(xiàng)目如何部署,這里就不說了,大家各憑本事吧。我這里用的是springboot。
打web包的時(shí)候 要指定渲染器,否則的話中文渲染不出來,而且會一直報(bào)錯(cuò)。
但是在pc端沒問題,原因是pc使用的渲染器是canvaskit本身就可以。
但是手機(jī)默認(rèn)是使用html渲染,為什么中文會報(bào)錯(cuò),還不知道,但是在統(tǒng)一了渲染器之后,中文就可以了,
這是打包命令:
flutter build web --web-renderer canvaskit --release

附上demo鏈接,github有時(shí)候連不上,就放gitee上了。
https://gitee.com/gotosleep7/share.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容