【博客园源码】【qqpsd源码】【powerui源码】flutterboost源码分析

1.2023年Flutter淡出人们视线:Flutter是源码否已失去竞争力?
2.解决Flutter_boost [FBFlutterContainerManager activeContainer:forUniqueId] 闪退
3.如何用 Flutter 实现混合开发?闲鱼公开源代码实例
4.好玩的开源项目推荐
5.Flutter 2.x 混合栈路由管理
6.Flutter 地图在携程的最佳实践

flutterboost源码分析

2023年Flutter淡出人们视线:Flutter是否已失去竞争力?

       年,Flutter在公众视野中的分析活跃度似乎有所下降,不禁让人质疑它是源码否还能保持竞争力。不过,分析要判断Flutter是源码否已失去优势,我们需要从多方面分析。分析博客园源码

       Flutter在年由闲鱼引入,源码随后在年的分析项目中大规模应用,期间闲鱼团队对框架进行了深度优化,源码甚至开源了Flutter Boost引擎。分析然而,源码尽管如此,分析Flutter始终伴随着质疑和争议,源码有人认为它只是分析重复造轮子,且语言选择上存在劣势。源码

       与此同时,技术市场不断涌现新框架,如React Native、Unity和Kotlin Native等,提供了更多选择。Kotlin与Flutter的开发理念不同,KMM更侧重于利用原生API,而Flutter则强调自绘UI和高性能渲染。在技术成本上,Flutter需要额外的引擎和较大包体积,而KMM则相对轻量,对开发者门槛较低。

       尽管如此,Flutter的自绘UI、高性能和热重载功能仍然是其不可替代的优势。在大型项目中,这些特性显得尤为重要。尽管面临新技术和学习曲线的挑战,Flutter作为谷歌的官方支持框架,其在企业级应用中的地位仍然稳固。

       尽管市场竞争激烈,Flutter的跨平台能力、高质量的原生界面和全球开发者社区的支持,使其仍具有吸引力。对于想要系统学习Flutter的开发者,有专门的学习资料可供参考,包括阿里P7架构师和谷歌技术团队的深度解析。

       结论是,虽然Flutter的市场热度有所下降,但它在核心竞争力方面并未消减,仍然有其独特的价值。点击获取更多关于Flutter学习资源的详细信息,以便深入理解并决定其是qqpsd源码否适合你的开发需求。

解决Flutter_boost [FBFlutterContainerManager activeContainer:forUniqueId] 闪退

       文章标题:解决Flutter_boost [FBFlutterContainerManager activeContainer:forUniqueId] 闪退

       前言

       在开发过程中,部分公司选择通过部分接入Flutter技术,以减少风险和降低开发成本,实现原生App与Flutter的混合开发。闲鱼推出的Flutter_boost提供了这样的容器能力,让开发者能够灵活地在原生App中嵌入Flutter组件。

       问题描述

       在使用iOS平台的Flutter_boost时,遇到了一个特定问题。当尝试通过FBFlutterContainerManager维护的字典,使用uniqueId进行查找容器时,遇到了页面闪退的情况。这通常发生在尝试销毁当前页面时,但系统未能正确识别当前页面作为父节点,导致错误的销毁行为。

       解决方案

       为了解决这一问题,首先需要检查当前页面是否为null。如果自定义的presentingViewController为null,则说明当前页面A作为父节点,不应被销毁。这一临时性解决方案在实际应用中有效,能够暂时避免页面闪退的问题。

       总结

       虽然这一方案解决了当前问题,但从长远考虑,我们已将这一解决方案提交给Flutter_boost的官方团队,期望能够获得一个更为完善、官方推荐的解决方案。这不仅有助于提升用户体验,也能确保开发过程中的稳定性。

