最后核验:2026-09-04
本篇结论
同一台 Mac 上可以并存上游 Flutter 与 Flutter-OH,但不要把两套 SDK 的 bin 同时永久加入 PATH。本课程采用“分别保存 SDK,执行命令时写明 SDK 绝对路径”的方式:iOS/Android 命令固定交给上游 Flutter,OpenHarmony 命令固定交给 Flutter-OH。
这样做不需要安装额外的版本管理工具,也不会让目录顺序决定构建结果。每次操作前先检查 Flutter 与 Dart 版本;版本不匹配时停止,不用另一套 SDK 继续碰运气。
本篇已在本机验证上游 Flutter 3.47.2 与 Dart 3.13.2 的路径和命令,并使用这条轨道完成 iOS Simulator 构建、Android 16 模拟器运行、debug APK 与 release AAB 构建。Flutter-OH SDK 尚未安装,因此涉及 Flutter-OH 的同构检查命令只依据 CPF-Flutter 官方资料给出,未在本机执行,也不代表 Spark 已通过 OpenHarmony 构建。
学完你能做到
- 解释 SDK、目标平台和项目源码为什么是三个不同概念。
- 不依赖全局
PATH,明确指定一条 Flutter 命令来自哪套 SDK。 - 在执行分析、测试或构建前核对 Flutter 与 Dart 版本。
- 识别终端、VS Code 和自动化脚本使用了不同 SDK 的情况。
- 判断当前
Spark为什么只能在上游轨道继续开发。
开始前检查
先读完第 07 课,确认你理解 Flutter-OH 是独立维护的 OpenHarmony 适配 SDK,不是上游 Flutter 的一个可选 target。
本篇不会执行以下操作:
- 安装或克隆 Flutter-OH。
- 修改
~/.zshenv、~/.zprofile或~/.zshrc。 - 修改 DevEco Studio、VS Code 或系统配置。
- 修改
Spark的pubspec.yaml、依赖或 Dart 约束。 - 生成
ohos/、构建 HAP 或验证 OpenHarmony 设备。
01 先把三件事分开
双 SDK 不是复制两份应用。需要分开理解的是:
同一份课程源码
├── Track A:上游 Flutter SDK → iOS/Android
└── Track B:Flutter-OH SDK → OpenHarmony
| 对象 | 本课程中的含义 | 当前状态 |
|---|---|---|
| 项目源码 | Spark 的 Dart 代码、资源和平台工程 |
已存在于 app/ |
| Track A SDK | Flutter 3.47.2 stable,配套 Dart 3.13.2 | 本机已安装并验证 |
| Track B SDK | Flutter-OH 3.41.10-ohos-1.0.1,基于上游 Flutter 3.41.9,配套 Dart 3.11.5 |
本机未安装 |
| 目标平台 | 一次命令实际要运行或构建的平台 | iOS 与 Android 已验证;OpenHarmony 尚未验证 |
flutter 只是命令名。Shell 最终执行哪一个文件,取决于路径解析结果;它不会根据当前目录自动理解你想构建 iOS 还是 OpenHarmony。
02 为什么不把两套 SDK 都塞进 PATH
假设配置文件中同时存在:
export PATH="<flutter-upstream>/bin:$PATH"
export PATH="<flutter-oh>/bin:$PATH"
两行都没有语法错误,但后加入的目录通常排在前面。调换行序、重新加载不同配置文件,或从不同入口启动 VS Code,都可能改变裸命令 flutter 的来源。
这会产生三类问题:
flutter --version显示的 SDK 与你以为的不同。flutter pub get使用了另一套 SDK 自带的 Dart 和 pub,依赖解析结果随之改变。flutter build能看到的 target 和使用的 Engine 来自错误轨道。
Flutter 官方安装文档说明,PATH 用来让终端找到 Flutter 与 Dart;修改后还要重启终端和 IDE 才能完整生效。它适合配置一套默认 SDK,不适合靠两个同名目录的排序表达本课程的双轨关系。
03 为两套 SDK 各自命名
先在当前终端为 SDK 根目录设置容易辨认的变量。下面的路径是结构示例,必须换成你电脑上的真实路径:
export FLUTTER_UPSTREAM_HOME="$HOME/development/flutter"
export FLUTTER_OH_HOME="$HOME/development/flutter-oh"
这些命令只影响当前终端,不会改 Shell 配置文件。变量指向 SDK 根目录,而不是 bin 目录。
用可执行文件检查路径是否有效:
test -x "$FLUTTER_UPSTREAM_HOME/bin/flutter"
test -x "$FLUTTER_OH_HOME/bin/flutter"
命令没有输出且退出码为 0,只说明对应文件存在并且可以执行,不说明版本正确,也不说明平台工具链完整。路径不存在时,先修正变量;不要继续运行后续命令。
当前课程机器的上游 SDK 实际位于:
/Users/ido/development/flutter/flutter
这是本机记录,不应原样复制到其他电脑。
04 用绝对路径验明 SDK 身份
检查 Track A 时,不运行裸命令 flutter:
"$FLUTTER_UPSTREAM_HOME/bin/flutter" --version
"$FLUTTER_UPSTREAM_HOME/bin/dart" --version
本机于 2026-09-02 使用真实上游路径执行后确认:
Flutter 3.47.2 · channel stable
Dart 3.13.2 · stable · macos_arm64
版本输出还包含 Framework revision、Engine 和 DevTools 等信息;这里只保留判断轨道所需的字段。
Flutter-OH 安装完成后,应使用另一条绝对路径执行同构检查:
"$FLUTTER_OH_HOME/bin/flutter" --version
"$FLUTTER_OH_HOME/bin/dart" --version
"$FLUTTER_OH_HOME/bin/flutter" doctor -v
按本课程当前锁定的 CPF-Flutter release,前两条应能识别 Flutter-OH 3.41.10-ohos-1.0.1 所对应的 Flutter/Dart 版本,doctor -v 还要检查 OpenHarmony toolchain。由于本机没有该 SDK,本篇不提供伪造输出,也不把预期版本当作运行结果。
05 在 Spark 中明确选择轨道
进入项目后,上游轨道的分析与测试命令写成:
cd app
"$FLUTTER_UPSTREAM_HOME/bin/flutter" analyze
"$FLUTTER_UPSTREAM_HOME/bin/flutter" test
iOS 构建仍然明确使用 Track A:
"$FLUTTER_UPSTREAM_HOME/bin/flutter" build ios --simulator
Android 也属于 Track A。当前 Spark 已使用同一上游 SDK 完成:
"$FLUTTER_UPSTREAM_HOME/bin/flutter" run -d <android_device_id>
"$FLUTTER_UPSTREAM_HOME/bin/flutter" build apk --debug
"$FLUTTER_UPSTREAM_HOME/bin/flutter" build appbundle
运行结果、产物和签名边界见第 06 课。这里的 <android_device_id> 必须替换为 flutter devices 的实际输出。
OpenHarmony 命令必须交给 Track B,例如:
"$FLUTTER_OH_HOME/bin/flutter" doctor -v
"$FLUTTER_OH_HOME/bin/flutter" build hap --debug
上面两条只是轨道归属示例,当前不能在 Spark 中执行:本机未安装 Flutter-OH,项目没有 ohos/,配套 DevEco Studio/API 也不满足当前 release 要求。
06 PATH 检查只能检查裸命令
如果教程、终端历史或 IDE 任务仍在使用裸命令,先运行:
command -v flutter
command -v dart
flutter --version
dart --version
command -v 回答“裸命令会执行哪个文件”,绝对路径调用则绕过这次查找。因此:
- 裸命令指向 Track A,不影响你用 Flutter-OH 绝对路径执行检查。
- 裸命令指向 Track B,也不影响你用上游绝对路径执行 iOS 命令。
command -v flutter与flutter --version必须一起看;只有路径,没有版本,仍不足以确认轨道。
本机核验时,裸命令解析为:
/Users/ido/development/flutter/flutter/bin/flutter
它属于 Track A。当前没有第二个 Flutter-OH 路径可供检查。
07 Dart 与依赖不会自动向下兼容
当前 Spark 的 pubspec.yaml 写着:
environment:
sdk: ^3.13.2
Dart 官方文档说明,SDK 约束定义包接受的 Dart 版本范围,pub 会用当前正在运行的 Dart SDK 判断约束能否满足。^3.13.2 不接受 Dart 3.11.5,因此当前 Flutter-OH 基线不能直接为 Spark 解析依赖。
这里不能用三种方式掩盖问题:
- 不要先把约束下调,再假设现有源码和依赖仍然兼容。
- 不要用 Track A 执行
pub get,再拿生成结果证明 Track B 可用。 - 不要只比较 Flutter 版本号,忽略每套 Flutter SDK 自带的 Dart 版本。
未来解除阻塞时,要先审计语言特性与依赖约束,再分别使用两套 SDK 执行依赖解析、静态分析和测试。两条轨道都通过后,才能修改约束并记录共享源码已兼容。
08 终端正确不等于编辑器正确
VS Code、集成终端和普通终端可能在不同时间读取环境。Flutter 官方文档要求在修改 PATH 后重启终端与 IDE,原因正是已启动进程不会自动获得后来修改的环境。
因此切换项目时至少检查:
- 普通终端里的
command -v flutter和版本。 - VS Code 集成终端里的相同命令。
- 实际运行任务输出中的 Flutter 与 Dart 版本。
如果三处结果不一致,先停止构建并统一 SDK 来源。不要用“终端已经正确”推断编辑器任务也正确。本课程当前只用 Track A 打开并运行 Spark;Flutter-OH 编辑器工作流要等环境实际安装后再验证。
预期结果
完成本篇后,上游轨道应能得到明确结果:
- SDK 路径真实存在。
- 绝对路径输出 Flutter 3.47.2 和 Dart 3.13.2。
Spark的分析、测试、iOS 构建、Android 运行与 Android 构建命令明确来自 Track A。
Flutter-OH 轨道当前只能得到边界结论:
- 已记录独立 SDK 路径约定和身份检查命令。
- 本机没有可执行的 Flutter-OH SDK,不能进行版本、doctor、依赖或构建验证。
- 当前
Spark的 Dart 约束不接受 Flutter-OH 配套的 Dart 3.11.5。
常见问题
可以为两套 SDK 分别设置 alias 吗
可以,但 alias 属于 Shell 配置,容易在终端、IDE 和自动化脚本之间产生差异。本课程先使用可直接审计的绝对路径;等两套 SDK 都安装并验证后,再考虑是否增加项目级快捷命令。
为什么不直接使用 Flutter 版本管理工具
当前只需要区分两套固定 SDK,绝对路径已经能解决问题。引入新的版本管理工具会增加安装、网络、配置和维护成本,而且不能消除 Flutter-OH 与 Dart 约束的真实兼容问题。
设置 FLUTTER_UPSTREAM_HOME 算切换 PATH 吗
不算。变量只是保存一个目录字符串;只有运行 export PATH=... 才会改变裸命令的搜索顺序。本篇通过 "$FLUTTER_UPSTREAM_HOME/bin/flutter" 直接选择可执行文件。
两套 SDK 可以共用 pub 缓存吗
不能因为都是 Flutter 就默认安全。两套 SDK 的 Dart 版本、平台补丁和依赖来源可能不同。本课程会在 Flutter-OH 环境可用后验证缓存与依赖策略;本篇不配置或迁移 PUB_CACHE。
为什么不先下调 Spark 的 Dart 约束
SDK 约束是兼容性声明,不是消除错误提示的开关。没有在 Dart 3.11.5 上完成依赖解析、分析和测试,就没有证据证明下调后的声明成立。
command -v 显示正确,为什么 VS Code 仍可能用错
command -v 只检查当前 Shell。VS Code 可能在 PATH 修改前已经启动,也可能使用自己的 SDK 配置。需要在集成终端和实际任务输出中再次核对。
完成检查
- 我能区分项目源码、Flutter SDK 和目标平台。
- 我没有把上游 Flutter 与 Flutter-OH 的
bin同时永久加入PATH。 - 我会同时检查 Flutter 路径、Flutter 版本和 Dart 版本。
- 我知道 iOS/Android 使用 Track A,OpenHarmony 使用 Track B。
- 我知道当前
Spark只能在 Track A 中继续验证。 - 我没有把未执行的 Flutter-OH 命令写成已经通过。
- 我不会在双轨验证前下调
Spark的 Dart 约束。