一、FlutterEngineGroup插件介绍

FlutterEngineGroup是OpenHarmony平台上的一个高级组件,它允许开发者在单个应用中管理多个Flutter引擎实例,实现更灵活、更高效的混合开发架构。通过FlutterEngineGroup,开发者可以在不同页面或模块中使用独立的Flutter引擎,实现资源隔离和性能优化。

核心功能特点:

  • 多引擎管理:支持在单个应用中创建和管理多个Flutter引擎实例
  • 资源共享:引擎之间共享资源,减少内存占用
  • 灵活控制:可根据需求动态创建和销毁引擎
  • 隔离性:不同引擎实例之间相互隔离,避免状态污染
  • 高性能:优化的引擎启动和资源管理机制

二、环境搭建

在使用FlutterEngineGroup之前,需要确保已经完成以下环境配置:

  1. DevEco Studio:安装最新版本的DevEco Studio(推荐4.0+)
  2. JDK 17:配置JDK 17环境变量
  3. Flutter SDK:下载并配置OpenHarmony版本的Flutter SDK
  4. 环境变量
    export PUB_HOSTED_URL=https://pub.flutter-io.cn
    export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
    export PATH=/path/to/flutter_flutter/bin:$PATH
    export PATH=/path/to/ohos-sdk/ets/tools:$PATH
    

三、FlutterEngineGroup的引入与配置

由于FlutterEngineGroup是为OpenHarmony定制修改的版本,需要通过AtomGit以Git形式引入:

3.1 添加依赖

在OpenHarmony项目的pubspec.yaml文件中,添加FlutterEngineGroup的Git依赖:

dependencies:
  flutter_engine_group:
    git:
      url: "https://atomgit.com/flutter-openharmony/flutter_engine_group"
      path: "packages/flutter_engine_group/flutter_engine_group"

3.2 安装依赖

执行以下命令安装依赖:

flutter pub get

四、FlutterEngineGroup的使用步骤

4.1 EntryAbility配置

首先,需要将EntryAbility继承自UIAbility,并实现相关接口:

import { AbilityConstant, UIAbility, Want, window } from '@kit.AbilityKit';
import { common } from '@kit.ArkTS';
import { FlutterManager } from '@ohos/flutter_engine_group';
import type { ExclusiveAppComponent } from '@ohos/flutter_engine_group';

export default class EntryAbility extends UIAbility implements ExclusiveAppComponent<UIAbility> {
  detachFromFlutterEngine(): void {
    // 实现detachFromFlutterEngine方法
  }

  getAppComponent(): UIAbility {
    return this;
  }

  static app?: EntryAbility;

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    FlutterManager.getInstance().pushUIAbility(this);
    EntryAbility.app = this;
  }

  onDestroy(): void | Promise<void> {
    FlutterManager.getInstance().popUIAbility(this);
    EntryAbility.app = undefined;
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    FlutterManager.getInstance().pushWindowStage(this, windowStage);
    windowStage.loadContent('pages/MainPage');
  }

  onWindowStageDestroy() {
    FlutterManager.getInstance().popWindowStage(this);
  }
}

4.2 封装FlutterEngine的attach和detach操作

为了更好地管理FlutterEngine的生命周期,建议封装一个EngineBindings类:

import { common } from '@kit.ArkTS';
import { FlutterEngine, FlutterManager, MethodChannel, Options, engines, DartEntrypoint } from '@ohos/flutter_engine_group';
import { Log } from '@ohos.hilog';
import type { EngineBindingsDelegate } from './EngineBindingsDelegate';

export class EngineBindings implements DataModelObserver {
  private engine?: FlutterEngine;
  private channel?: MethodChannel;
  private context: common.Context;
  private delegate: EngineBindingsDelegate;
  private flutterView: FlutterView;

  constructor(context: common.Context, delegate: EngineBindingsDelegate) {
    this.context = context;
    this.delegate = delegate;
    this.flutterView = FlutterManager.getInstance().createFlutterView(context);
  }

  getFlutterViewId() {
    return this.flutterView.getId();
  }

