去年图片方案可以参考《闲鱼Flutter图片框架架构演进(超详细)》。
Flutter原生方案
在我们新方案开始之前,先简单回忆一下 flutter 原生图片方案。
原生 Image Widget 先通过 ImageProvider 得到 ImageStream,通过监听它的状态,进行各种状态的展示。比如frameBuilder
、loadingBuilder
,最终在图片加载成功后,会 rebuild
出 RawImage
,RawImage
会通过 RenderImage
来绘制,整个绘制的核心是 ImageInfo
中的 ui.Image
。
-
Image:负责图片加载的各个状态的展示,如加载中、失败、加载成功展示图片等。
-
ImageProvider:负责 ImageStream 的获取,比如系统内置的 NetworkImage、AssetImage 等。
-
ImageStream:图片资源加载的对象。
在梳理 flutter 原生图片方案之后,我们发现是不是有机会在某个环节将 flutter 图片和 native 以原生的方式打通?
新的方案
我们巧妙地将 FFi 方案与外接纹理方案组合,解决了一系列业务痛点。
▐ FF1
正如开头说的那些问题,Texture 方案有些做不到的事情,这需要其他方案来互补,这其中核心需要的就是 ui.Image
。我们把 native 内存地址、长度等信息传递给 flutter 侧,用于生成 ui.Image
。
首先 native 侧先获取必要的参数(以 iOS 为例):
_rowBytes = CGImageGetBytesPerRow(cgImage);
CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
CFDataRef rawDataRef = CGDataProviderCopyData(dataProvider);
_handle = (long)CFDataGetBytePtr(rawDataRef);
NSData *data = CFBridgingRelease(rawDataRef);
self.data = data;
_length = data.length;
dart 侧拿到后
@override
FutureOr createImageInfo(Map map) {
Completer completer = Completer();
int handle = map[‘handle’];
int length = map[‘length’];
int width = map[‘width’];
int height = map[‘height’];
int rowBytes = map[‘rowBytes’];
ui.PixelFormat pixelForma