目录
iOS 与 Flutter module 混合应用
内容待整理
启动与调试
一、启动
1、iOS 端加载 Flutter module
App 启动时或某个特定页面打开时,初始化 Flutter 引擎(FlutterEngine)。
Flutter engine 启动后,就会载入并执行dart代码(调用main函数)。
2、iOS 启动 Dart VM Service 服务
Flutter Engine 在 iOS 端运行时,会启动 Dart VM Service 并监听一个 TCP 端口( 127.0.0.1:randomPort)。
当我们在xcode启动运行一个混合项目的时候,我们会看到在xcode的控制台内输出一段下面这样的日志:
flutter: The Dart VM service is listening on http://127.0.0.1:58788/0eT_T4ppesY=/
说明 dart vm service 已经启动,并监听58788端口,当该端口收到信息后,就会通知Flutter engin执行相应的操作,比如热重载、热重启、断点调试等。
3、为什么是127.0.0.1
127.0.0.1 是 本机回环地址,只在本机内部通信,不会进入局域网。因为网络设备不会转发这些数据包。
这样做的目的是:确保安全性,避免调试端口暴露到外网,防止远程攻击。
补充知识点:
127.0.0.1 仅限本机访问,任何外部设备都无法连接。
192.168.1.100 仅允许局域网访问,公网无法访问。
0.0.0.0 允许所有网络接口(包括 Wi-Fi)上的设备访问。
既然外网无法访问 dart vm service 那么这个服务如何跟外界通讯呢?
方法一:端口转发
flutter 正是采用的这种方式。
Flutter 通过 iproxy 端口转发工具完成这个映射。iproxy 是 libusbmuxd 提供的工具,它可以 将 USB 连接的 iOS 设备上的端口转发到 Mac。
// 将 Mac 上的 64914 端口映射到 iPhone 上的 58788,
// 这样 Mac 访问 127.0.0.1:64914,就等同于访问 iOS 设备上的 127.0.0.1:58788。
iproxy 64914:58788 <iPhone UDID>
补充:
端口转发工具有:iproxy、SSH、socat
方法二:手动修改 Dart VM Service 监听 IP
如果你有 Flutter Engine 的源码,可以修改 Dart VM Service 的监听地址,让它监听 0.0.0.0 而不是 127.0.0.1
// 修改 Flutter Engine 源码(示意代码)
vmService->Listen("0.0.0.0", 58788);
然后重新编译 Flutter Engine,让 iOS 设备的 VM Service 监听所有 IP。
二、调试
flutter代码调试,主要通过一个命令 flutter attach 来实现。
有了上边的基本知识,我们来看看 flutter attach 命令执行后发生了什么。
app运行起来后,在flutter module项目的跟目录执行下面命令:
flutter attach --verbose
我们看到输出的日志中有下面关键内容:
1、环境检测
确定当前设备架构(是否是 ARM64)。
executing: sysctl hw.optional.arm64
确定 Flutter SDK 的版本和 Git 信息。
3.7.12-ohos-99-gc2d467a188
检查 Xcode 版本,确保 iOS 相关工具可用。
executing: /usr/bin/arch -arm64e xcrun xcodebuild -version
2、设备检测
检测 Android 设备,没找到
executing: /Users/lxy/Library/Android/sdk/platform-tools/adb devices -l
检测OpenHarmony 设备,没找到
executing: /Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc -t list targets
检测 iOS 设备,包括模拟器和物理设备。
executing: /usr/bin/arch -arm64e xcrun xcdevice list --timeout 2
/usr/bin/arch -arm64e xcrun simctl list devices booted iOS --json
下面列出了很多找到的ios设备和模拟器
...
3. 连接 Dart Observatory 调试端口
Dart Observatory(观察器)是 Dart 虚拟机(Dart VM)提供的 调试、性能分析 服务。
这一步的目的是 查找 Flutter 应用的 Dart Observatory 服务,确保 flutter attach 能够连接到已经运行的 Flutter 进程,并进行调试。
[ +28 ms] Checking for advertised Dart observatories...
查找dart vm service可用的端口
[+5015 ms] Checking for available port on com.lxy.demo._dartobservatory._tcp.local
检查调试连接是否需要认证
[ +2 ms] Checking for authentication code for com.lxy.demo._dartobservatory._tcp.local
通过 iproxy 端口转发工具,转发到mac的64914端口,完成端口映射
[ +10 ms] Attempting to forward device port 58788 to host port 64914
[ +2 ms] executing: /Users/lxy/ohos/flutter_flutter/bin/cache/artifacts/usbmuxd/iproxy 64914:58788 --udid 00008101-001870E90A78001E --debug
[+1027 ms] Forwarded port ForwardedPort HOST:64914 to DEVICE:58788
4. 连接 Dart VM Service
链接映射后的本地服务(就相当于连接了ios设备上运行的 dart vm service)
[ +49 ms] Connecting to service protocol: http://127.0.0.1:64914/0eT_T4ppesY=/
DDS(Dart Development Service)作为中间层,代理 Dart VM Service,提供更稳定和多对一的通信。
启动DDS服务,端口号为0,代表随机分配
[ +99 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:64914/0eT_T4ppesY=/.
DDS启动成功,监听端口号为64917
[ +53 ms] DDS is listening at http://127.0.0.1:64917/A6bTmPCtjbI=/.
DDS和dart vm service映射链接成功,后续就可以通过DDS跟dart vm service通信
[ +25 ms] Successfully connected to service protocol: http://127.0.0.1:64914/0eT_T4ppesY=/
DDS(http://127.0.0.1:64917/A6bTmPCtjbI=/)【mac】
dart vm service 映射(http://127.0.0.1:64914/0eT_T4ppesY=/) 【mac 】
dart vm service( http://127.0.0.1:58788/0eT_T4ppesY=/)【iOS】
5. 创建 DevFS 并同步文件
DevFS 是 Flutter 在调试模式下使用的 设备上的虚拟文件系统,用于同步 Flutter 代码和资源,而不需要重新编译整个应用。
以上次编译的.dill文件作为基础,增量编译,并将增量文件同步到设备。
.dill 文件是 Dart Kernel 编译中间文件,Flutter 运行时可以直接加载它们,提高调试效率。
6. 启动 DevTools
本地启动一个调试服务http://127.0.0.1:9101,这个调试服务访问DDS,依赖DDS提供的信息。
An Observatory debugger and profiler on XY的iPhone 12 Pro Max is available at: http://127.0.0.1:64917/A6bTmPCtjbI=/
The Flutter DevTools debugger and profiler on XY的iPhone 12 Pro Max is available at: http://127.0.0.1:9101?uri=http://127.0.0.1:64917/A6bTmPCtjbI=/
调试 UI 页面能看到 Dart 代码,是因为 Dart VM Service 能提供 dill 文件。
三、Hot Reload 和 Hot Restart
特性 | 热重载(r) | 热重启(R) |
是否保留状态 | ✅ 是 | ❌ 否 |
是否重新执行 main() | ❌ 否 | ✅ 是 |
执行速度 | 非常快 | 稍慢 |
支持范围 | Dart UI 代码变更 | 全部 Dart 代码 |
用途 | 改 UI 不丢状态 | 初始化变更、彻底刷新 |
说明:
Hot Reload:
1、会触发当前页面 build() 方法重建,从而刷新 UI
2、会保留当前页面的状态,比如变量值,表单输入等
3、路由栈(你跳到第 3 个页面也不会跳回第一个)
4、不会重走初始化逻辑,比如类的 constructor、initState()
Hot Restart:
1、相当于在不重新安装 App 的前提下,从 main() 再跑一遍。
2、不会保留任何状态。
3、页面会回到第一个(初始页面)。
发现热重载不生效时可以尝试下热重启
行者常至,为者常成!