  async attach() {
    if (this.engine) {
      Log.i("Multi->attach", "engine already exists");
      return;
    }
    DataModel.instance.addObserver(this);

    // 按顺序执行以下步骤
    // 1. 检查加载器
    await engines.checkLoader(this.context, []);

    // 2. 创建并运行引擎
    let options: Options = new Options(this.context)
      .setDartEntrypoint(DartEntrypoint.createDefault());
    this.engine = await engines.createAndRunEngineByOptions(options) ?? undefined;

    if (!this.engine) {
      throw new Error("Create engine failed.");
    }

    // 3. 通知引擎应用已恢复
    this.engine.getLifecycleChannel()?.appIsResumed();

    // 4. 附加到Ability
    if (EntryAbility.app) {
      this.engine.getAbilityControlSurface()?.attachToAbility(EntryAbility.app);
    }

    // 5. 将FlutterView附加到引擎
    this.flutterView.attachToFlutterEngine(this.engine);

    // 6. 注册插件
    GeneratedPluginRegistrant.registerWith(this.engine);

    // 7. 设置MethodChannel通信
    this.setupMethodChannel();
  }

  detach() {
    this.flutterView.detachFromFlutterEngine();
    this.engine?.destroy();
    DataModel.instance.removeObserver(this);
    this.channel?.setMethodCallHandler(null);
  }

  private setupMethodChannel() {
    if (!this.engine) return;

    this.channel = new MethodChannel(this.engine, 'flutter_engine_channel');
    this.channel.setMethodCallHandler((call, result) => {
      // 处理Flutter发送的消息
      switch (call.method) {
        case 'getEngineInfo':
          result.success({ 'engineId': this.engine?.getId() });
          break;
        default:
          result.notImplemented();
      }
    });
  }

  // 实现DataModelObserver接口方法
  onDataChange(key: string, value: any): void {
    // 处理数据变化
  }
}

4.3 在页面中使用FlutterEngineGroup

在OpenHarmony页面中,可以通过以下方式使用FlutterEngineGroup:

import { common } from '@kit.ArkTS';
import { Column, Log } from '@ohos.arkui.widget';
import { FlutterPage } from '@ohos/flutter_engine_group';
import { EngineBindings } from '../engine/EngineBindings';
import type { EngineBindingsDelegate } from '../engine/EngineBindingsDelegate';

@Entry()
@Component
struct SingleFlutterPage implements EngineBindingsDelegate {
  @State viewId: string = "";
  private context = getContext(this) as common.UIAbilityContext;
  private engineBindings: EngineBindings = new EngineBindings(this.context, this);

  onNext() {
    router.pushUrl({ "url": "pages/MainPage" });
  }

  aboutToAppear() {
    Log.i("Multi->aboutToAppear", "SingleFlutterPage");
    this.viewId = this.engineBindings.getFlutterViewId();
    Log.i("Multi->aboutToAppear", "SingleFlutterPage, id=" + this.viewId);
    this.engineBindings.attach();
  }

  aboutToDisappear(): void {
    this.engineBindings.detach();
  }

  build() {
    Column() {
      FlutterPage({ viewId: this.viewId, xComponentType: XComponentType.TEXTURE })
        .backgroundColor(Color.Transparent)
        .width('100%')
        .height('100%')
    }
  }
}

4.4 Flutter与OpenHarmony通信

FlutterEngineGroup支持通过MethodChannel实现Flutter与OpenHarmony原生层的双向通信:

在Flutter端发送消息:
import 'package:flutter/services.dart';

class EngineCommunication {
  static const MethodChannel _channel = MethodChannel('flutter_engine_channel');

  // 获取引擎信息
  static Future<Map<String, dynamic>?> getEngineInfo() async {
    try {
      final Map<dynamic, dynamic>? result = await _channel.invokeMethod('getEngineInfo');
      return result?.cast<String, dynamic>();
    } on PlatformException catch (e) {
      print('Failed to get engine info: ${e.message}');
      return null;
    }
  }
}
在OpenHarmony端接收消息:
private setupMethodChannel() {
  if (!this.engine) return;

  this.channel = new MethodChannel(this.engine, 'flutter_engine_channel');
  this.channel.setMethodCallHandler((call, result) => {
    // 处理Flutter发送的消息
    switch (call.method) {
      case 'getEngineInfo':
        result.success({ 'engineId': this.engine?.getId() });
        break;
      case 'showMessage':
        const message = call.arguments['message'];
        this.showToast(message);
        result.success('Message shown');
        break;
      default:
        result.notImplemented();
    }
  });
}

五、完整示例

以下是一个完整的FlutterEngineGroup使用示例,展示了如何在OpenHarmony应用中管理多个Flutter引擎实例:

5.1 EngineBindingsDelegate接口

export interface EngineBindingsDelegate {
  onNext(): void;
}

5.2 DataModel类

