dsh-flutter-dev
把 Flutter 开发环境随插件一起装进 DeepSeek Harness:插件目录里自带 Flutter SDK、Temurin JDK、Android SDK(含 NDK 与 CMake)与国内镜像配置,装上就能建项目、出 APK——不读用户已装的 SDK,不改用户环境变量,也不需要用户配任何路径。
每次构建/校验前,插件还会自检「目录与关键 exe 的完整性级别」和「SDK 内 CMake」这两项换机器就会重新出现的前提,坏了自动修(见 §5)。
装好之后在对话里直接说「建一个 Flutter 项目 todo_app,出个 release APK」,模型就能连续调用本插件的工具完成。
仓库版说明:GitHub 上只有源码,
runtime/(8.9 GB 自带 SDK)不入库;克隆后按 §7 的「从 GitHub 克隆后怎么用」补出运行时。
1. 它装了什么(实测体积)
| 目录 | 内容 | 体积 |
|---|---|---|
runtime/flutter |
Flutter SDK 3.47.4(stable,含 .git 与 bin/cache 全套 artifacts) |
3.2 GB |
runtime/jdk |
Temurin JDK 21.0.12.1+1 | 329 MB |
runtime/android-sdk |
platform-tools、platforms(34~37)、build-tools(34、36)、NDK 28.2.13676358、CMake 3.22.1(含 ninja)、licenses | 约 3.1 GB(NDK 占 2.2 GB,CMake 43 MB) |
runtime/gradle-home |
GRADLE_USER_HOME:镜像 init 脚本 + 依赖缓存(做过一次构建后的量) |
2.4 GB |
runtime/pub-cache |
PUB_CACHE |
49 MB |
runtime/sys、runtime/android-user |
APPDATA / LOCALAPPDATA / TEMP、.android 的重定向目标 |
~1.2 MB |
合计约 9 GB。其中 runtime/gradle-home 的 2.4 GB 是构建缓存:删掉可退回约 6.6 GB,代价是首次构建重新下载依赖(约 5 分钟)。
NDK 不是可选项:Flutter 3.47 的 Android 模板写死
ndkVersion = flutter.ndkVersion,AGP 9 在配置阶段就校验该目录,缺了直接NDK not configured失败。
2. 快速开始
对话里直接说:
- 「建一个 Flutter 项目
todo_app,出个 release APK」 - 「帮这个项目 analyze + test」
- 「给它加上
http和provider依赖」
模型会依次调用 flutter_create → flutter_build / flutter_check / flutter_pub。
3. 工具清单
| 工具 | 作用 | 关键参数 |
|---|---|---|
flutter_env |
查看/校验自带环境 | action: status(默认)/ doctor / env / prepare |
flutter_create |
创建项目 | name、parentDir、org、platforms、template |
flutter_build |
构建并返回产物绝对路径与体积 | projectPath、target(apk/appbundle/web/windows/linux/macos)、release、splitPerAbi、dartDefine、clean |
flutter_check |
pub get + analyze + test | projectPath、steps |
flutter_pub |
依赖管理 | projectPath、action(get/add/remove/upgrade)、packages、dev |
flutter_devices |
列出设备与模拟器 | — |
projectPath 留空时默认用当前会话工作目录,所以多数时候只需要给 name 或 target。
想在终端里自己跑热重载
本插件不提供 flutter run(长驻交互进程)。需要热重载时:
- 调
flutter_env,action=env(可加shell=bash); - 把返回的环境变量脚本粘到 PowerShell / Git Bash;
- 之后终端里的
flutter就指向插件自带 SDK,flutter run直接可用。
4. 环境隔离:为什么不冲突、不污染
每次执行 Flutter 命令,插件都会重建一份子进程环境(见 lib/env.js):
| 变量 | 值 | 为什么 |
|---|---|---|
PATH |
前置 runtime/flutter/bin、runtime/jdk/bin、platform-tools |
不依赖用户 PATH |
JAVA_HOME |
runtime/jdk |
不依赖用户 JDK |
ANDROID_HOME / ANDROID_SDK_ROOT |
runtime/android-sdk |
同上 |
ANDROID_USER_HOME |
runtime/android-user |
AGP 把 debug.keystore 放用户 ~/.android,写用户目录被拒时签名阶段直接 AccessDeniedException |
GRADLE_USER_HOME / PUB_CACHE |
runtime/gradle-home / runtime/pub-cache |
缓存与镜像脚本都关在插件里 |
APPDATA / LOCALAPPDATA / TEMP / TMP / TMPDIR |
runtime/sys/** |
绕开用户目录写入限制(实测 %APPDATA%\.dart-tool 不可写时 Flutter 会在真正报错前先抛 FileSystemException errno 5,掩盖真因) |
PUB_HOSTED_URL / FLUTTER_STORAGE_BASE_URL / SDK_TEST_BASE_URL |
国内镜像 | pub、engine、sdkmanager 都走镜像 |
FLUTTER_SUPPRESS_ANALYTICS / DART_SUPPRESS_ANALYTICS |
true |
关遥测,避免首跑卡住 |
5. 构建前提:Gradle 镜像、完整性级别、CMake
lib/gradle.js 在自带 GRADLE_USER_HOME/init.d/ 写入一个 init 脚本,做两件事:
- 摘掉
dl.google.com/maven.google.com(本机实测这两个域名是连接超时,不是慢。留着会让所有依赖解析卡到超时); - 在 pluginManagement、settings 级 与 每个项目的 buildscript / repositories 三处追加镜像:阿里云 google / public / gradle-plugin +
${FLUTTER_STORAGE_BASE_URL}/download.flutter.io(Flutter 引擎构件io.flutter:*-release只在这个仓库)。
三处缺一不可,都是实测踩出来的:
| 只改了 | 结果 |
|---|---|
| settingsEvaluated | settings.gradle.kts 的 plugins{} 即时解析,AGP 9.1.0 找不到 |
| settings 级 | Flutter 3.47 新模板没有 dependencyResolutionManagement,依赖走项目级仓库 |
| 主构建 | includeBuild(flutter_tools/gradle) 的复合构建另有仓库配置,Kotlin 依赖仍去 dl.google.com |
另外,构建前会把项目 gradle-wrapper.properties 的 distributionUrl 临时指向 mirrors.cloud.tencent.com/gradle,构建结束(成功或失败)立刻还原。
5.2 完整性级别:低标签会让一切写操作失败
| 你看到的现象 | 真正原因 |
|---|---|
dart.exe 报 PathAccessException … errno 5;Gradle 报 AccessDeniedException: debug.keystore.lock |
插件目录被打成 Low,从它启动的子进程一律继承低完整性 |
目录已是 Medium、icacls 看着正常,构建却仍报 java.io.IOException: 拒绝访问(栈里是 WelcomeMessageAction.writeMarkerFile / createFileExclusively) |
关键 exe 自己残留 Low 标签,从低标签 exe 启动的进程会被降级 |
Could not create service of type DaemonDir、Unable to establish loopback connection |
上一轮的 daemon 带着旧标签还在跑,或 registry 已脏 |
插件在每次构建/校验前自检(lib/platform.js,结果按 probeCacheMs 缓存),发现阻断项就自动修:
- 目录:
icacls <dir> /setintegritylevel "Medium:(OI)(CI)",复检仍阻断才加/T递归; - 关键 exe 逐个查:
java.exe、dart.exe、adb.exe、cmake.exe——只查目录不够(见上表第二行,本轮实测踩过:目录Medium、java.exe仍Low,构建全挂); - 修完顺手清掉
gradle-home/daemon与notifications,让下一次构建起干净的 daemon; - 也可手动触发:
flutter_env action=prepare;构建日志里出现「拒绝访问 / errno 5」时,flutter_build会直接给出这条修复建议。
5.3 CMake
Flutter 3.47 + AGP 9 下,只要依赖里有一个带 native 构建的包(实测由 pubspec.lock 里的传递依赖触发),AGP 就要求 SDK 内的 CMake,缺了直接失败:
[CXX1300] CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property
因此 runtime/android-sdk/cmake/3.22.1/(43 MB,含 ninja.exe)必须随插件带上;scripts/build-runtime.mjs 已不再排除 cmake。
6. 配置项
在 profile 的 cordis.patch.yml 里用 id flutter-dev 覆盖 config,全部字段有默认值:
| 字段 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关 |
flutterSdkPath / javaHomePath / androidSdkPath |
空(用 runtime/) |
想改用自己的 SDK 时填绝对路径 |
gradleUserHome / pubCache |
空(用 runtime/) |
同上 |
pubHostedUrl / flutterStorageBaseUrl / androidRepositoryBase |
见 §4 | 镜像覆盖 |
mavenMirrors |
阿里云 google / public / gradle-plugin | Gradle 依赖镜像 |
gradleMirror |
true |
是否启用 §5 的 Gradle 镜像处理 |
buildTimeoutMs |
1800000(30 分钟) | 构建超时 |
commandTimeoutMs |
600000(10 分钟) | create/pub/check 超时 |
probeCacheMs |
300000(5 分钟) | 版本探测缓存 |
7. 分发与迁移
- 用
plugin_manager的install_bundle安装,target填本目录绝对路径(本地目录走 link,不会复制 9 GB)。 - 想让另一台机器同样「装上就有环境」:把整个插件目录(含
runtime/)拷过去再装(压缩后传输更快)。 - npm 的
files白名单不含runtime/,避免把 9 GB 推到 registry;runtime/只随本地目录分发。 - 重建 runtime:
node scripts/build-runtime.mjs --flutter <SDK> --jdk <JDK> --android <SDK>(保留cmake与 NDK,只排除emulator/system-images/.temp/sources/tools)。
从 GitHub 克隆后怎么用
仓库只含源码(约 100 KB),不含 runtime/——它 8.9 GB,远超 GitHub 的单文件(100 MB)与仓库体积限制,因此写进了 .gitignore。克隆后按下面三步补出运行时:
准备三份 SDK(本机以前装过 Flutter / Android 就可以直接复用现成的):
- Flutter SDK 3.47.x(必须包含
bin/cache,离线构建靠它) - Temurin JDK 21
- Android SDK:
platform-tools、platforms、build-tools、NDK 28.2.13676358、CMake 3.22.1
- Flutter SDK 3.47.x(必须包含
生成
runtime/:node scripts/build-runtime.mjs \ --flutter 'F:\flutter_sdk\flutter' \ --jdk 'F:\jdk21\jdk-21.0.12.1+1' \ --android 'F:\android_sdk'装进 profile 并自检:
plugin_manager → install_bundle,target = 本目录绝对路径 flutter_env action=prepare # 报告缺什么;顺手修目录/关键 exe 的完整性标签
8. 已知限制
- 没有
flutter run(热重载是长驻交互进程),需要时用 §3 的action=env在终端里跑。 - 只带 Windows 版 Flutter SDK:
macos/ios目标在当前 runtime 上不可用;windows桌面目标另需本机 Visual Studio C++ 工具链。 - CMake 已带 3.22.1(AGP 9 默认要求)。若某个项目显式要求别的 CMake 版本,需要把对应版本再补进
runtime/android-sdk/cmake/。 runtime/gradle-home的缓存会长大;runtime/android-sdk里的 NDK 只在 AGP 校验路径时需要。
9. 验证记录(2026-10-31 ~ 11-01,本机 Windows)
| 项 | 结果 |
|---|---|
node test/selftest.mjs |
36/36 通过(引号规则、输出截断、env 合成、镜像改写、Config 校验、完整性标签解析、CMake 探测、失败诊断) |
flutter_env action=status |
Flutter 3.47.4 / Dart 3.13.3 / JDK 21.0.12.1 / build-tools 36.0.0 / platforms 34~37 全部 ✅ |
flutter_create(工具调用) |
2.6 秒建出 todo_app(android + web) |
flutter_check(工具调用) |
pub 1.5s / analyze 14.7s / test 8.9s 全绿 |
flutter_pub add http provider(工具调用) |
2.2 秒成功(走 pub 镜像) |
flutter_build target=apk(工具调用,新建项目) |
39.6 秒产出 app-release.apk,42.1 MB |
flutter_build(已构建项目,缓存热) |
9.0 秒 |
flutter_devices |
正常返回(本机无连接设备) |
真实项目 douyin download/flutter_app(依赖里有 native 包) |
缺 CMake 时报 [CXX1300] CMake '3.22.1' was not found;把 CMake 补进 runtime 后构建通过(53.9 MB APK) |
只把 java.exe / dart.exe 设成 Low(目录保持 Medium) |
flutter_env action=prepare 自行查出并修复这两个 exe;随后 flutter_build 8.6 秒出包 |
10. 目录结构
flutter/
├── lib/
│ ├── index.js 插件入口:Config + 6 个工具注册
│ ├── runtime.js runtime/ 路径布局
│ ├── env.js 子进程环境合成(隔离 + 镜像)
│ ├── runner.js 命令执行(Windows 引号规则、超时、进程树清理、输出截断)
│ ├── probe.js 环境探测(版本、Android SDK 结构)
│ ├── project.js create / build / check / pub / devices
│ ├── gradle.js Gradle 三处镜像 + wrapper 镜像临时改写
│ ├── platform.js 构建前提自检:完整性级别(目录 + 关键 exe)与 CMake
│ ├── mirrors.js 国内镜像常量(均已实测可达)
│ └── format.js 中文渲染
├── runtime/ 自带 SDK(不随 npm 发布)
├── scripts/build-runtime.mjs
├── test/selftest.mjs
├── cordis.patch.yml
└── package.json
许可
MIT
No comments yet. Be the first to write one.