Flutter 混合工程改造实践

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010960265/article/details/82886054

背景


由于原有的 iOS 和 Android 工程都已相当庞大,如何将 Flutter 无缝桥接到这些大工程并保证开发效率不受影响成为优先要解决的问题。

本文针对项目实践人员给出了一种通用的工程改造方案,希望为准备转型 Flutter 的团队提供参考。

问题


Flutter 的工程结构比较特殊,由 Flutter 目录再分别包含 Native 工程的目录(即 iOS 和 Android 两个目录)组成。默认情况下,引入了 Flutter 的 Native 工程无法脱离父目录进行独立构建和运行,因为它会反向依赖于 Flutter 相关的库和资源。
在这里插入图片描述

很显然,在拥有了 Native 工程的情况下,开发者不太可能去创建一个全新的 Flutter 工程重写整个产品,因此 Flutter 工程将包含已有的 Native 工程,这样就带来了一系列问题:

1)构建打包问题

引入 Flutter 后,Native 工程因对其有了依赖和耦合,从而无法独立编译构建。在 Flutter 环境下,工程的构建是从 Flutter 的构建命令开始,执行过程中包含了 Native 工程的构建,开发者要配置完整的 Flutter 运行环境才能走通整个流程;

2)混合编译带来的开发效率的降低

在转型 Flutter 的过程中必然有许多业务仍使用 Native 进行开发,工程结构的改动会使开发无法在纯 Native 环境下进行,而适配到 Flutter 工程结构对纯 Native 开发来说又会造成不必要的构建步骤,造成开发效率的降低。

目标


针对以上问题,我们提出了以下的改造目标,力求最小化 Native 工程对 Flutter 相关文件的依赖,使得:

1)Native 工程可以独立地编译构建和调试执行,进而最大限度地减少对相关开发同学的干扰并使打包平台不再依赖 Flutter 环境及相关流程;

2)Native 工程处在 Flutter 环境中时(即作为 iOS 或 Android 子目录)能够正确依赖相关库和文件,正常执行各类 Flutter 功能,如 dart 代码的构建,调试,hot reload 等,保证 Flutter 环境下开发的正确性。

方案的制定


两种模式

首先定义 Native 工程处于独立目录环境下称为 Standalone 模式,处于 Flutter 目录下称为 Flutter 模式。目标中纯 Native 开发或平台打包就处于 Standalone 模式,Flutter 对开发人员和打包平台来说是透明的存在,不会影响构建与调试;而 Flutter 的代码则在 Flutter 模式进行开发,其相关库的生成,编译和调试都走 Flutter 定义的流程。
在这里插入图片描述

理清依赖

从上面的定义来看,改造的核心就是把 Standalone 模式提取出来,那么就要理清 Standalone 模式对 Flutter 的依赖,并将其提取成第三方的库,资源或源码文件。以 iOS 为例,通过阅读 Flutter 构建的源码,可知 Xcode 工程对 Flutter 有如下依赖:

1)App.framework:dart 业务源码相关文件;
2)Flutter.framework:Flutter 引擎库文件;
3)pubs 插件目录及用于索引的文件:Flutter 下的插件,包括各种系统的和自定义的 channels;
4)flutter_assets:Flutter 依赖的静态资源,如字体,图片等;

依赖引入的策略

尝试过两种依赖引入策略,以下分别进行阐述。

1)本地依赖

通过修改 Flutter 构建流程将其库文件,源码和资源直接放置到 Native 工程的子目录中进行引用,以 iOS 为例,就是将 Flutter.framework 及相关插件等做成本地的 pod 依赖,资源也复制到本地进行维护。 由此,Standalone 模式便具备了独立构建和执行的能力,对于纯 Native 开发人员来说 Flutter 只是一些二方库与资源的合集,无需关注。 而在 Flutter 模式下,dart 源码的构建流程不变,不影响编译和调试;同时由于是本地依赖,Flutter 模式下的各种改动也实时可以同步到 Native 工程的子目录中,提交修改后 Standalone 模式也就拥有了最新的 Flutter 相关功能。

  • 优点:Flutter 相关内容的改动同步到 Standalone 模式也比较方便;
  • 缺点:需要对 Flutter 原有的构造流程进行稍嫌复杂的改动,并且与后续的 Flutter 代码合并会有冲突,且 Native 工程与
    Flutter 的内容还是耦合在本地不够独立。

2)远程依赖

远程依赖的想法是将 Flutter 所有依赖内容都放在独立的远端仓库中,在 Standalone 模式下引用远程仓库中的相关资源,源码和库文件,Flutter 模式下的构建流程和引用方式则不变。

  • 优点:对 Flutter 自身的构建流程改动较少并且较彻底第解决了本地耦合的问题;
  • 缺点:同步的流程变得更繁琐,Flutter 内容的变动需要先同步到远程仓库再同步到 Standalone模式方能生效。

PS. 最终选择了这个策略。
在这里插入图片描述

改造的实现


目录的组织

Flutter 模式下父工程目录下的 ios 和 android 的子目录分别包含对应的 Native 工程,代码管理上子工程可以使用 git 的 submodule 形式,保证目录间的独立。

远程依赖的实现

在 Standalone 模式下,Flutter 的依赖内容都指向远程仓库中的对应文件,而在 Flutter 模式下依赖的方式不变。

1)向 Standalone 模式同步 Flutter 的变更

由于远程依赖的问题是同步变动比较麻烦,为此开发了一系列脚本工具使该过程尽量自动完成。 假设 Flutter 的内容(可能是业务源码,引擎库或某些资源文件)发生变化,那么在 Flutter 模式下构建结束后,脚本会提取生成好的所有依赖文件拷贝到远程仓库,提交并打 tag,然后依据打出的 tag 生成新的远程依赖说明(比如 iOS 下的 podspec),最后在 Standalone 模式下修改 Flutter 的依赖至最新的版本,从而完成整个同步过程。
在这里插入图片描述

2)同步的时机

建议在提测及灰度期间,每次 Flutter 业务的提交都能够触发同步脚本的执行和 app 打包;开发期间保持每日一次的同步即可。

总结


为解决引入 Flutter 后的工程适配问题,我们抽取了 Flutter 的相关依赖放到远程供纯 Native 工程进行引用,从而保证了 Flutter 与纯 Native 开发的相互独立与并行执行。

相信该方案也可以为转型 Flutter 的团队提供帮助,当然项目间的差异也会导致方案的不同,因此如有更好的方法和意见也期望多多交流!

猜你喜欢

转载自blog.csdn.net/u010960265/article/details/82886054