如何用 Flutter 实现混合开发?闲鱼公开源代码实例

       阿里妹导读:具有一定规模的 App 通常有一套成熟通用的基础库,尤其是阿里系 App,一般需要依赖很多体系内的基础库。那么使用 Flutter 重新从头开发 App 的成本和风险都较高。所以在 Native App 进行渐进式迁移是 Flutter 技术在现有 Native App 进行应用的稳健型方式。

       今天我们来看看,闲鱼团队如何在这个实践过程中沉淀出一套独具特色的混合技术方案。

       现状及思考

       闲鱼目前采用的混合方案是共享同一个引擎的方案。这个方案基于这样一个事实:任何时候我们最多只能看到一个页面,当然有些特定的场景你可以看到多个 ViewController ,但是这些特殊场景我们这里不讨论。

       我们可以这样简单去理解这个方案:我们把共享的 Flutter View 当成一个画布,然后用一个 Native 的容器作为逻辑的页面。每次在打开一个容器的时候我们通过通信机制通知 Flutter View 绘制成当前的逻辑页面,然后将 Flutter View 放到当前容器里面。

       这个方案无法支持同时存在多个平级逻辑页面的情况,因为你在页面切换的时候必须从栈顶去操作,无法再保持状态的同时进行平级切换。举个例子:有两个页面A,powerui源码B,当前B在栈顶。切换到A需要把B从栈顶 Pop 出去,此时B的状态丢失,如果想切回B,我们只能重新打开B之前页面的状态无法维持住。

       如在 pop 的过程当中,可能会把 Flutter 官方的 Dialog 进行误杀。而且基于栈的操作我们依赖对 Flutter 框架的一个属性修改,这让这个方案具有了侵入性的特点。

       新一代混合技术方案 FlutterBoost

       重构计划

       在闲鱼推进 Flutter 化过程当中,更加复杂的页面场景逐渐暴露了老方案的局限性和一些问题。所以我们启动了代号 FlutterBoost(向C++ Boost库致敬)的新混合技术方案。这次新的混合方案我们的主要目标有:

       跟老方案类似,新的方案还是采用共享引擎的模式实现。主要思路是由 Native 容器 Container 通过消息驱动 Flutter 页面容器 Container,从而达到 Native Container与 Flutter Container 的同步目的。我们希望做到 Flutter 渲染的内容是由 Naitve 容器去驱动的。

       简单的理解,我们想做到把 Flutter 容器做成浏览器的感觉。填写一个页面地址,然后由容器去管理页面的绘制。在 Native 侧我们只需要关心如果初始化容器,然后设置容器对应的页面标志即可。

       主要概念

       Native 层概念

       Dart 层概念

       关于页面的理解

       在 Native 和 Flutter 表示页面的对象和概念是不一致的。在 Native,我们对于页面的概念一般是 ViewController,Activity。而对于 Flutter 我们对于页面的概念是 Widget。我们希望可统一页面的概念,或者说弱化抽象掉 Flutter 本身的 Widget 对应的页面概念。换句话说,当一个 Native 的页面容器存在的时候, FlutteBoost 保证一定会有一个 Widget 作为容器的内容。所以我们在理解和进行路由操作的时候都应该以 Native 的容器为准, Flutter Widget 依赖于 Native 页面容器的状态。

       那么在 FlutterBoost 的概念里说到页面的时候,我们指的是 Native 容器和它所附属的 Widget。所有页面路由操作,打开或者关闭页面,实际上都是对 Native 页面容器的直接操作。无论路由请求来自何方,最终都会转发给 Native 去实现路由操作。这也是接入 FlutterBoost 的时候需要实现 Platform 协议的原因。

       另一方面,我们无法控制业务代码通过 Flutter 本身的 Navigator 去 push 新的 Widget。对于业务不通过 FlutterBoost 而直接使用 Navigator 操作 Widget 的multidesk 源码情况,包括 Dialog 这种非全屏 Widget,我们建议是业务自己负责管理其状态。这种类型 Widget 不属于 FlutterBoost 所定义的页面概念。

       理解这里的页面概念,对于理解和使用 FlutterBoost 至关重要。

       与老方案主要差别

       前面我们提到老方案在 Dart 层维护单个 Navigator 栈结构用于 Widget 的切换。而新的方案则是在 Dart 侧引入了 Container 的概念,不再用栈的结构去维护现有的页面,而是通过扁平化 key-value 映射的形式去维护当前所有的页面,每个页面拥有一个唯一的 id。这种结构很自然的支持了页面的查找和切换,不再受制于栈顶操作的问题,之前的一些由于 pop 导致的问题迎刃而解。也不需要依赖修改 Flutter 源码的形式去进行页面栈操作,去掉了实现的侵入性。

       实际上我们引入的 Container 就是 Navigator 的,也就是说一个 Native 的容器对应了一个 Navigator。那这是如何做到的呢?

       多 Navigator 的实现

       Flutter 在底层提供了让你自定义 Navigator 的接口,我们自己实现了一个管理多个 Navigator 的对象。当前最多只会有一个可见的 Flutter Navigator,这个 Navigator 所包含的页面也就是我们当前可见容器所对应的页面。

       Native 容器与 Flutter 容器(Navigator)是一一对应的,生命周期也是同步的。当一个 Native 容器被创建的时候,Flutter 的一个容器也被创建,它们通过相同的 id 关联起来。当 Native 的容器被销毁的时候,Flutter 的容器也被销毁。Flutter 容器的状态是跟随 Native 容器,这也就是我们说的 Native 驱动。由 Manager 统一管理切换当前在屏幕上展示的容器。

       我们用一个简单的例子描述一个新页面创建的过程:

       这就是一个新页面创建的主要逻辑,销毁和进入后台等操作也类似有 Native 容器事件去进行驱动。

       官方提出的混合方案

       基本原理

       Flutter 技术链主要由 C++ 实现的 Flutter Engine 和 Dart 实现的 Framework 组成(其配套的编译和构建工具我们这里不参与讨论)。Flutter Engine 负责线程管理,Dart VM 状态管理和 Dart 代码加载等工作。而 Dart 代码所实现的 Framework 则是业务接触到的主要 API,诸如 Widget 等概念就是在 Dart 层面 Framework 内容。

       一个进程里面最多只会初始化一个 Dart VM。然而一个进程可以有多个 Flutter Engine,多个 Engine 实例共享同一个 Dart VM。

       我们来看具体实现,在 iOS 上面每初始化一个 FlutterViewController 就会有一个引擎随之初始化,也就意味着会有新的线程(理论上线程可以复用)去跑 Dart 代码。Android 类似的 Activity 也会有类似的效果。如果你启动多个引擎实例,注意此时Dart VM 依然是kde 源码共享的,只是不同 Engine 实例加载的代码跑在各自独立的 Isolate。

       官方建议

       引擎深度共享

       在混合方案方面,我们跟 Google 讨论了可能的一些方案。Flutter 官方给出的建议是从长期来看,我们应该支持在同一个引擎支持多窗口绘制的能力,至少在逻辑上做到 FlutterViewController 是共享同一个引擎的资源的。换句话说,我们希望所有绘制窗口共享同一个主 Isolate。

       但官方给出的长期建议目前来说没有很好的支持。

       多引擎模式

       我们在混合方案中解决的主要问题是如何去处理交替出现的 Flutter 和 Native 页面。Google 工程师给出了一个 Keep It Simple 的方案:对于连续的 Flutter 页面(Widget)只需要在当前 FlutterViewController 打开即可,对于间隔的 Flutter 页面我们初始化新的引擎。

       例如,我们进行下面一组导航操作:

       我们只需要在 Flutter Page1 和 Flutter Page3 创建不同的 Flutter 实例即可。

       这个方案的好处就是简单易懂,逻辑清晰,但是也有潜在的问题。如果一个 Native 页面一个 Flutter 页面一直交替进行的话,Flutter Engine 的数量会线性增加,而 Flutter Engine 本身是一个比较重的对象。

       多引擎模式的问题

       因此,综合多方面考虑,我们没有采用多引擎混合方案。

       总结

       目前 FlutterBoost 已经在生产环境支撑着在闲鱼客户端中所有的基于 Flutter 开发业务,为更加负复杂的混合场景提供了支持,稳定为亿级用户提供服务。

       我们在项目启动之初就希望 FlutterBoost 能够解决 Native App 混合模式接入 Flutter 这个通用问题。所以我们把它做成了一个可复用的 Flutter 插件,希望吸引更多感兴趣的朋友参与到 Flutter 社区的建设。在有限篇幅中,我们分享了闲鱼在 Flutter 混合技术方案中积累的经验和代码。欢迎兴趣的同学能够积极与我们一起交流学习。

       扩展补充

       在两个 Flutter 页面进行切换的时候,因为我们只有一个 Flutter View 所以需要对上一个页面进行截图保存,如果 Flutter 页面多截图会占用大量内存。这里我们采用文件内存二级缓存策略,在内存中最多只保存 2-3 个截图,其余的写入文件按需加载。这样我们可以在保证用户体验的同时在内存方面也保持一个较为稳定的水平。

       页面渲染性能方面,Flutter 的 AOT 优势展露无遗。在页面快速切换的时候,Flutter 能够很灵敏的响应页面的切换,在逻辑上创造出一种 Flutter 多个页面的感觉。

       项目开始的时候我们基于闲鱼目前使用的 Flutter 版本进行开发,而后进行了 Release 1.0 兼容升级测试目前没有发现问题。

       只要是集成了 Flutter 的项目都可以用官方依赖的方式非常方便的以插件形式引入 FlutterBoost,只需要对工程进行少量代码接入即可完成接入。详细接入文档,请参阅 GitHub 主页官方项目文档。

