flutter windows、macos使用多窗口方法

最近研究flutter在Windows和MacOs操作系统上使用多窗口方法,总结一下开发心得。

众所周知,flutter使用skia将像素点,通过opengl,software,metal等方式渲染到一个窗口上,不像原生开发的可以指定控件添加到具体窗口内。

在flutter pub仓库管理中,看了几个大神写的多窗口方案,无一例外都是通过加载多个flutter engine实例,即一个窗口一个flutter engine实例创建多窗口,

通过底层(c++,swift)使用EventSink实现两个窗口之间通讯,使用这种方式无需改动flutter engine源码,集成多窗口plugin开发即可,

但这个方案同样存在几个问题:

1.加载新窗口时间过长:创建多个窗口时,需要加载一个新的dart vm环境,同时创建一个新的flutter engine对象,创建新的窗口需要等待几秒,如果在7代i5的设备上,

甚至长达10秒左右。

2.窗口之间数据共享复杂:创建新的窗口,主窗口需要将数据传输到新窗口,一旦两个窗口之间数据通讯越来越多,对于后期开发来说,简直是个灾难。

3.增加内存开销:前面说了,每个窗口之间创建需要重新创建一个dart vm,就是要加载一个新的dart源码文件,一个空的flutter demo的源码so文件,

就有10多m,加载到内存中占多100m。

 

针对以上几个问题,我下载了flutter engine的源码进行小修改,使其更加简单开发。

先看看dart中我的创建新窗口思路源码:

class MyWindow {
  final WindowID id;
  final String title;
  late SingletonFlutterWindow subwindow;
  double width;
  double height;
  int x;
  int y;

  late WindowEventListener listener;

  MyWindow(
      {required this.title,
      required this.id,
      this.width = 1280,
      this.height = 720,
      this.x = 0,
      this.y = 0,
      bool bMaximize = false}) {
    MultiWindow.create(
            title: title,
            id: id.index,
            width: width,
            height: height,
            x: x,
            y: y,
            bMaximize: bMaximize)
        .then((value) {
      if (value == true) {
        Timer.run(
          () {
            //要等窗口大小回来
            onCreateWindowSuccess();
          },
        );

        listener.addEventListener();
      }
    });
    listener = WindowEventListener(id.index);
  }

  void onCreateWindowSuccess() {
    subwindow =
        SingletonFlutterWindow(this.id.index, PlatformDispatcher.instance);
    WidgetsFlutterBinding widgetsBinding =
        WidgetsFlutterBinding(bindingWindow: subwindow);
    WindowManager.instance.setCurWidgetBinding(widgetsBinding);
    widgetsBinding.scheduleAttachRootWidget(build());
    widgetsBinding.scheduleWarmUpFrame();
  }

  Widget build() {
    return Container();
  }
}

新窗口继承MyWindow,

import 'package:flutter/material.dart';
import 'package:flutter_app/UI/BaseWindow/MyWindow.dart';

class DemoWindow extends MyWindow {
  String key = "";
  DemoWindow(
      {required String title,
      required WindowID id,
      required double width,
      required double height,
      required int x,
      required int y,
      required bool bMaximize})
      : super(
            title: title,
            id: id,
            width: width,
            height: height,
            x: x,
            y: y,
            bMaximize: bMaximize) {
    key = "chart${id.index}";
  }

  @override
  Widget build() {
    return MaterialApp(home: DemoWindowHome(this));
  }
}

class DemoWindowHome extends StatefulWidget {
  DemoWindow window;

  DemoWindowHome(this.window);

  @override
  State<DemoWindowHome> createState() => _DemoWindowHomeState();
}

class _DemoWindowHomeState extends State<DemoWindowHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.blue,
        body: Center(
            child: Column(
          children: [
            Container(
                width: 200, height: 100, color: Colors.red, child: TextField()),
            MaterialButton(
              onPressed: () {},
              child: Text("sec wind"),
            )
          ],
        )));
  }
}

只要调用

DemoWindow newWindow =  DemoWindow();

这样在一个dart创建中,就能创建一个新的窗口了,并且可以使用现有窗口的环境的数据,而且打开新的窗口的时间更原生几乎一样。

 

我将flutter engine源码下载下来后,按照以下思路进行更改:

1.每个flutter window需要绑定有一个整形id,用于指定窗口事件分发(鼠标,键盘,渲染等)。

2.需要一个WindowManager来管理所有窗口的事件分发。

3.一个窗口一个WidgetBinding对象,管理一个窗口的手势识别,控件布局,焦点管理,键盘通知等。

4.多个窗口同时渲染时,需要将渲染消息入队,通过前后顺序一个个渲染。

 

不过这个方法也有一个弊端:那就是多个窗口打开时不能使用较长或循环动画系统,这是为什么呢?

我们先大致了解一下flutter的渲染原理,当一个stateful widget调用setState时,会标记state为dirty,并且通知c++的光栅线程调用dart的handleBeginFrame来布局绘制,

上面说了要把需要渲染的窗口id入队,进行排队渲染,如果一个窗口里面有个AnimationController动画系统一直循环播放来通知底层渲染,其他窗口就无法将通知渲染事件

入队,这会导致一个窗口画面停止了。

 

如果你的项目动画系统不多,可以使用这个方案实现多窗口。

 

 

我已经把多窗口方案应用到线上项目中,有兴趣的小伙伴可以跳转交易侠官网(www.jiaoyixia.com)下载对应的系统版本来体验。

如果大家有更好的解决方案,也可以留言提出。

转载请注明出处,from博客园HemoJohn,有偿指导加q:980550823

posted on 2023-09-30 19:41  HemJohn  阅读(1890)  评论(0编辑  收藏  举报

导航