鸿蒙系统(HarmonyOS)是华为公司发布的一款走向未来、朝向全情景的分布式系统电脑操作系统。在传统式单机器设备系统软件工作能力的基本上,洪蒙明确提出了根据同一套系统软件工作能力、兼容多种多样终端设备形状的分布式系统核心理念。自 2020 年 9 月 HarmonyOS 2.0 公布至今,华为公司加速了鸿蒙系统规模性落地式的脚步,预估 2021 年末,鸿蒙系统会遮盖包含手机上、平板电脑、智能穿戴设备、智慧屏、车载一体机以内数千万台智能终端。对移动智能终端来讲, 新的系统软件核心理念、新的互动方式,也代表着新的机会 。假如可以运用好洪蒙的开发设计绿色生态以及特点工作能力,能够让运用遮盖大量的互动情景和机器设备种类,进而产生新的突破点。
与遭遇的机会对比,兼容鸿蒙系统产生的挑戰一样极大。当今移动端,虽然鸿蒙系统依然适用安卓系统 APK 安裝及运作,但长期性看来,华为公司必定会抛下 AOSP,逐渐发展趋势出自身的绿色生态,这代表着目前安卓软件在洪蒙机器设备上把会慢慢变为“二等公民”。殊不知,假如在 iOS 及 Android 以外再再次开发设计和维护保养一套洪蒙运用,在现如今业内愈来愈重视开发设计迭代更新高效率的自然环境下,所产生的项目成本也是难以估量的。因而,根据打造出一套适合的跨端架构,以相对性低的成本费移殖运用到洪蒙服务平台,并运用好该系统软件的特点工作能力,就变成了一个十分关键的选择项。
在目前的诸多跨端架构之中,Flutter 因其自3D渲染工作能力产生的跨平台高宽比一致性,在新系统的兼容上拥有 突显的优点。尽管Flutter 官方网 并沒有兼容洪蒙的方案 ,但历经一段时间的探寻和实践活动,美团 MTFlutter 精英团队取得成功完成了 Flutter 针对鸿蒙系统的原生态适用。
这儿还要提早表明一下,由于鸿蒙系统现阶段还处在Beta版本,因此 这套兼容计划方案都还没在具体业务流程中发布,归属于技术性方面较为早期的探寻。下面文中会根据基本原理和一部分完成关键点的详细介绍,共享我们在移殖和开发设计全过程中的一些工作经验。期待能对大伙儿有一定的启迪或是协助。
在兼容逐渐以前,我们要确立好先做什么事儿。先来回望一下 Flutter 的三层构造:
在 Flutter 的架构模式中,顶部为 架构层 ,应用 Dart 語言开发设计,朝向 Flutter 业务流程的开发人员;内层为 模块层 ,应用 C/C 开发设计,完成了 Flutter 的渲染管线和 Dart 运作时等基本工作能力;最下一层为 置入层 ,承担与服务平台有关的工作能力完成。显而易见我们要做的是将置入层移殖到洪蒙上,准确地说,我们要 根据洪蒙原生态出示的服务平台工作能力,再次完成一遍 Flutter 置入层 。
针对 Flutter 置入层的兼容,Flutter 官方网有一份算不上详尽的 手册 ,操作过程起來成本费很高。因为洪蒙的业务流程编程语言依然能用 Java,在许多基本定义上与 Android 也是有共同之处(以下表所显示),我们可以从 Android 的完成下手,进行对洪蒙的移殖。
至始文上述,要进行 Flutter 在新系统上的移殖,大家必须详细完成 Flutter 置入层规定的全部子控制模块,而从工作能力适用视角, 3D渲染 、 互动 及其 别的必需的原生态服务平台工作能力 是确保 Flutter 运用可以运作起來的最基础的因素,必须优先选择适用。下面会先后开展详细介绍。
大家再说回望一下 Flutter 的图象3D渲染步骤。如下图所示,机器设备进行 垂直同步 (VSync)数据信号以后,先历经 UI 进程的渲染管线(Animate/Build/Layout/Paint),再历经 Raster 进程的组成和栅格化,最后根据 OpenGL 或 Vulkan 将图象 上屏 。这一步骤的绝大多数工作中都由架构层和模块层进行,针对洪蒙的兼容,大家关键关心的是与机器设备本身工作能力有关的难题,即:
(1) 怎样监听设备的 VSync 数据信号并通告 Flutter 模块? (2) OpenGL/Vulkan 用以上屏的对话框目标究竟是从哪里而来的呢??
在 Flutter 模块的 Android 完成中,机器设备的 VSync 数据信号根据 Choreographer 开启,它造成及消費步骤如下图所显示:
Flutter 架构申请注册 VSync 回调函数以后,根据 C 侧的 VsyncWaiter 类等候 VSync 数据信号,后面一种根据 JNI 等一系列启用,最后 Java 侧的 VsyncWaiter 类启用 Android SDK 的 Choreographer.postFrameCallback 方式,再根据 JNI 一层层传到 Flutter 模块消費掉此回调函数。Java 侧的 VsyncWaiter 关键编码以下:
@Override
public void asyncWaitForVsync(long cookie) {
Choreographer.getInstance()
.postFrameCallback(
new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
float fps = windowManager.getDefaultDisplay().getRefreshRate();
long refreshPeriodNanos = (long) (1000000000.0 / fps);
FlutterJNI.nativeOnVsync(
frameTimeNanos, frameTimeNanos refreshPeriodNanos, cookie);
}
});
}
在全部步骤中,除开来源于 Android SDK 的 Choreographer 之外,大部分逻辑性基本上都由 C 和 Java 的基本 SDK 完成,能够立即在洪蒙上多路复用,难题是洪蒙现阶段的 API 文本文档中尚沒有对外开放相近 Choreographer 的工作能力。因此 目前我们可以使用洪蒙出示的相近 iOS Grand Central Dispatch 的进程 API,模拟 VSync 的数据信号开启与回调函数:
@Override
public void asyncWaitForVsync(long cookie) {
// 仿真模拟每秒钟 60 帧的显示屏更新间距:向主线任务程推送一个多线程每日任务, 16ms 后启用
applicationContext.getUITaskDispatcher().delayDispatch(() -> {
float fps = 60; // 机器设备更新帧数,HarmonyOS 未曝露获得帧数 API,先写死 60 帧
long refreshPeriodNanos = (long) (1000000000.0 / fps);
long frameTimeNanos = System.nanoTime();
FlutterJNI.nativeOnVsync(frameTimeNanos, frameTimeNanos refreshPeriodNanos, cookie);
}, 16);
};
在这里一部分,大家必须在鸿蒙系统上搭建服务平台器皿,为 Flutter 模块的图型3D渲染出示用以上屏的对话框目标。一样,大家参照 Flutter for Android 的完成,看一下 Android 系统软件是怎么做的:
Flutter 在 Android 上适用 Vulkan 和 OpenGL 二种3D渲染模块,篇数缘故大家只关心 OpenGL。撇开繁杂的申请注册及启用关键点,实质上全部步骤关键干了三件事:
下面大家用洪蒙出示的服务平台工作能力完成这三点。
鸿蒙系统的 UI 架构 出示了许多常见主视图部件(Component) ,例如按键、文本、照片、目录等,但大家必须撇开这种顶层部件,得到立即绘图的工作能力。依靠官方网 多媒体播放器开发设计具体指导 文本文档,能够发觉洪蒙出示了 SurfaceProvider 类,它管理方法的 Surface 目标能够用以视频转码后的展现。而 Flutter 3D渲染与视頻上屏从基本原理上是相近的,因而我们可以使用 SurfaceProvider 完成 Surface 的管理方法和建立:
// 建立一个用以管理方法 Surface 的器皿部件
SurfaceProvider surfaceProvider = new SurfaceProvider(context);
// 申请注册主视图建立回调函数
surfaceProvider.getSurfaceOps().get().addCallback(surfaceCallback);
// ... 在 surfaceCallback 中
@Override
public void surfaceCreated(SurfaceOps surfaceOps) {
Surface surface = surfaceOps.getSurface();
// ...将 surface 根据 JNI 交到 Native 侧
FlutterJNI.onSurfaceCreated(surface);
}
洪蒙现阶段对外开放的 Native API 并不是很多,在官方网文本文档中我们可以较为非常容易地寻找 Native_layer API 。依据文本文档的表明,Native API 中的 NativeLayer 目标恰好相匹配了 Java 侧的 Surface 类,依靠 GetNativeLayer 方式,大家完成了彼此之间的转换:
// platform_view_android_jni_impl.cc
static void SurfaceCreated(JNIEnv* env, jobject jcaller, jlong shell_holder, jobject jsurface) {
fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env);
// 根据洪蒙 Native API 获得当地对话框目标 NativeLayer
auto window = fml::MakeRefCounted<AndroidNativeWindow>(
GetNativeLayer(env, jsurface));
ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window));
}
在 Android 的 AOSP 完成 中,EGLSurface 可根据 EGL 库的 eglCreateWindowSurface 方式从当地对话框目标 ANativeWindow 建立而成。针对洪蒙来讲,尽管大家沒有从公布文本文档寻找相近的表明,可是 洪蒙标准库 默认设置适用了 OpenGL ES,并且洪蒙 SDK 中也附加了 EGL 有关的库及头文件,大家有原因坚信在鸿蒙系统上,EGLSurface 还可以根据此方式过去一步形成的 NativeLayer 转换而成,在以后的认证中大家也确定了这一点:
// window->handle() 即是以前获得的 NativeLayer
EGLSurface surface = eglCreateWindowSurface(
display, config_, reinterpret_cast<EGLNativeWindowType>(window->handle()),
attribs);
//...交到 Flutter 渲染管线
互动工作能力是支撑点 Flutter 运用可以一切正常运作的另一个基础规定。在 Flutter 中,互动包括了各种各样触碰恶性事件、鼠标事件、电脑键盘入录恶性事件的传送及消費。以触碰恶性事件为例子,Flutter 恶性事件传送的全部步骤如下图所显示:
iOS/Android 的原生态器皿根据触碰恶性事件的回调函数 API 接受到恶性事件以后,会将其装包传送至模块层,后面一种将恶性事件传发送给 Flutter 架构层,并进行恶性事件的消費、派发和逻辑性解决。一样,全部步骤的绝大多数工作中早已由 Flutter 统一,我们要做的只是是在原生态器皿上 监视 客户的键入,并 封裝 成特定文件格式交到模块层罢了。
在鸿蒙系统上,我们可以依靠服务平台出示的 多模光纤键入 API ,完成各种类型恶性事件的监视:
针对恶性事件的封裝解决,能够多路复用 Android 现有逻辑性,只必须关心洪蒙与 Android 在事故处理上的对应关系就可以,例如触碰恶性事件的一部分对应关系:
为了更好地确保 Flutter 运用可以一切正常运作,除开最基础的3D渲染和互动外,大家的置入层也要出示资源优化配置、恶性事件循环系统、生命期同歩等服务平台工作能力。针对这种工作能力 Flutter 大多数都是在置入层的公共性一部分有抽象类申明,只必须应用洪蒙 API 再次完成一遍就可以。
例如资源优化配置,模块出示了 AssetResolver 申明,我们可以应用洪蒙 Rawfile API 来完成:
class HAPAssetMapping : public fml::Mapping {
public:
HAPAssetMapping(RawFile* asset) : asset_(asset) {}
~HAPAssetMapping() override { CloseRawFile(asset_); }
size_t GetSize() const override { return GetRawFileSize(asset_); }
const uint8_t* GetMapping() const override {
return reinterpret_cast<const uint8_t*>(GetRawFileBuffer(asset_));
}
private:
RawFile* const asset_;
FML_DISALLOW_COPY_AND_ASSIGN(HAPAssetMapping);
};
针对恶性事件循环系统,模块出示了 MessageLoopImpl 抽象类,我们可以应用洪蒙 Native_EventHandler API 完成:
// runner_ 为洪蒙 EventRunnerNativeImplement 的案例void MessageLoopHarmony::Run() { FML_DCHECK(runner_ == GetEventRunnerNativeObjForThread()); int result = ::EventRunnerRun(runner_); FML_DCHECK(result == 0);}void MessageLoopHarmony::Terminate() { int result = ::EventRunnerStop(runner_); FML_DCHECK(result == 0);}
针对生命期的同歩,洪蒙的 Page Ability 出示了详细的生命期回调函数(如下图所显示),大家只必须在相匹配的机会将情况汇报给模块就可以。
当之上这种工作能力都准备好以后,大家就可以取得成功把 Flutter 运用跑起来了。下列是根据 DevEco Studio 运作官方网 flutter gallery 运用的截屏,截屏中 Flutter 模块早已应用鸿蒙系统的服务平台工作能力开展了重写:
借由洪蒙的多机器设备适用工作能力,此运用乃至可在 TV、车载一体机、腕表、平板电脑等机器设备上运作:
根据所述的搭建和兼容工作中,大家以很小的项目成本完成了 Flutter 在鸿蒙系统上的移殖,根据 Flutter 开发设计的顶层业务流程几乎不做一切改动就可以在鸿蒙系统上原生态运作,为迎来鸿蒙系统事后的规模性营销推广也提早搞好了技术实力。
自然,小故事到这儿并沒有完毕。在最基础的运作和互动工作能力以上,大家更必须关心 Flutter 与洪蒙本身绿色生态的融合:怎样雅致地兼容洪蒙的分布式技术?怎样用 Flutter 完成机器设备中间的相互连接、共享资源?目前的诸多 Flutter 软件怎样运用到鸿蒙系统上?将来 MTFlutter 精英团队将在这种层面做更深层次的探寻,由于处理好这种难题,才算是真实能让运用遮盖客户日常生活的全情景的重要。