好玩的开源项目推荐

       欢迎光临,今日为您推荐一系列趣味十足的开源项目,让工作之余也能享受科技带来的乐趣。

       项目一:Spleeter。一款音轨分离软件,只需输入一段命令,即可轻松分离音乐中的人声与乐器声,支持多种常见音频格式,由 Python 语言编写,并利用 TensorFlow 进行模型训练。

       项目地址:github.com/deezer/spleeter...

       项目二:FlutterBoost。由阿里系闲鱼团队开源的框架,提供快速便捷的原生应用与 Flutter 混合集成方案,最新版本为 v3.0-preview,目前仍持续维护中。

       项目地址:github.com/alibaba/flutterboost...

       项目三:Orika。一个基于字节码技术栈实现的高性能 Java 对象映射框架,以其简单易用、高效的特点成为众多映射框架中的佼佼者。

       项目地址:github.com/orika-mapper...

       项目四:hotkey。京东 APP 后台热数据探测开源框架,经过多次高压压测和京东 大促的考验,精确探测热门商品并快速推送到服务端,大幅减轻数据层查询压力,提升应用性能。

       项目地址:gitee.com/jd-platform-hotkey...

       项目五:PaddleOCR。基于飞桨的 OCR 工具库,提供超轻量级中文 OCR,支持中英文数字组合识别、竖排文本识别、长文本识别,同时包含多种文本检测、识别的训练算法。

       项目地址:gitee.com/paddlepaddle/...

       项目六:XXL-JOB。一个轻量级分布式任务调度平台,设计目标是开发迅速、学习简单、轻量级、易扩展,现已开放源代码,并在多家公司线上产品线中应用。

       项目地址:github.com/xuxueli/xxl-job...

       项目七:CIM。基于 Netty 框架的即时消息推送系统,支持多端接入,适用于移动应用、物联网、智能家居等领域。

       项目地址:gitee.com/farsunset/cim...

       项目八:DevSidecar。为开发者提供辅助的边车工具,通过本地代理将 HTTP 请求代理到加速通道,解决网站和库无法访问或访问速度慢的问题。

       项目地址:github.com/docmirror/devsidecar...

       项目九:Jsoup。一款 Java 的 HTML 解析器,可直接解析 URL 或 HTML 文本,提供简单易用的 API,支持 DOM、CSS 以及类似 jQuery 的操作方法。

       项目地址:github.com/jhy/jsoup...

       项目十:Knife4j。为 Java MVC 框架集成 Swagger 生成 API 文档的增强解决方案,前身是 swagger-bootstrap-ui,取名 knife4j,旨在小巧、轻量、功能强大。

       项目地址:github.com/xiaoymin/swagger-bootstrap-ui...

       项目十一:Arthas。阿里巴巴开源的 Java 诊断工具,支持 JDK 6+,适用于 Linux/Mac/Windows,提供命令行交互模式与丰富的 Tab 自动补全功能。

       项目地址:github.com/alibaba/arthas...

       项目十二:El-admin。基于 Spring Boot、Jpa、Spring Security、redis、Vue 的前后端分离的开源后台管理系统,采用 RBAC 权限控制方式,支持数据字典、数据权限管理与代码生成。

       项目地址:github.com/elunez/eladmin...

       项目十三:Halo。使用 Java 开发的开源博客系统,基于 Spring Boot 框架,通过一行命令即可完成安装。

       项目地址:github.com/halo-dev/halo...

       项目十四:Hutool。一个功能全面的 Java 工具类库,提供静态方法封装,降低学习成本,提高工作效率。

       项目地址:github.com/dromara/hutool...

       希望以上推荐能满足您的需求,若感兴趣,不妨前往 GitHub 上探索更多好玩的开源项目,每日都有更新!

