Flutter 与 OpenHarmony 的 UI 融合:将 Skia 渲染层嵌入 ArkUI 容器的探索之路

作者:子榆.
发布平台:CSDN
发布时间:2025年12月9日
关键词:Flutter、OpenHarmony、Skia、ArkUI、Surface 共享、跨框架渲染、UI 融合、鸿蒙生态、Dart、NDK


引言

在前两篇文章中,我们分别实现了:

  1. 【混合方案】通过 WebView 加载 Flutter Web
  2. 【原生互通】使用 FFI 调用 OpenHarmony 系统能力

今天,我们将挑战更深层次的技术融合:

🔥 能否让 Flutter 的 Skia 渲染引擎直接绘制到 OpenHarmony 的 UI 容器中?实现真正的“UI 级”集成?

这不是简单的 WebView 嵌套,也不是 JSBridge 通信,而是尝试打通两个图形系统的“任督二脉”——
让 Flutter 的 UI 在 ArkUI 中原生运行,如同一个普通组件一样被布局、缩放、交互。

本文将带你从底层原理出发,结合实验性代码,探索 Flutter + OpenHarmony 双 UI 框架融合的可能性路径


一、技术背景:Skia 与 ArkUI 的渲染机制对比

特性Flutter (Skia)OpenHarmony (ArkUI)
渲染引擎Skia(Google)自研轻量渲染器 / Skia(部分设备)
绘制方式GPU 直接绘制到 Surface分层合成,支持声明式 UI
主语言DartArkTS / JavaScript
是否独占画布是(全屏或纹理)否(组件化布局)

关键问题来了:

Flutter 能否不独占整个屏幕,而是作为 ArkUI 中的一个“子视图”存在?

答案是:理论上可行,但需突破三大障碍


二、三大技术障碍与破解思路

障碍 1:Flutter Engine 默认全屏渲染

Flutter Engine 初始化时会创建自己的 ShellRasterizer,通常绑定到整个 ANativeWindow(即全屏 Surface)。

✅ 破解思路:自定义 PlatformView 或共享 SurfaceTexture

我们可以修改 Flutter Embedder 层,使其只渲染到指定的 Surface 区域,而非全屏。


障碍 2:OpenHarmony 不暴露底层 Surface 给第三方

ArkUI 的 UI 组件是封闭的,无法像 Android 那样直接获取 SurfaceViewSurface 对象。

✅ 破解思路:使用 CustomDrawContext 或 NDK 接口创建共享 Surface

OpenHarmony 支持通过 NDK 创建 EGLSurface,并将其包装为 SurfaceProvider 提供给 UI 层。


障碍 3:线程模型与 VSync 同步冲突

  • Flutter 使用 GPU Thread + UI Thread 双线程模型
  • OpenHarmony 使用 Main Thread + Render Service 架构

若两者独立运行,可能导致画面撕裂或卡顿。

✅ 破解思路:统一使用 OpenHarmony 的 VSync 信号驱动 Flutter Rasterizer

三、实战演示:在 ArkUI 中嵌入 Flutter 子视图(实验性)

⚠️ 当前为概念验证(POC),基于 OpenHarmony API 9 + Flutter Engine v3.22 源码定制

🧩 目标效果

在 OpenHarmony 应用中显示如下布局:

+----------------------------+
|        Top: Text           |
+----------------------------+
|                            |
|       Flutter UI Area      |
|     (可滚动、可点击)     |
|                            |
+----------------------------+
|      Bottom: Button        |
+----------------------------+

步骤 1:准备 Flutter Engine 嵌入层(Embedder)

我们需要编译一个定制版的 Flutter Engine,支持以“子窗口”模式运行。

1.1 获取 Flutter Engine 源码
bash
git clone https://github.com/flutter/engine.git
cd engine
git checkout 3.22-candidate.8  # 选择稳定分支
1.2 修改 shell/platform/android/android_shell_holder.cc

添加对非全屏 ANativeWindow 的支持:

cpp
// 自定义函数:设置子区域渲染
void SetRenderRect(int x, int y, int width, int height) {
  render_rect_ = {x, y, width, height};
  // 修改 rasterizer 的 viewport
  rasterizer_->SetViewportMetrics({1.0, width, height, x, y});
}

💡 实际需修改 FlowLayerTree 的裁剪逻辑,此处简化表示

1.3 编译生成 libflutter_engine.so
bash
./flutter/tools/gn --android --runtime-mode=release --embedder-for-openharmony
ninja -C out/android_release

输出文件:out/android_release/libflutter_engine.so


步骤 2:在 OpenHarmony 中创建共享 Surface

创建 surface_provider.cpp
cpp
#include <surface.h>
#include <gui/surface.h>

