Flutter 开发 (2)优雅的 Flutter 组件化 混编方案

背景

此篇文章,主要针对想要在原有Native工程的基础上集成Flutter的需求,所提供的混编方案的探讨。

Flutter 官方已经给出了混编方案:https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps#ios 这种方案有 优点,也有 缺点

1. 官方方案的优缺点

(1)优点:
  • 不需要每次 Run 起来之后,先进行 同步flutter代码(组件化Flutter后,因为组件化后flutter代码已经变为framework,所以每次进来需要先热更新同步代码)
  • 不需要单独搞一个组件进行集成,管理组件的版本,发布等。
(2)缺点:
  • 会非常耦合工程,需要修改工程配置,添加 BUILD PHASE 调用 flutter 中 xcode_backend.sh 脚本 去编译 Flutter。

  • 如果使用pod管理,那么还需修改xcconfig配置。

  • 因为需要调用 Flutter 的编译脚本,所以这种方式集成后,团队内所有组员电脑和打包机,都必须安装Flutter环境才能编译成功。

2. Flutter 组件化混编方案

(1)优点:
  • 不需修改 原有 xcconfig 配置。
  • 不需要添加 Run Script 脚本。
  • 运行不需要依赖 Flutter 环境。
(2)缺点
  • 需要单独管理一个 flutter私有索引库。
  • 开发加载 Flutter 页面 首次需要热更新 进行刷新同步 Flutter 代码。
(3)混编方案 实现核心思想
  • 通过查看 Flutter 编译脚本xcode_backend.sh 和 测试单独引入编译产物,发现其实 只要拥有 Flutter 的编译产物,项目就可以接入 Flutter 的功能。
  • 所以说只要把Flutter编译好的产物,放在工程里,那么就无需配置每次调用 xcode_backend.sh 脚本,也无需强耦合Flutter环境,不需要所有组员安装Flutter环境,只需要有发布开发需求的同学进行安装即可。
  • 这就是Flutter组件化的实现核心点。
(4)Flutter 核心编译产物
  • App.framework:dart业务源码相关文件,在 Debug 模式下就是一个很小的空壳,在 Release 模式下包含全部业务逻辑。
  • flutter_assets:Flutter依赖的静态资源,如字体,图片等。
  • Flutter.framework:Flutter库和引擎。

目录

  • Flutter组件化 - 混编方案
  • Flutter组件化 - 断点调试
  • Flutter组件化 - 发布更新
  • Flutter组件化 - 一些坑点

一、Flutter组件化 - 混编方案

1. Git仓库存放 - 示例说明

主要分为3个仓库,分别存放Native项目、Flutter 工程源码、Flutter 编译产物私有pod库。
flutter 工程创建,使用 flutter create -t module my_flutter 命令

2. 项目目录 - 示例
  • Flutter_iOS :iOS开发主项目。

  • flutter_library :Flutter 项目的开发源码。

  • FlutterSDK :Flutter 源码的编译产物,所构建的私有 pod 库。

3. 混编方案说明
  • 根据 只要拥有 Flutter 的编译产物,项目就可以接入 Flutter 的功能 的核心思想,我们如果进行组件化Flutter混编,那么大概思路是:
有组件化环境 - 混编方案说明

(1)在 flutter 项目目录下,执行 flutter build ios 针对 Flutter 项目进行编译打包,生成 Flutter 编译产物。

Flutter 的产物分为两种模式,一个是 Debug 模式,采用 JIT(Just In Time)的方式,好处是可以支持热更新,方便调试,,但是性能比较慢。
另一种是 AOT(Ahead Of Time)release 模式,好处是性能比较好。

通过 flutter build ios --debug 可打包出 Debug 下的 Flutter 编译产物。

flutter build ios 命令依赖于 Flutter 生成的 Runner 工程,所以要确保 Runner 工程能够编译成功,这样才能生成 flutter 编译产物。如果遇到编译失败,可以检查下 bundle id 修改一下,使用自己的证书。如下图示例:

(2)针对编译产物,制作 Flutter SDK 私有库, podspec 指定 App.framework、engine、flutter_assets 路径。

# podspec 有省略
Pod::Spec.new do |s|
  s.name         = "FlutterSDK"
  s.vendored_frameworks = 'Framework/*.framework', 'Framework/engine/*.framework'
  s.resources = 'Framework/flutter_assets'
end

(3)上传 Flutter SDK 私有库项目到云端私有pod索引库。(如何制作私有 pod 索引库,可搜索查看相关资料,这里不细说了)

(4)iOS 主项目指定 Podfile ,拉取云端Flutter私有库到本地。

没有组件化环境 - 混编方案说明
  • 没有组件化环境的项目,并且不会建立私有索引库。
  • 那么只有手动 执行 flutter build ios 命令后,将编译产物手动拖拽到iOS项目中。
4. 最后效果

如下图,可以看到最终工程只引用了一个私有 pod 库。

总结

  • 对 flutter 项目执行 flutter build ios 命令,生成编译产物。
  • 针对编译产物,制作为私有 pod 库。
  • 主工程通过 cocoapods 引入私有 pod 库。

二、Flutter 组件化 - 断点调试

因为是编译后的资源接入,我们还需要保证 Flutter 开发的同学可以正常调试。

