背景
去年,闲鱼技术团队新一代图片库 PowerImage 在经过一系列灰度、问题修复、代码调优后,已全量稳定应用于闲鱼。相对于上一代 IFImage,PowerImage 经过进一步的演进,适应了更多的业务场景与最新的 flutter 特性,解决了一系列痛点:比如,因为完全抛弃了原生的 ImageCache,在与原生图片混用的场景下,会让一些低频的图片反而占用了缓存;比如,我们在模拟器上无法展示图片;比如我们在相册中,需要在图片库之外再搭建图片通道。
简介
PowerImage 是一个充分利用 native 原生图片库能力、高扩展性的flutter图片库。我们巧妙地将外接纹理与 ffi 方案组合,以更贴近原生的设计,解决了一系列业务痛点。
能力特点
支持加载 ui.Image 能力。在基于外接纹理的方案中,使用方无法拿到真正的 ui.Image 去使用,这导致图片库在这种特殊的使用场景下无能为力。
支持图片预加载能力。正如原生precacheImage一样。这在某些对图片展示速度要求较高的场景下非常有用。
新增纹理缓存,与原生图片库缓存打通!统一图片缓存,避免原生图片混用带来的内存问题。
支持模拟器。在 flutter-1.23.0-18.1.pre之前的版本,模拟器无法展示 Texture Widget。
完善自定义图片类型通道。解决业务自定义图片获取诉求。
完善的异常捕获与收集。
支持动图。(来自淘特的PR)
Flutter 原生方案
在介绍新方案开始之前,先简单回忆一下 flutter 原生图片方案。
![null 58d6abe8cbd71e09f78f22a584828127.png](https://i-blog.csdnimg.cn/blog_migrate/61e86823f51847dcd2ed80ec28fee033.png)
原生 Image Widget 先通过 ImageProvider 得到 ImageStream,通过监听它的状态,进行各种状态的展示。比如frameBuilder
、loadingBuilder
,最终在图片加载成功后,会 rebuild
出 RawImage
,RawImage
会通过 RenderImage
来绘制,整个绘制的核心是 ImageInfo
中的 ui.Image
。
• Image:负责图片加载的各个状态的展示,如加载中、失败、加载成功展示图片等。
• ImageProvider:负责 ImageStream 的获取,比如系统内置的 NetworkImage、AssetImage 等。
• ImageStream:图片资源加载的对象。
在梳理 flutter 原生图片方案之后,我们发现是不是有机会在某个环节将 flutter 图片和 native 以原生的方式打通?
新一代方案
我们巧妙地将 FFi 方案与外接纹理方案组合,解决了一系列业务痛点。
FFI
正如开头说的那些问题,Texture 方案有些做不到的事情,这需要其他方案来互补,这其中核心需要的就是 ui.Image
。我们把 native 内存地址、长度等信息传递给 flutter 侧,用于生成 ui.Image
。
首先 native 侧先获取必要的参数(以 iOS 为例):
_rowBytes = CGImageGetBytesPerRow(cgImage);