欢迎关注微信公众号:FSA全栈行动 👋
一、背景:Android Platform View 的演进历程
如果你在 Flutter 项目里嵌入过 Google Map、WebView 或者原生的视频播放器,那你一定经历过 Platform View 带来的“两难境地”。
长期以来,在 Flutter 中集成原生视图就像是在走钢丝:要么选择 Virtual Display,结果原生键盘和无障碍功能(Accessibility)直接歇菜;要么选择 Hybrid Composition,结果原本流畅的 120Hz 滚动瞬间变成“幻灯片”,帧率跌到谷底。
为了解决这个问题,Flutter 团队折腾了很久。我们先来盘点一下目前已知的几种方案及其优缺点,看完你就能理解为什么 HCPP 这么重要。
1、方案对比
|
方案 |
渲染性能 |
交互体验 |
核心痛点 |
|
|
极高 |
极差 |
无法处理键盘焦点、无法支持无障碍服务 |
|
|
极低 |
满分 |
线程同步开销大,滑动时频繁掉帧 |
|
|
中等 |
中等 |
高速滑动时仍会有微小卡顿或裁剪问题 |
|
|
极高 |
满分 |
需要 |
2、核心差异点
-
Virtual Display:Flutter引擎在后台画一张“隐形画布”(GPU Texture),让原生视图画在上面,再把这张画贴到屏幕上。这方案渲染飞快,但系统压根不知道原生视图的存在,所以键盘、选中文本这些交互全废了。 -
Hybrid Composition:为了解决交互问题,Flutter把原生视图直接塞进Android的视图层级里。虽然体验好,但代价是Flutter的渲染线程和Android的主线程得频繁“碰头”同步,还得不停地在两个线程间拷贝像素数据,性能损耗(Rendering Tax)非常恐怖。 -
TLHC:这是之前的折中方案,用了SurfaceTexture来优化。虽然比HC快一点,但在快速滑动时,依然难逃掉帧和视觉撕裂的坑。
二、HCPP 原理:打破“渲染税”
Flutter 3.44 引入的 Hybrid Composition++ (简称 HCPP),目标就是实现:既要 Virtual Display 的高性能,也要 Hybrid Composition 的完美交互。
它的核心思路是:既然“合并像素”这一步最费劲,那我们干脆不合并了,直接让系统(OS)来搞定。
1、理解 Surface
要理解 HCPP,得先搞清楚 Android 图形系统里的 Surface。
你可以把物理屏幕想象成一个投影台:
-
Flutter引擎在 A 胶片上画 UI,生成一个Surface。 -
原生视图(如
Google Map)在 B 胶片上画内容,也生成一个Surface。
在以前,Flutter 必须要在自己家里把 A 和 B 拼好再交出去。而 HCPP 的做法是:把 A 和 B 叠在一起,直接扔给系统的调度员(SurfaceFlinger),让它在硬件层面完成合成。
2、HCPP 的流水线逻辑
HCPP 的工作流程如下:
-
Impeller渲染:Flutter使用全新的Impeller引擎(基于Vulkan)渲染 UI,生成一个原生的Surface。 -
原生视图渲染:原生组件(如
WebView)在它自己的Surface上绘图。 -
SurfaceControl提交:Flutter不再尝试合并像素,而是把这两个Surface封装成一个SurfaceControl事务。 -
SurfaceFlinger合成:Android系统的SurfaceFlinger接收到指令,直接在硬件层把两个图层叠在一起。
因为不需要在 Flutter 线程和 Android 线程之间反复拷贝 GPU 纹理数据,那种因为线程同步导致的掉帧(Jank)被彻底消除了。
三、实战:如何在你的项目中开启 HCPP
目前 HCPP 还是个“可选配置”特性。想要体验,你的设备必须满足:Android 14 (API 34) 及以上、支持 Vulkan、并且开启了 Impeller 引擎。
1、配置 AndroidManifest.xml
首先,你需要在 android/app/src/main/AndroidManifest.xml 的 application 节点下手动开启这个开关:
<application ...>
<meta-data
android:name="io.flutter.embedding.android.EnableHcpp"
android:value="true" />
<activity ...>
...
</activity>
</application>
2、Dart 层集成
在 Dart 端,你需要使用 PlatformViewLink 配合 AndroidViewSurface 来实现:
class AndroidNativeTextHcpp extends StatelessWidget {
final String text;
const AndroidNativeTextHcpp({super.key, required this.text});
@override
Widget build(BuildContext context) {
const String viewType = 'custom-native-text';
final Map<String, dynamic> creationParams = <String, dynamic>{'text': text};
return PlatformViewLink(
viewType: viewType,
surfaceFactory: (context, controller) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (params) {
return PlatformViewsService.initHybridAndroidView(
id: params.id,
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
onFocus: () => params.onFocusChanged(true),
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
);
}
}
3、原生端实现(Kotlin)
你还需要在 MainActivity.kt 中注册你的原生视图工厂:
class MainActivity : FlutterActivity(){
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine
.platformViewsController
.registry
.registerViewFactory("custom-native-text", NativeTextViewFactory())
}
}
4、运行测试
由于这玩意儿对硬件有要求,建议直接连真机测试,并使用 profile 模式查看性能表现。注意,一定要加上 --enable-hcpp 参数:
flutter run --profile --enable-hcpp
四、最后
HCPP 的设计非常聪明的一点是它的退路机制。如果用户用的是旧设备(比如 Android 12)或者不支持 Vulkan,Flutter 引擎会自动回退到 TLHC 模式。作为开发者,你只需要写一套代码,剩下的性能优化由 Flutter 自动完成。
HCPP 的出现标志着 Flutter 在 Android 平台上的成熟度又上了一个台阶。如果你正在处理复杂的地图、视频或文档查看功能,是时候关注这个新特性了。
如果你觉得这篇内容对你有帮助,欢迎点个赞,关注我获取更多 Flutter 实战干货。
资料参考
-
Flutter 官方文档: Hosting native Android views
-
Android 开发者指南: Surface API Documentation
如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不仅有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~