我正在参与「启航计划」

1. FlutterEngine

flutter 作为模块嵌入iOS工程或者android工程。咱们能够参阅下官方文档, FlutterEngine充当 Dart VM 和 Flutter 运行时的主机;FlutterViewController依附于FlutterEngine,给 Flutter 传递 UIKit 的输入事情,并展现被FlutterEngine烘托的每一帧画面。

FlutterEngine文档

创立FlutterEngine:

import UIKit
import Flutter
// Used to connect plugins (only if you have plugins with iOS platform code).
import FlutterPluginRegistrant
@UIApplicationMain
class AppDelegate: FlutterAppDelegate { // More on the FlutterAppDelegate.
  lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Runs the default Dart entrypoint with a default Flutter route.
    flutterEngine.run();
    // Used to connect plugins (only if you have plugins with iOS platform code).
    GeneratedPluginRegistrant.register(with: self.flutterEngine);
    return super.application(application, didFinishLaunchingWithOptions: launchOptions);
  }
}

运用

  let flutterEngine = (UIApplication.shared.delegate as! AppDelegate).flutterEngine
  let flutterViewController =
       FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil)
   present(flutterViewController, animated: true, completion: nil)

2. 加载多个modules

咱们想要加载多个modules的时候,测验运用在podfile文件中

flutter_application_path = '../../mall/mall_flutter_module'
flutter_application_path1 = '../../testModule'
load File.join(flutter_application_path,'.ios','Flutter','podhelper.rb')
load File.join(flutter_application_path1,'.ios','Flutter','podhelper.rb')
target 'xxx' do
install_all_flutter_pods(flutter_application_path)
install_all_flutter_pods(flutter_application_path1)
end

pod install

Flutter中多module集成

报错,已经导入了,之后我测验运用数组的形式inatll,也是无法install,之后进行下图操作

Flutter中多module集成

覆盖了之前的mallModul

  • 手动增加 咱们增加flutter Module的时候也有手动的作用
flutter build ios-framework --output=some/path/MyApp/Flutter/

作用

some/path/MyApp/
└── Flutter/
    ├── Debug/
    │   ├── Flutter.xcframework
    │ ├── App.xcframework
    │ ├── FlutterPluginRegistrant.xcframework (only if you have plugins with iOS platform code)
    │ └── example_plugin.xcframework (each plugin is a separate framework)
    ├── Profile/
    │   ├── Flutter.xcframework
    │   ├── App.xcframework
    │   ├── FlutterPluginRegistrant.xcframework
    │   └── example_plugin.xcframework
    └── Release/
        ├── Flutter.xcframework
        ├── App.xcframework
        ├── FlutterPluginRegistrant.xcframework
        └── example_plugin.xcframework

一直运用相同目录下的Flutter.frameworkApp.framework。混合运用不同目录(例如Profile/Flutter.framework以及Debug/App.framework)将会导致运行失利。

Flutter中多module集成

Xcode工程增加

Flutter中多module集成

不论是运用framework仍是pods导入,实践上是导入上面的2个framework,包含flutter环境和app实践的代码

3. 解决方式

终究,与我的搭档评论了一切这些,他们主张测验将一切模块导入一个类似伞的项目中,然后导入到本机应用程序中。因此,我测验将这两个模块作为第三个模块的包导入,这里称为umbrella

umbrella/pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  login:
    path: ../flutter_modules/login
  register:
    path: ../flutter_modules/register

那行得通,可是您有必要在模块中创立路由umbrella以映射loginregister小部件。

因此需求运用一个胶水项目,来管理这些module

创立一个胶水项目


void main() => runApp(UmbrellaApp(route: window.defaultRouteName));
class UmbrellaApp extends StatelessWidget {
  final String route;
  UmbrellaApp(this.route);
  @override
  Widget build(BuildContext context) {
    switch (route) {
      // UmbrellaModule is class holding static strings.
      case UmbrellaModules.login:  // UmbrellaModules.login = 'login_module'
        return LoginModule();
      case UmbrellaModules.register:
        return RegisterModule();
      default:
        return ErrorRoute();
    }
  }
}

iOS 原生应用:

let flutterViewController = UmbrellaViewController()
flutterViewController.setInitialRoute("oobe_module")
self.present(flutterViewController, animated: false, completion: nil)
// UmbrellaViewController
class UmbrellaViewController: FlutterViewController