Flutter 2.x 混合栈路由管理

       在Flutter开发中,混合栈路由管理是一个关键问题。面临混合开发时,尤其是当项目已有成熟业务代码且考虑将Flutter作为子模块接入时,路由和组件生命周期的管理显得尤为重要。目前,尽管Flutter在跨平台方案一致性与体验上广受好评,但对于已有原生业务代码的项目,直接使用纯Flutter开发几乎是不切实际的,因此,混合开发成为普遍选择。混合开发中,Flutter页面与原生页面之间的跳转成为核心问题。然而,在Flutter 2.0版本前,其官方路由方案在多引擎环境下存在通信隔离、资源不共享以及可能引发的内存损耗(多次打开Flutter页面时,内存异常增长)等问题。为解决这些问题,业内出现了如flutter_boost、mix_stack、flutter_thrio等混合路由方案,这些方案通过单引擎复用策略应对,但依旧存在痛点,主要在于:混合栈路由使用时可能产生内存异常,以及在Flutter底层代码修改后,上层框架需不断适配。

       针对上述问题,多引擎方案在一定程度上缓解了内存泄露和性能问题,但其优势主要体现在特定场景下,例如集成有Flutter界面的应用,其位置不在路由栈的叶子节点上,且可能是混合路由栈;或多个FlutterView同时集成在一个页面上,并同时显示。

       为解决上述问题,Flutter 2.0引入了FlutterEngineGroup方案。该方案通过使用多个Flutter Engine的混合模式,显著减少了额外的Flutter引擎内存占用,将内存开销减少了约%。FlutterEngineGroup简化了API,并使得多个Engine实例内部维护独立的导航堆栈,实现每个Engine对应一个独立模块。得益于FlutterEngineGroup生成的FlutterEngine可以共享GPU上下文、共享渲染线程等特性,实现更快的引擎初始化和更低的内存占用。官方示例显示,在Android真机上运行使用FlutterEngineGroup打开个页面时,内存和CPU使用情况得到了优化。

       官方提供了使用FlutterEngineGroup的示例,通过以下步骤即可运行示例:打开并运行Android混合工程。在创建FlutterEngineGroup对象时,最好在Application的onCreate()方法中进行。在原生页面使用Intent方式跳转到Flutter主页面时,使用withCachedEngine可避免跳转时的白屏问题。在Flutter模块的main.dart中创建DartEntrypoint对象,确保方法名与FlutterEngineGroup创建的FlutterEngine对应。通过创建的dartEntrypoint和context,使用FlutterEngineGroup创建出对应的FlutterEngine,内部通过FlutterJNI.nativeSpawn与原有引擎交互,得到新的地址id。最后,通过生成的FlutterEngine的binaryMessenger获取一个MethodChannel,实现原生与Dart之间的通信。使用生成的Engine渲染运行新的FlutterUI时,无需担心内存问题,因为每个Flutter页面作为独立的Engine,无法共享内存。每个独立Engine的Flutter页面内存如dart isolate设计理念所示,无法直接共享,需要在原生层持有数据,并通过注入或传递至每个Flutter页面。

       最后,介绍如何在混合开发中使用Flutter 2.x进行数据传递等基本操作,实现更加高效、灵活的数据管理与交互。