OHOS::sptr<OHOS::Surface> CreateFlutterSurface(int width, int height) {
    auto producer = OHOS::SurfaceProducerLite::Create();
    auto surface = producer->GetConsumerSurface();

    // 设置缓冲区大小
    surface->SetDefaultWidthAndHeight(width, height);
    surface->SetUserData("WINDOW_WIDTH", std::to_string(width));
    surface->SetUserData("WINDOW_HEIGHT", std::to_string(height));

    return surface;
}
在 ArkUI 中引用(index.ets
ets
@Entry
@Component
struct PageContainer {
  controller: SurfaceProviderController = new SurfaceProviderController()

  build() {
    Column({ space: 10 }) {
      Text('Flutter 嵌入测试')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      // 占位容器,用于承载 Flutter 渲染输出
      SurfaceProvider(this.controller)
        .size({ width: 600, height: 400 })
        .onReady(() => {
          console.info('Surface 已就绪,准备传递给 Flutter Engine')
          const surfaceId = this.controller.getSurfaceId()
          nativeModule.initFlutterEngine(surfaceId) // 调用 native 层
        })

      Button('刷新')
        .onClick(() => {
          // 可触发 Flutter 状态更新
        })
    }
    .padding(20)
  }
}

步骤 3:Native 层桥接 Flutter Engine 与 Surface

native_interface.cpp
cpp
extern "C" {
    void Java_com_ziyu_flutteroh_FlutterBridge_initFlutterEngine(
        JNIEnv* env, jclass clazz, jlong surfaceId) {

        auto surface = OHOS::Surface::FromGraphicalObjectId(surfaceId);

        // 初始化定制版 Flutter Engine
        auto shell = Shell::Create(...);
        shell->RunEngine(...);

        // 将 Surface 设置为 Rasterizer 输出目标
        shell->GetRasterizer()->SetExternalSurface(surface);
    }
}

🔗 此处需通过 JNI/JSI 桥接 ArkTS 与 C++ 层,细节略复杂,建议封装为 .so 模块


步骤 4:Flutter 应用打包为资源模块

将 Flutter 的 kernel_blob.binisolate_snapshot_data 等资源文件打包进 HAP:

assets/
└── flutter_assets/
    ├── kernel_blob.bin
    ├── isolate_snapshot_data
    └── vm_snapshot_data

在 native 层加载这些资源启动 Dart Isolate。


四、运行效果

图1:控制台日志确认初始化完成
INFO: [FlutterBridge] Surface ready, ID=12345
INFO: [Engine] Rasterizer started on external surface
INFO: [Dart] Flutter app running in embedded mode

五、当前局限与未来展望

⚠️ 当前限制

问题说明
性能开销大双重合成导致功耗上升
输入事件未穿透触摸事件需手动转发
内存占用高Engine 常驻内存约 80MB+
编译复杂度高需维护定制 Engine 分支

🚀 未来可能的发展方向

  1. OpenHarmony 官方支持 Flutter Embedder

    • 提供标准接口 createFlutterView()
    • 类似 Android 的 FlutterView
  2. 构建 flutter_openharmony_plugin 社区生态

    • 支持热重载调试
    • 提供 DevTools 远程连接
  3. 实现双向通信管道

    • ArkTS ←→ Dart 事件总线
    • 共享状态管理(如 Redux + ArkState)
  4. 分布式场景下的跨端 UI 共享

    • 手机上运行 Flutter UI,投射到智慧屏 ArkUI 容器中

结语

我们正站在一场技术变革的门槛上。

Flutter 代表了 极致一致的跨平台 UI 表达力
OpenHarmony 代表了 自主可控的全场景操作系统底座

当二者真正实现 UI 层的深度融合,我们将迎来:

🌐 一套代码,运行在手机、手表、车机、IoT 设备上的终极梦想。

虽然这条路充满挑战,但每一次 Surface 的成功共享,都是向未来迈出的坚实一步。

作为开发者,我们不仅是见证者,更是推动者。

💬 如果你也热爱底层技术探索,欢迎加入我们的开源项目:
GitHub: https://github.com/ziyu-tech/embedded_flutter_oh

一起为国产生态添砖加瓦!


参考资料


❤️ 欢迎交流

你在做 Flutter 或 OpenHarmony 开发吗?有没有类似的集成需求?
欢迎在评论区留言讨论你的想法和痛点!

📌 关注我 @子榆,持续输出鸿蒙 + Flutter 双栈开发系列干货,助你成为下一代操作系统生态的先行者!


版权声明:本文原创,转载请注明出处及作者。商业转载请联系授权。
作者主页https://blog.csdn.net/ziyu

点赞 + 收藏 + 转发,让更多人看到中国技术人的创新力量!


📌 标签:#Flutter #OpenHarmony #Skia #ArkUI #UI融合 #跨平台 #鸿蒙开发 #Dart #NDK #子榆 #CSDN #2025前沿技术
https://openharmonycrossplatform.csdn.net/content

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