架构方案
在上一篇文章中,我们初步了解了在鸿蒙中使用Flutter的可能性和可用性,还没看过的可以参考下面的链接。
Flutter鸿蒙终端一体化-混沌初开
在文章的最后,我们分析了两种混编模式,和Android、iOS类似,分别是源码依赖和产物依赖,在我们的项目中,由于很早之前就开始介入Flutter开发,同时抽象了一套Flutter的轻量级渲染模式,所以,这里我们会使用产物依赖的方式进行混编开发,这也和Native开发保持一致。
Flutter混编方案在起点客户端的实践之路
混编的这两种方式各有利弊,我们先来看下这两种方式的工程结构。
下面是以Flutter工程为主的鸿蒙混编项目结构,和纯Flutter工程结构基本一致,鸿蒙的Native功能,都写在ohos目录下,这就是一个完整的鸿蒙Native工程,可以直接使用DevECO Studio打开。
在这种方式下,直接执行flutter build hap,将工程编译成鸿蒙的hap包,就可以运行了,这种方式可以参考前面的文章。
下面是以Native工程为主的Flutter Module的工程结构,可以发现,这与我们在Native中看见的内容基本是一样的,还是很好理解的。
这种开发模式有什么好处呢?和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文件,如下所示。
在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