开启成长之旅!这是我参加「日新计划 12 月更文应战」的第1天,点击检查活动详情
公司的iOS项目是原生嵌Flutter类型,运用Flutter多引擎
(Engine group)计划。与曾经项目运用的Flutter boost
计划不同, 发现多引擎
计划的attach
功用十分不稳定,经常呈现无法attach
以及Hot reload
, Hot restart
卡死的状况,十分影响开发效率。本文会简略剖析问题原因及提供一些解决计划。
Flutter attach的原理
Flutter经过将更新的源代码文件注入到正在运转的Dart 虚拟机(VM)
来实现热重载。在虚拟机运用新的字段和函数更新类之后, Flutter
框架会自动从头构建 widget
树,以便快速检查更改的作用。
而attach
的进程就是一个衔接VM
的进程,使用以Debug
模式运转后,会启动一个VM
服务,并且运用mDNS
协议( mDNS/DNS-SD 是用于本地局域网服务发现的协议)广播。履行attach
操作时,会经过mDNS
协议去查找当时使用所匹配的VM
服务,再经过WS
协议进行衔接,这个时分就可能呈现如下几种状况,导致衔接失利:
- 找到的
VM
服务太多,需求挑选衔接哪一个。 - 调度问题,没有去连正确的 VM 服务。
-
mDNS
缓存没有刷新 -
mDNS
查找问题
1. 找到的VM
服务太多,需求挑选衔接哪一个
当呈现这类问题时,一般会呈现这类log:
There are multiple observatory ports available.
Rerun this command with one of the following passed in as the appId:
flutter attach --app-id com.xxx.test
flutter attach --app-id com.xxx.test (2)
多引擎
计划相对于单引擎
计划及纯Flutter
项目,很简单呈现这类问题,这种状况如提示所示,在项目的运转装备中指定app-id
,再运转测验,具体操作如图所示:
在多引擎
计划中,这个操作大概率不能解决attach
问题,咱们也不能清晰知道自己运转的使用对应的是哪个app-id
, 后面那个com.xxx.test (2)
相对于第一个附加了(2)
,实际上都是对应同一个bundle identifier
的使用,仅仅由于先来后到的原因,后到的被附加了(2)
,如果有更多,可能还会看到附加了(3)
的等。所有咱们需求如图所示在后面加上-v
参数来获取详细日志,以便于剖析问题发生的原因。
2. 调度问题,没有去连正确的VM
服务
当咱们指定 app-id
后, 还是会经常呈现attach
失利,这是什么原因呢?咱们能够经过指令: ns-sd -Z _dartobservatory._tcp
来获取当时VM
服务列表,输出如下:
➜ ✗ dns-sd -Z _dartobservatory._tcp
Browsing for _dartobservatory._tcp
DATE: ---Sat 28 May 2022---
20:19:44.892 ...STARTING...
; To direct clients to browse a different domain, substitute that domain in place of '@'
lb._dns-sd._udp PTR @
; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.
; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local
; names with the correct fully-qualified (unicast) domain name of the target host offering the service.
_dartobservatory._tcp PTR com\.xxx\.test._dartobservatory._tcp
com\.xxx\.test._dartobservatory._tcp SRV 0 0 57624 yanfang.local. ; Replace with unicast FQDN of target host
com\.xxx\.test._dartobservatory._tcp TXT "authCode=8DjE8_OckNk="
_dartobservatory._tcp PTR com\.xxx\.test\032(2)._dartobservatory._tcp
com\.xxx\.test\032(2)._dartobservatory._tcp SRV 0 0 64646 yanfang.local. ; Replace with unicast FQDN of target host
com\.xxx\.test\032(2)._dartobservatory._tcp TXT "authCode=J0BgTyk73m8="
_dartobservatory._tcp PTR com\.xxx\.test\032(3)._dartobservatory._tcp
com\.xxx\.test\032(3)._dartobservatory._tcp SRV 0 0 61345 star.local. ; Replace with unicast FQDN of target host
com\.xxx\.test\032(3)._dartobservatory._tcp TXT "authCode=E0fcBt3fdk2="
在输出中能够看到VM
服务的app-id
, 端口
, 设备名
。 如第一条,app-id
是 com.xxx.test
, 端口
是:57624
, 设备名
是:yanfang.local
。
输出中有3个服务,分别是:com\.xxx\.test._dartobservatory._tcp
和 com\.xxx\.test\032(2)._dartobservatory._tcp
,其实这两个都是bundle identifier
为 com.xxx.test
使用所对应的VM
服务,由于先来后到的原因,后到的就被加了一个(2)
以做区别,在上述log内容中,咱们甚至可能会看到搭档的设备名称,这是由于mDNS
协议是查找整个局域网内的VM
服务,当你和搭档在调试同一个项目时,mDNS
会把你和搭档相同app-id
的VM
服务一起找出来,那么哪个是你当时调试使用对应的VM
服务呢? 尽管你指定了app-id
,可是你先运转app-id
是com.xxx.test
,后运转你就变成了com.xxx.test (2)
。这种状况下有两种计划来解决这个问题:
- 在
attach
时拔掉网线,断开网络衔接,让mDNS
找不到局域网内其它设备的VM
服务 - 每次运转前履行
ns-sd -Z _dartobservatory._tcp
检查当时的VM
服务,依据上面的设备名和端口挑选正确的app-id
进行装备。
3. 存在mDNS
缓存,没有刷新
有时分,咱们调用ns-sd -Z _dartobservatory._tcp
指令后会发现,同一台设备中,存在多个同名的VM
服务,可是明明一台设备不可能一起运转两个相同bundle identifier
的使用。我置疑可能是Flutter多引擎下存在bug,导致缓存没有刷新引起的。具体没有深究,欢迎评论区点拨纠正。
在这类状况下就只能依赖于-v
参数,检查attach
时的log, 看是去测验衔接的哪一个VM
服务。 log样例日下:
[+1902 ms] Checking for available port on com.xxx.test._dartobservatory._tcp.local
[ +3 ms] Checking for authentication code for com.xxx.test._dartobservatory._tcp.local
[ +67 ms] Connecting to service protocol: http://127.0.0.1:56954/SNvhcI0TrgU=/
[ +17 ms] Exception attempting to connect to the VM Service: SocketException: OS Error: Connection refused, errno = 61, address = 127.0.0.1, port = 60679
[ ] This was attempt #1. Will retry in 0:00:00.100000.
在上述log中能够看到测验衔接的VM
服务端口和app-id
,一般配合ns-sd -Z _dartobservatory._tcp
指令来判断正确的app-id
,然后指定app-id
再运转即可。
4. mDNS
查找问题
Flutter库房的Issue46705有对这类问题进行说明,处理方式有:
- 封闭个人热点
- Mac -> 设置 -> 网络 -> iPhone USB -> 不勾选“除非需求,否则请停用”
- 重试
在实践中,经过上述4个流程,能够确保必定attach
成功。
Hot reload
问题
Flutter多引擎计划相对其它计划来讲,含辛茹苦attach
成功后,还会有更高概率呈现Hot reload
卡死的状况,实际运用起来十分不稳定,咱们能够经过如下事项缓解:
- 封闭自动
Hot reload
和保存代码触发Hot reload
功用。 - 不在
Hot reload
和Hot restart
时切换页面。 - 避免一起履行多次
Hot reload
,Hot reload
。 -
Hot reload
无效时,测验履行Hot reload
恢复状态。 - 代码中有死循环,也会导致
Hot reload
,Hot reload
卡死
做了如上操作后,Hot reload
卡死的状况会缓解,可是依然会有必定概率呈现,如果您有更好的计划,欢迎评论区告知。
参考资料
- 官方文档-热重载
- 解读Flutter中热重载原理
- iOS mDNS meta issue
by 星的天空