Flutter鸿蒙终端一体化-珠联璧合

3,477 阅读5分钟

架构方案

在上一篇文章中,我们初步了解了在鸿蒙中使用Flutter的可能性和可用性,还没看过的可以参考下面的链接。
Flutter鸿蒙终端一体化-混沌初开
在文章的最后,我们分析了两种混编模式,和Android、iOS类似,分别是源码依赖和产物依赖,在我们的项目中,由于很早之前就开始介入Flutter开发,同时抽象了一套Flutter的轻量级渲染模式,所以,这里我们会使用产物依赖的方式进行混编开发,这也和Native开发保持一致。
Flutter混编方案在起点客户端的实践之路
混编的这两种方式各有利弊,我们先来看下这两种方式的工程结构。

下面是以Flutter工程为主的鸿蒙混编项目结构,和纯Flutter工程结构基本一致,鸿蒙的Native功能,都写在ohos目录下,这就是一个完整的鸿蒙Native工程,可以直接使用DevECO Studio打开。
企业微信截图_5165f8c5-7705-4781-bfe3-041b9d8b9d24.png
在这种方式下,直接执行flutter build hap,将工程编译成鸿蒙的hap包,就可以运行了,这种方式可以参考前面的文章。

下面是以Native工程为主的Flutter Module的工程结构,可以发现,这与我们在Native中看见的内容基本是一样的,还是很好理解的。
企业微信截图_f209ac16-bb0f-46e3-96c6-339ceeb5a0df.png
这种开发模式有什么好处呢?和Native一样,最大的好处就是将Flutter开发和其它开发独立开来,这样双端独立开发互不影响,同时和我们Native的轻量级Flutter渲染架构统一。最后我们选择的架构也就是通过产物集成的方式,下面我们来看下具体的工程模板。

创建module工程

首先,我们通过下面的指令来创建一个支持鸿蒙的Flutter Module工程:

flutter create -t module <project_name>

然后就是执行编译指令,将Flutter Module编译成har,这就类似Android中的aar,这里包含了我们Flutter工程的代码和相关依赖。

flutter build har --local-engine=/Users/xxx/engine/src_release/out/ohos_release_arm64

编译success后,会在下面的目录中生成我们需要的产物:

/Users/xxx/.ohos/flutter_module/build/default/outputs/default/flutter_module.har

我们需要这里的flutter_module.har文件,同时,还需要flutter_embedding.har文件,它的目录如下:

/Users/xxx/.ohos/flutter_module/har/flutter_embedding.har

这个文件是当前flutter_flutter项目的bug,按道理产物只需要flutter_module.har,flutter_embedding.har中都是系统级别的一些产物代码,在当前版本中,未做合并,所以才需要copy出来引入。

产物集成

如果你能顺利完成上面的步骤,那么恭喜你,距离成功就只有一步步步步步步之遥了。

首先,我们创建一个鸿蒙Native工程,你可以使用Dev-ECO Studio来创建,然后直接运行跑起来,这时候,你可以通过这个项目来检查下你的鸿蒙的Native环境,以及验证签名、打包等问题。

一起准备就绪后,在根目录下,创建har文件夹,将前面我们准备好的产物copy到这里,然后,修改entry中的oh-package.json5文件,如下所示。
企业微信截图_995088ac-466d-4289-bc2e-d9bfaf8cc7bf.png
在dependencies中增加两个文件的依赖,并分别命名为flutter_module和flutter_ohos,方便我们后面引用。

编辑之后,右键快捷刷新依赖,执行鸿蒙的run install指令,创建相关的依赖。

打开EntryAbility,我们可以将纯Flutter工程的模板代码copy过来,实际上就和FlutterActivity的使用一模一样,代码如下。

import { FlutterAbility } from '@ohos/flutter_ohos'
import { FlutterPlugin } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
import { GeneratedPluginRegistrant } from '@ohos/flutter_module/src/main/ets/plugins/GeneratedPluginRegistrant';
import List from '@ohos.util.List';
import FlutterEngine from '@ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine';

export default class EntryAbility extends FlutterAbility {
  configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    let plugins = GeneratedPluginRegistrant.getPlugins() as List<FlutterPlugin>;
    plugins.forEach((plugin) => {
      this.addPlugin(plugin);
    })
  }
}

然后在Index中添加FlutterPage,代码如下。

import common from '@ohos.app.ability.common';
import { FlutterPage } from '@ohos/flutter_ohos'

let storage = LocalStorage.getShared()
const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'

@Entry(storage)
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext
  @LocalStorageLink('viewId') viewId: string = "";

  build() {
    Column() {
      FlutterPage({ viewId: this.viewId })
    }
  }

  onBackPress(): boolean {
    this.context.eventHub.emit(EVENT_BACK_PRESS)
    return true
  }
}

可以发现,这里的FlutterPage是完全可以当作一个View来使用的,你甚至可以设置它的尺寸,或者是将它放到一个Native的Tab组件中,相当灵活。

直接运行项目,我们就可以看到熟悉的Flutter计数器页面了。熟悉的感觉又回来了,现在我们可以随心所欲地在Flutter中创建页面,并直接运行在鸿蒙系统中了。

然后等你开开心心的写了一堆Flutter代码,好不容易实现了老板的大饼,满心欢喜的将har重新copy到项目中,结果,它居然还是那个计数器!!!没错,现在IDE的编译系统还存在缓存问题,而且不论你怎么clean都没用,必须要把项目中的build、oh_modules文件夹都删掉,然后重新install才会创建正确的数据,有点小坑,但不大。

本篇就先到这里,这里我们确定了Flutter鸿蒙的混编方案,并探索了har产物集成的一般方法,当然这还只是迈出了一小步,后面我们会逐步实现Channel和双向通信,这才是我们混编的核心。

欢迎大家关注我的公众号——【群英传】,专注于「Android」「Flutter」「Kotlin」
我的语雀知识库——www.yuque.com/xuyisheng