Flutter Installation Bundles:为 Flutter 仓库构建可离线使用的预缓存安装包
导读
本文以 Flutter 仓库 infra 文档《Flutter-Installation-Bundles》为骨架,系统讲解 Flutter 官方"安装包(Installation Bundle)"的用途、手动构建的完整 10 步流程,以及官方发布所依赖的一键脚本 prepare_package.dart 及其背后的源码实现。读完本文,你将掌握在任意分支(如 master)上从零制作一个预缓存好工具链、pub 依赖与二进制产物的 Flutter 开发环境归档包,并可自行离线解压使用。
什么是 Flutter Installation Bundle
Flutter 官方会针对 beta 频道提供可直接下载安装的"安装包"(此前 dev 频道也提供,但该频道已被并入 master/main 而退休)。这类安装包的设计初衷是:让用户获得一个"完全填充就绪"的 Flutter 环境,而不必先下载 Git 仓库、再现场编译 flutter 工具等。
也就是说,普通从源码搭建 Flutter 环境需要经历"克隆仓库 → 下载 Dart SDK → 构建 flutter 工具快照 → 拉取各包依赖 → 预缓存引擎产物"等一系列联网且耗时的步骤;而安装包把这些步骤全部预先完成并把结果打进归档包,使用者下载解压后即可直接投入离线开发。
从源码结构看,安装包的正式生产工具集中在 dev/bots/prepare_package.dart 及其子模块(common.dart、archive_creator.dart、archive_publisher.dart)中——它就是官方 CI 生成安装包所用的同一套脚本。
手动构建安装包:完整 10 步流程
下面的步骤可在任意 Git 与网络环境可达的机器上执行,官方亦明确表示可以照此流程为 master 分支制作安装包。所有命令的"离线预缓存"意图贯穿始终。
第 0 步(可选):预先决定 pub 缓存位置
PUB_CACHE 环境变量决定 pub 全局缓存放哪。若不设置,pub 会使用默认位置(随操作系统不同而变化,通常在你的主目录下)。
另一种方式:在任意调用 pub 的命令(例如 flutter packages)之前,先创建好 flutter/.pub-cache 目录——flutter 工具会自动探测并使用该目录,这样你就不必在环境中手动导出 PUB_CACHE。
需要说明的是,手动构建流程里 pub 缓存面向"构建方",而面向最终使用者的 pub 依赖预缓存则是安装包内的
.pub-preload-cache目录(详见下文"源码揭秘")。
Windows 专属:安装命令行版 Git
Windows 不自带 Git,请先自行下载并安装一个命令行版 Git,后续的 git clone、git reset 等操作依赖它。
克隆仓库并进入目录
git clone -b master https://github.com/flutter/flutter.git
cd flutter
这会以 master 分支克隆 Flutter Git 仓库到当前目录下的 flutter/ 子目录并进入其中。
将 Flutter 的 bin 目录加入 PATH
-
Windows(CMD):
set PATH="%PATH%;%CD%\bin\flutter"注意此写法把
bin追加进了 PATH,示例字符串本身带\flutter字样属文档原文,实际关键是把仓库内bin目录加入 PATH。 -
其他平台(Linux/macOS):
export PATH="$PATH:$PWD/flutter"
运行 flutter doctor
flutter doctor
它完成两件事:校验安装是否健康,以及构建 flutter 工具的初始快照(首次运行 flutter 命令会下载 Dart SDK 并编译工具自身)。如果它提示缺失 Android SDK、Xcode 工具链等,请按其指示补齐后再继续。
运行 flutter update-packages
flutter update-packages
下载构建 Flutter 主发行版中所有 package 所需的 pub 依赖。其命令实现在 packages/flutter_tools/lib/src/commands/update_packages.dart 中(UpdatePackagesCommand),会自动解析 packages/*、dev/* 等各包的 pubspec.yaml 并统一执行依赖更新。
运行 flutter precache
flutter precache
确保 flutter 工具缓存的二进制产物(引擎 artifacts 等)为最新。flutter doctor 与后续 flutter create 都会触发引擎产物下载,precache 把该做的一次性做全,避免解包后被使用者触发联网下载。
可选:生成 IDE 配置文件
flutter ide-config --overwrite
仅当你要用 IntelliJ、VS Code 等 IDE 打开 Flutter 仓库时才有必要。它会生成/刷新仓库内的 IDE 配置。
预热工程模板(三个模板各建一次)
flutter create --template=app app_sample
flutter create --template=package package_sample
flutter create --template=plugin plugin_sample
在临时目录中分别以 app、package、plugin 三种模板创建示例项目,之后即可删除这些目录。flutter create 会对其自身执行 pub get,从而把"创建新 Flutter 项目"所需的额外依赖也一并预热进 pub 缓存——这正是让解包后的使用者能离线 flutter create 的关键一环。
官方一键方案:直接运行 prepare_package.dart
官方制作安装包并非逐条手工执行上述 10 步,而是运行 dev/bots/prepare_package.dart 脚本自动完成。任何人都可以调用它:
-
先推进到上文"
flutter doctor"那一步(如果已有一个可用的 Flutter 仓库,可以跳过——它来自其他频道也可以,但建议用较新版本以保证兼容); -
在 flutter 仓库根目录执行:
./bin/cache/dart-sdk/bin/dart ./dev/bots/prepare_package.dart --temp_dir $TMPDIR --revision $REVISION --branch master --output $PWD其中:
TMPDIR指向一个有数 GB 空闲空间的目录(构建过程会写入几 GiB 临时数据);REVISION是你要构建的目标修订版的 40 位完整 Git hash。
执行完毕后,当前目录会生成一个已经完成上述所有预热步骤、且包含 master 分支内容的归档包。
prepare_package.dart 全部命令行参数
结合 dev/bots/prepare_package.dart 的源码,脚本支持的参数如下:
| 参数 | 类型 | 说明 | 默认值 / 约束 |
|---|---|---|---|
--temp_dir |
选项 | 临时文件写入位置,会写入数 GiB 数据,需足够空闲空间 | 系统临时目录,用后自动创建并删除 |
--revision |
选项 | 要打包的 Git 修订版 hash | 必填;必须是完整 40 位 hash,不接受前缀 |
--branch |
选项 | 要打包的分支 | 必填;取值限于 Branch 枚举:beta、stable、master、main |
--output |
选项 | 归档包输出目录,不存在会自动递归创建 | 当前目录 |
--publish |
标志 | 成功后把归档上传到 Google Cloud Storage | 默认关闭 |
--target_arch |
选项 | 目标 CPU 架构 | 默认取构建机本机架构;取值 x64、arm64 |
--force / -f |
标志 | 覆盖云端已存在的同名归档 | 默认关闭 |
--dry_run |
标志 | 只打印 gsutil 命令而不真正执行上传 | 默认关闭 |
--help |
标志 | 打印帮助后退出 | — |
Branch 与 TargetArch 枚举定义在 dev/bots/prepare_package/common.dart。注意:虽然安装包当前只针对 beta 频道发布,但脚本本身对 stable、master、main 同样可用——文档明确说明可以照此流程为 master 分支构建。
脚本内部的工作流程
dev/bots/prepare_package.dart 的 main() 构造 ArchiveCreator 并依次调用:
creator.initializeRepo():克隆并准备仓库(见下文);creator.createArchive():填缓存、校验、打归档包;- 若指定
--publish,构造ArchivePublisher上传并更新发布元数据,否则调用generateLocalMetadata()生成本地元数据文件。
每一步若抛 PreparePackageException 都会以非零码退出并打印友好错误,随后按需清理临时目录。
源码级揭秘:安装包是怎么"预热"出来的
仓库初始化:clone → reset → 换源 → gc
ArchiveCreator._checkoutFlutter()(见 archive_creator.dart)执行:
git clone -b <branch> https://flutter.googlesource.com/mirrors/flutter:从 Chromium 镜像克隆指定分支(比 GitHub 更快更稳);git reset --hard <revision>:把工作区精确复位到目标 40 位 hash,保证归档内容与修订版一一对应;git remote set-url origin https://github.com/flutter/flutter.git:把 origin 改回 GitHub,方便解包者日后flutter upgrade/push;git gc --prune=now --aggressive:精简.git体积(源码注释指出约可省 100 MB)。
此外在 _populateCaches() 末尾,还会用 git clean -f -x 清掉各项目的 .packages 与 .dart_tool/(已 check-in 的除外),并删除 .pub-cache/git 下的 git 依赖缓存——保证归档内缓存干净、体积可控。
缓存预热命令序列
_populateCaches()(archive_creator.dart)内部实际执行的命令与手动 10 步一一对应:
flutter doctor;flutter update-packages;flutter precache(若指定--target_arch会追加--host-arch=<arch>);flutter ide-config;- 对
app、package、plugin三个模板分别执行flutter create --template=...(在临时目录执行,避免把嵌套 git 仓库打进归档); _downloadPubPackageArchives():把当前 pub 缓存里每个 package 的.tar.gz归档下载到$flutterRoot/.pub-preload-cache,供解包后首次使用时自动装入用户级缓存。下载带 SHA-256 校验、并发 10、单包最多重试 7 次(archive_creator.dart)。
--target_arch 的跨架构打包原理:通过设置 FLUTTER_HOST_ARCH 环境变量,让 bin/internal/update_dart_sdk.sh/.ps1(打的是被打包分支中的脚本)下载对应架构的 Dart SDK,进而让 flutter 命令缓存对应架构的引擎产物。脚本会做"paranoid check":比对实际下载的 Dart SDK 架构与请求的 target_arch 是否一致,不一致直接抛错(archive_creator.dart)。这正是 CI 上"在 arm64 主机交叉打包 x64 归档"的实现基础。
版本信息与命名规则
_getVersion()(archive_creator.dart)通过 git describe 找版本 tag(strict 模式下要求 revision 恰好命中 tag),再以 flutter --version --machine 取 JSON 版本信息,合并进 frameworkVersionFromGit、dartSdkVersion、dartTargetArch 等字段。
归档文件名由 _archiveName 生成(archive_creator.dart),形如 flutter_<os>_<version>-<branch>.<suffix>,其中:
- x64 架构文件名不带架构后缀,arm64 等则以
arm64_前缀标注; - macOS 用
.zip(Archive Utility双击解压.tar.xz的行为异常),Linux 用.tar.xz; - Windows 归档打包含额外步骤:先下载 MinGit 到
bin/mingit,压缩时先attrib -h .git再以 7za 极值压缩(-mx=9)。
发布流程(可选)
ArchivePublisher(archive_publisher.dart)在 --publish 时把归档上传到 gs://flutter_infra_release/releases/<branch>/<os>/...,并通过 transactionalUpdate 以"读-改-写"事务方式更新发布元数据 JSON(releases_<os>.json)。每条发布记录包含 hash、channel、version、dart_sdk_version、dart_sdk_arch、release_date、archive 与 sha256(archive_publisher.dart);无 --publish 时则把同样的元数据写到本地文件便于人工检查。上传与元数据更新前会先 rm 目标(失败可容忍)并用正确 MIME 头与 Cache-Control 控制缓存。
质量门禁
strict 模式(即 --publish 且非 --dry_run)下,在 macOS 打包会执行 codesign -vvvv --check-notarization 校验 Dart 二进制已签名(archive_creator.dart),不通过则拒绝出包。测试覆盖见 dev/bots/test/prepare_package_test.dart。
与发布频道的对应关系
安装包按频道发布,而 Flutter 官方渠道定义在 docs/releases/Flutter-build-release-channels.md,按稳定性递增依次为 master(别名 main,tip-of-tree)、beta(最新稳定候选)、stable(面向生产)。当前安装包面向 beta 频道发布,而脚本与文档均支持你为任意分支自行构建——若你以 flutter channel 查看,通常看到的就是 master/beta/stable 三个分支的切换。
实践建议与注意事项
- 磁盘空间:无论手动流程还是
prepare_package.dart,预热过程会占用数 GiB 临时空间,请为临时目录预留充足容量; - revision 必须完整:
--revision只接受 40 位完整 hash,用短 hash 或分支名会直接报错退出; - Windows 前置:Windows 需先装命令行 Git;打包 Windows 归档时脚本会自动下载并嵌入 MinGit;
- 离线使用:解包后首次运行 flutter 命令会把
.pub-preload-cache中的依赖自动装入用户级缓存,因此尽量在联网状态正常的机器上执行构建,以获得真正"开箱即用"的离线包; - 本机跑通验证:若对产出物不放心,可参考 dev/bots/test/prepare_package_test.dart 了解脚本的测试注入点(如假
HttpReader、假ProcessManager),理解各阶段行为后再做定制。
通过本文,你既掌握了逐条手工预热 Flutter 仓库的完整命令序列,也理解了官方 prepare_package.dart 的内部机理与全部参数,足以在本地复刻一条可靠的 Flutter 安装包生产线。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00