JHHK

欢迎来到我的个人网站
行者常至 为者常成

混合应用创建与调试⭐️

目录

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、页面会回到第一个(初始页面)。

发现热重载不生效时可以尝试下热重启


行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.