export interface DataModelObserver {
  onDataChange(key: string, value: any): void;
}

export class DataModel {
  private static instance: DataModel;
  private observers: DataModelObserver[] = [];
  private data: Map<string, any> = new Map();

  private constructor() {}

  static get instance() {
    if (!DataModel.instance) {
      DataModel.instance = new DataModel();
    }
    return DataModel.instance;
  }

  addObserver(observer: DataModelObserver) {
    if (!this.observers.includes(observer)) {
      this.observers.push(observer);
    }
  }

  removeObserver(observer: DataModelObserver) {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
    }
  }

  setData(key: string, value: any) {
    this.data.set(key, value);
    this.notifyObservers(key, value);
  }

  getData(key: string): any {
    return this.data.get(key);
  }

  private notifyObservers(key: string, value: any) {
    this.observers.forEach(observer => {
      observer.onDataChange(key, value);
    });
  }
}

5.3 多引擎管理页面

import { common } from '@kit.ArkTS';
import { Column, Text, Button, Log } from '@ohos.arkui.widget';
import { FlutterPage } from '@ohos/flutter_engine_group';
import { EngineBindings } from '../engine/EngineBindings';
import type { EngineBindingsDelegate } from '../engine/EngineBindingsDelegate';

@Entry()
@Component
struct MultiEnginePage implements EngineBindingsDelegate {
  @State viewId1: string = "";
  @State viewId2: string = "";
  private context = getContext(this) as common.UIAbilityContext;
  private engineBindings1: EngineBindings = new EngineBindings(this.context, this);
  private engineBindings2: EngineBindings = new EngineBindings(this.context, this);

  onNext() {
    router.pushUrl({ "url": "pages/MainPage" });
  }

  aboutToAppear() {
    Log.i("Multi->aboutToAppear", "MultiEnginePage");
    this.viewId1 = this.engineBindings1.getFlutterViewId();
    this.viewId2 = this.engineBindings2.getFlutterViewId();

    // 顺序启动两个引擎
    this.startEngine1();
    this.startEngine2();
  }

  aboutToDisappear(): void {
    this.engineBindings1.detach();
    this.engineBindings2.detach();
  }

  private async startEngine1() {
    try {
      await this.engineBindings1.attach();
      Log.i("Multi->startEngine1", "Engine 1 started successfully");
    } catch (e) {
      Log.e("Multi->startEngine1", "Failed to start engine 1: " + e);
    }
  }

  private async startEngine2() {
    try {
      await this.engineBindings2.attach();
      Log.i("Multi->startEngine2", "Engine 2 started successfully");
    } catch (e) {
      Log.e("Multi->startEngine2", "Failed to start engine 2: " + e);
    }
  }

  build() {
    Column() {
      Text('多引擎示例页面').fontSize(24).margin(20)

      Column() {
        Text('Flutter引擎1').fontSize(18).margin(10)
        FlutterPage({ viewId: this.viewId1, xComponentType: XComponentType.TEXTURE })
          .backgroundColor(Color.LightGray)
          .width('100%')
          .height('45%')
      }

      Column() {
        Text('Flutter引擎2').fontSize(18).margin(10)
        FlutterPage({ viewId: this.viewId2, xComponentType: XComponentType.TEXTURE })
          .backgroundColor(Color.LightGray)
          .width('100%')
          .height('45%')
      }
    }
  }
}

六、注意事项

  1. 引擎生命周期管理:确保在页面销毁时正确detach和销毁引擎
  2. 资源消耗:虽然引擎之间共享资源,但仍需注意内存占用
  3. 性能优化:避免频繁创建和销毁引擎,可考虑使用引擎池
  4. 状态管理:不同引擎实例之间状态相互隔离,需要通过其他方式共享数据
  5. 插件兼容性:确保使用的Flutter插件兼容多引擎环境
  6. 错误处理:添加适当的错误处理机制,确保应用稳定性

七、总结

FlutterEngineGroup为OpenHarmony开发者提供了强大的多引擎管理能力,使开发者能够在单个应用中灵活地使用多个Flutter引擎实例。通过本文的介绍,开发者可以快速掌握FlutterEngineGroup的使用方法,包括环境搭建、依赖引入、引擎管理和双向通信等核心功能。

使用FlutterEngineGroup,开发者可以:

  • 实现更灵活的混合开发架构
  • 优化应用性能和资源利用
  • 实现不同模块之间的隔离
  • 充分利用Flutter的跨平台能力
  • 构建更复杂、更高效的应用

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