4.优化

FlutterEngine上调用run,默认将会调用你的lib/main.dart文件里的main()函数。

你也能够运用另一个进口方法runWithEntrypoint,并运用NSString字符串指定一个不同的 Dart 进口。

运用main()以外的 Dart 进口函数,有必要运用下面的注解,避免被tree-shaken优化掉,而没有编译。

  @pragma('vm:entry-point')
  void myOtherEntrypoint() { ... };

别的,在指定 Dart 函数时,你能够指定特定文件的特定函数。

下面的例子运用lib/other_file.dart文件的myOtherEntrypoint()函数替代lib/main.dartmain()函数:

flutterEngine.run(withEntrypoint: "myOtherEntrypoint", libraryURI: "other_file.dart")

可是报错

**Dart Error: Dart_LookupLibrary: library 'other_file.dart' not found.**

咱们看官方注释

Flutter中多module集成

flutterEngine.run(withEntrypoint: entryPoint, libraryURI: ":package:multiple_flutters_module/other_file.dart")

可是仍是有点问题

2022-09-08 16:20:48.674755+0800 MultipleFluttersIos[17128:42337128] [VERBOSE-2:shell.cc(93)] Dart Error: Dart_LookupLibrary: library ‘:package:multiple_flutters_module/other_file.dart’ not found.

终究咱们运用在main函数中履行不同的进口


void main() => runApp(const MyApp(color: Colors.blue));
@pragma('vm:entry-point')
void topMain() => runApp(const MyApp(color: Colors.green));
@pragma('vm:entry-point')
void bottomMain() => runApp(const MyApp(color: Colors.purple));

在 Android 和 iOS 上增加多个 Flutter 实例的主要 API 是根据新的FlutterEngineGroup类 (Android API,iOS API) 来创立FlutterEngine的,而不是经过以前的FlutterEngine结构。

尽管FlutterEngineAPI 的用法简洁明了,但从FlutterEngineGroup生成的FlutterEngine具有常用同享资源(例如 GPU 上下文、字体衡量和阻隔线程的快照)的功能优势,然后加快首次烘托的速度、下降延迟并下降内存占用。

  • FlutterEngineGroup生成的FlutterEngine能够用来关联 UI 相关的类,例如FlutterActivityFlutterViewController,与通常结构缓存的FlutterEngine类似。

  • 第一个FlutterEngineGroup生成的FlutterEngine不需求持续保活,只要有 1 个可用的FlutterEngine,就能够随时在各个FlutterEngine之间同享资源。

  • 经过FlutterEngineGroup生成的首个FlutterEngine与运用从前的结构方法结构的FlutterEngine有相同的功能特征。

  • 当一切由FlutterEngineGroup结构的FlutterEngine都被毁掉后,下一个创立的FlutterEngine与首个创造的功能特征相同。

  • FlutterEngineGroup本身不需求持续保活。将其毁掉后,已生成的FlutterEngine不受影响,但无法持续在现有同享的基础上创立新引擎。

在delegate

let engines = FlutterEngineGroup(name: "multiple-flutters", project: nil)

初始化

class SingleFlutterViewController: FlutterViewController {
 private var channel: FlutterMethodChannel?
 init(withEntrypoint entryPoint: String?) {
  let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
  let newEngine = appDelegate.engines.makeEngine(withEntrypoint: entryPoint, libraryURI:nil)
  GeneratedPluginRegistrant.register(with: newEngine)
  super.init(engine: newEngine, nibName: nil, bundle: nil)
 }
  }

5 实践中的表现

展现flutter商城,并随意点击

Flutter中多module集成

终究稳定在430左右,最高441

Flutter中多module集成

初始化Engine,不展现flutter商城页面

Flutter中多module集成

首页正常运用后增加内存

Flutter中多module集成

运用FlutterEngineGroup加载测验模块

Flutter中多module集成

运用group 加载模块2

Flutter中多module集成

翻开商城运用独立的Engine

FlutterEngine(name: "io.flutter", project: nil)

Flutter中多module集成

内存运用情况会变大,此刻内存中加载了2个Engine,3个烘托的FlutterViewController

模块全部运用group

Flutter中多module集成

切换模块一

Flutter中多module集成

切换模块三

Flutter中多module集成

没有明显的增加,由于flutter模块共用了一个烘托引擎,减少了内存压力,同时也方便处理以前的模块和新模块的联系。