美文网首页FlutterFlutter
Flutter新锐专家之路:工程研发体系篇

Flutter新锐专家之路:工程研发体系篇

作者: ced020bebb6c | 来源:发表于2018-08-07 12:34 被阅读158次

    写在前面

    当前,闲鱼客户端已经实现了基于Flutter的商品详情页的全量重构,线上效果良好。从alpha一路走来,我们遇到了很多问题,或基于原理,或透过社区,或与官方合作,都一个个解决了,是时候梳理和总结下,也希望为其他的开发者们,尤其是已有工程中引入Flutter(混合场景)实现渐进式重构带来启发和帮助。

    鉴于存在多个问题一个原因或解法的情况,而本系列的重点在于说明各种问题的解决方案与思路,就不一一列出问题。所有调试/热重载相关的Flutter均为Debug模式的Flutter,不再特殊说明。

    本系列文章包含三篇:引入篇,运行篇,上线篇。引入篇重点介绍工程研发体系;运行篇介绍混合情景下的栈管理与能力补齐等;上线篇介绍兼容/稳定性保障及方法。

    工程研发体系的关键点包括:

    a.混合工程下的Flutter研发结构

    混合工程中一个全局视角的的研发结构如何。

    b.工程结构

    已有的Native工程如何引入Flutter,工程结构如何组织,如何管理Flutter环境,如何去编译构建,集成打包等。

    c.构建优化

    这里主要介绍如何去针对Flutter的工具链(flutter_tools,Intellij插件等)进行调试与优化。

    d.Native启动下的Flutter调试

    不同于Flutter启动下的一体化调试,这种Native启动(Xcode/Android Studio启动,或点击图标打开应用)下的Flutter调试,我称之为分离式调试。分离式调试可以简化flutter_tools带来的复杂度,提高调试的稳定性和灵活性。

    e.Native启动下的Flutter热重载

    同d。

    f.联合调试

    即同时调试Flutter和Android/iOS。

    g.持续集成

    即混合环境下的Flutter构建与持续集成。

    环境说明

    混合工程下的Flutter研发结构

    工程结构

    这部分的核心逻辑是如何在最小改动已有iOS/Android工程的前提下运行Flutter。我们可以将Flutter部分理解成为一个单独的模块,通过pod库(iOS),aar库(Android)的方式,由CocoaPods和Gradle引入到主工程。

    具体的原理与实践请参见:

    深入理解flutter的编译原理与优化

    Flutter混合工程改造实践

    Add Flutter to existing apps

    其中,我们将整套Flutter环境作为Git Submodule统一管理,以保证团队内环境一致,遇到的个性化的问题/需求能够统一处理。

    构建优化篇

    编译速度的优化(Android)

    问题:Android在由Flutter启动时构建缓慢。

    原因:在flutter工具链(flutter_tools)的逻辑中,未找到android/app/build.gradle时,会运行gradle build从而执行多个编译配置的构建,而不是gradle assembleDebug。

    解法:重构Android工程,使工程应用Module对应的build.gradle位于android/app下,从而符合flutter_tools的逻辑。

    原理:flutter_tools的调试

    a.修改flutter_tools.dart,使之可打印参数

    b.删除flutter/bin/cache/flutter_tools.stamp使得flutter_tools可以被重建

    c.从flutter运行构建,获取其入口参数

    d.用Intellij(或Android Studio下同)打开flutter_tools工程,新建Dart Command Line App,并基于步骤c获得的入参配置"Program arguments"

    e.开始你的flutter_tools调试之旅吧‘

    编译速度的优化(iOS)

    问题:Flutter构建报"Observatory connection never became ready.",造成构建中断

    原因:重构前我们的工程全量编译时间较长(1000+文件全量编译时长>10min),而Flutter Intellij插件有个超时逻辑,使得构建中断。

    解法a(下策):定制Flutter Intellij插件(修改下面代码中的超时时间),编译插件,并替换Android Studio中的Flutter插件。更合理的解法是提PR,但这一路基本上都是在马不停蹄地解决各种产品化中的问题,所以...(最新版本已去除此逻辑)

    原理:

    前往查看Flutter Intellij源码

    事实上,我们使用IDE开发Flutter时,有下面的一个逻辑流程:

    解法b(中策):iOS工程的模块拆分和Pod(Framework)化,主工程构建依赖编译好的Framework,大大加快了构建时间。

    原理:模块化+预编译Framework

    解法c(上策):Native视角下的Flutter调试

    原理:Native启动下,Flutter的调试与热重载

    Native视角下的Flutter调试

    Flutter启动下的Flutter的调试与热重载逻辑

    实际上,当Native工程配置好Flutter支持后,Flutter启动下做的事情主要有:

    a.检查是否需要重新生成flutter_tools.snapshot。

    b.基于pubspec.yaml获取依赖(pub packages get),并生成插件描述文件.flutter-plugins和pubspec.lock。

    c.基于Flutter配置(如Framework路径,Debug/Release模式,是否开启Dart2等),生成Generated.xcconfig(iOS)和local.properties(Android)。

    d.基于gradle和xcodebuild构建应用(Flutter相关构建请参见前文中深入理解flutter的编译原理与优化)。

    e.基于adb和lldb启动应用。

    f.等待应用中Flutter启动,寻找Observatory端口,通过Dart Debugger连接以便调试。

    g.寻找到端口后同步Hot Reload依赖的文件,同时透过Daemon监听命令(如用户点击插件按钮)实现Full Restart或Hot Reload。

    换个角度来看,如果我们能够解决Native启动下的Dart调试和Hot Reload,由flutter_tools造成的编译慢等问题将不是问题,且可解决调试环境不稳定的情况(如我们的场景下,应用启动后,仅当用户点击进入详情页面的时候才会启动Flutter,此时flutter_tools才能去发现Observatory端口,调试和热重载,常有不好用的情况)。当从Xcode启动(或点击桌面图标启动,不再重复)包含了Debug模式Flutter内容的iOS(Android Studio启动Android类似,这里不再重复)应用时,我们需要关注abcfg。而abc除非flutter_tools或pubspec.yaml或Flutter配置变化等,否则都不需要重新执行。fg则是研发依赖的调试与热重载,必须考虑此模式下如何支持。

    Native启动下的Flutter的调试与热重载逻辑

    a.寻找iOS设备上Observatory端口

    或者命令行通过idevicesyslog获取,此处涉及到libimobiledevice库,其包含了idevicesyslog,iproxy等命令。

    可以看到iOS设备上Observatory启动了一个xxxx的端口(端口号随机)。

    b.透过iproxy将iOS设备上端口xxxx映射到本机端口yyyy

    c.可以看到waiting for connection,此时就可以访问http://127.0.0.1:yyyy/#/vm打开Observatory如下:

    可以使用Observatory去检查诸多dart相关的内存,调试等,这里不展开。

    也可以通过IDE链接去调试:

    d.配置Dart Remote Debug

    这里需要注意的是端口要使用刚转发到电脑的端口yyyy,搜索源码路径是Flutter工程的根目录。

    e.配置好之后点击Debug按钮,连接到调试端口

    f.成功后可以看到Debugger显示Connected(如果没有显示,再点击一次绿色的调试按钮‍️)

    g.之后便可以正常地使用IDE设置断点和调试dart(Flutter)代码

    Native视角下的Flutter热重载

    a.启动App,进入Flutter页面,查找Observatory端口xxxx,并转发到电脑yyyy(同上面ab)

    b.在Flutter工程目录下,执行flutter attach --debug-port=yyyy

    c.修改dart源代码,然后在b中Terminal中输入r(这一输入位于上图中'To quit,press"q"'之后)

    这里我们将超赞文案换成了赞。

    d.可以看到Terminal显示"Initializing hot reload...Reloaded...",结束后,设备上变更生效(左下角文案变成了赞)

    >>>>阅读全文

    相关文章

      网友评论

        本文标题:Flutter新锐专家之路:工程研发体系篇

        本文链接:https://www.haomeiwen.com/subject/ksiovftx.html