目录

  • 单独运行 Flutter 工程调试
  • 同时调试 iOS 和 Flutter(不支持断点)
  • 同时调试 iOS 和 Flutter(支持断点)
注意点:
  • 确保,已经安装 Android Studio(用于打开 Flutter 工程)
  • 确保,项目中依赖的 Flutter 打包出来的是 Debug 版本,Release 版本是无法热更新和调试的(使用 flutter build ios --debug 打包 debug 版本)
1. 单独运行 Flutter 工程调试 (只适合和 Native 没有太多关联的工程,比较少用)

使用 Android Studio 打开 Flutter 工程目录

选择好真机或者模拟器,然后点击 Run 按钮

这样 Run 起来后,我们就可以在 Flutter 项目中打断点调试。这种方法 只适合和 Native 没有关联的工程,比较少用。

2. 同时调试 iOS 和 Flutter(不支持Flutter断点的方式)

这种方法,需要先打开 Xcode 运行到 Flutter 页面,再进行附加 Flutter 端口号。

  • 使用 Xcode 打开 iOS 项目,运行起 Flutter 页面。

  • 会发现会输出一行日志,其中有一个端口号我们记录下来,例如:

flutter: Observatory listening on http://127.0.0.1:60455/
  • 然后 使用 Android Studio 打开 Flutter 项目(不点击运行),在 底部的 终端框中输入 flutter attach --debug-port=60455,端口号替换为xcode 日志输出的端口号。

Gif 演示

总结

  • 先打开 iOS 工程,运行起 Flutter 页面,得到一个日志输出的端口号。
  • 然后 Android Studio 打开 Flutter 工程,在底部终端处输入 flutter attach --debug-port=日志输出端口号,然后附加成功即可。
  • 注意点:附加成功后,在终端处,按小写 r 只会刷新有有修改的文件,按大写的 R 会全部刷新,如果使用组件化的话,每次进入 Flutter 页面,Android Studio 附加成功后,都要先按大写 R 全部刷新一次 同步到最新代码。否则还会显示旧的页面。
3. 同时调试 iOS 和 Flutter(同时支持Flutter 和 Xcode断点的方式)

这种方法,需要先打开 Android Studio 选择 Attach Debugger to Android Process 等待 Flutter 页面连接,然后在 iOS 端,运行到 Flutter 页面,Android Studio 就会附加成功。

  • 首先打开 Flutter 工程,直接点击 Attach Debugger to Android Process,然后会等待 Flutter 页面连接。

  • 然后运行 iOS 工程,进入 Flutter 页面。

  • 然后就会发现 Android Studio 已经显示在 同步文件了(Syncing files to device 张大森的 iPhone...

  • 同步完成即连接成功。

注意坑点

  • 我们可以看到 闪电符号 Flutter Hot Reload 和 返回绿色符号 Flutter Hot Restart
  • Flutter Hot Reload 为局部刷新,比如某个文件有改动,才会同步刷新此页面。Flutter Hot Restart可以理解为全部刷新,在 Android Studio 面板上也有对应按钮,相应也有对应快捷键。
  • 按照 Flutter 组件化的开发方式,我们首次附加连接成功后,一定要遵循一个步骤,先 点击 Flutter Hot Restart 进行全部刷新,再点击 Flutter Hot Reload 局部刷新。因为本人发现,如果最后一次刷新点击的是 Flutter Hot Restart 按钮,那么发现断点会不生效,只有点击 Flutter Hot Reload 后 触发的断点才会生效。

演示 Gif

  • 打断点.gif

总结

  • Android Studio 打开 Flutter 工程 ,点击 Attach Debugger to Android Process
  • 然后运行 Flutter 页面。
  • 然后点击Flutter Hot Restart (同步最新 Flutter 代码),在点击 Flutter Hot Reload 确保断点能够生效。

三、Flutter组件化 - 发布更新

发布大概流程

(1)对 Flutter 工程 执行 flutter build ios 或 flutter build ios --debug 生成编译产物。
(2)把编译产物复制移动到 Flutter 私有库目录下。
(3)打包 上传更新私有库内容。
(4)主工程拉取最新版本。

版本更新说明
  • 开发期间:基本只用热更新进行开发代码。
  • 发布版本:一般可在上线前进行发布,所以组件版本更新,用的比较少。

四、一些坑点

(1)FlutterViewController 不释放
  • 加载 Flutter 页面后,返回后,VC 不会释放。闲鱼有大神研究过这个问题,不过目前我们没有找到解决方案去释放 VC。
  • 我们使用单例持有了 VC,只能做到不每次进行叠加内存,不重新创建。每次进入 Flutter 页面都先重置一下。
  • 参考文章:https://www.jianshu.com/p/9ff7a9a5dfec
(1)不支持x86_64
  • 可以用xcode跑下,生成App.framewok,然后 lipo 命令合并下。
  • 我们目前不支持模拟器,这种方案没有进行测试。

其它

  • 如果有更好的调试方法,坑点解决方法,混编方法,欢迎交流反馈下。
下一篇文章 (主要涉及到 Flutter 开发的一些知识)
  • 教你 Flutter 如何与原生进行交互 待更新

参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容