Flutter 地图在携程的最佳实践

       随着技术的快速发展,项目设计从单一的 Native 应用扩展到 Native+RN,再到如今的 Native+RN+Flutter。在携程,我们的业务主要基于 Flutter,这就需要在 Flutter 项目中嵌套使用地图。目前,实现这一目标的主要方法有两种:

       1. 采用官方 Flutter 地图插件,但可能面临维护成本和定制需求的权衡。为了更好地定制 API 和快速修复问题,我们选择源码集成,主要在 flutter-boost 的混合工程中实践,以单引擎模式接入插件。

       源码集成主要分为两个步骤:首先,从官方 demo 中获取插件源码,然后分别在 Flutter 和 Native(iOS/Android)端进行导入。Flutter 端执行 `flutter pub get`,导入插件源码,iOS 与 Android 则导入对应目录的代码。

       地图插件的实现基础是 PlatformView,它允许原生组件嵌入 Flutter 页面。插件通过 MethodChannel 与 Native 通信,以 Map 为例,平台View 将 Native 地图嵌入 Flutter,并通过指定 viewId 初始化 BMFMapViewController,处理地图操作和事件传递。

       在混合项目中,集成 PlatformView 需要处理不同平台的生命周期同步问题。例如,IOS 页面切换时可能会出现白屏,这是由于 Flutter A 页面跳转到 B 页面时,平台View 的生命周期与预期不符。为解决这个问题,可以在适当的地方调用 `surfaceUpdated` 方法,以确保同步。

       Android 地图使用中也遇到过卡死和内存溢出问题。这些通常是由于生命周期管理不当导致的,如 context 对象回收。通过设置 `shouldAttachEngineToActivity` 为 `false`,使 Flutter 引擎独立于 Activity,避免了这些问题。

       自定义地图中的 BitMap Marker 时,推荐利用地图插件提供的 iconData 参数,将文本和绘制后传递给 Native。在 Flutter 3 中,要注意 toImage 方法可能在 debug 环境下因为弱引用指针检查而被终止,但在 release 环境下正常工作。

       在展示 Marker 时,可能需要调整地图的可见范围,这涉及 iOS 和 Android 的不同计算方式。随着业务需求的迭代,还需考虑地图大小与列表的配合,确保动画流畅。

       总的来说,Flutter 地图插件在携程的最佳实践主要围绕如何在混合项目中集成、处理 PlatformView 的生命周期问题、自定义 Marker 和优化地图显示效果展开。通过解决这些问题,我们实现了高效、稳定的地图功能集成。

更多内容请点击【百科】专栏