快速开始 - 操作流程总览
项目目录结构
/Users/wangjinshan/Documents/writer/
├── android/ # Android项目文件
├── ios/ # iOS项目文件
├── flutter_sdk/ # Flutter Engine源码(Mac/Docker共享)
├── writer_build_engin_shell/ # 构建脚本和Docker配置
│ ├── docker_shell_build/ # Docker构建文件
│ │ ├── Dockerfile # Docker镜像定义
│ │ └── scripts/ # 容器脚本
│ └── md/ # 文档目录
└── writer-flutter/ # Flutter应用项目
第一步:安装 Docker Desktop
# 1. 下载并安装 Docker Desktop for Mac
# 从官网下载: https://www.docker.com/products/docker-desktop
# 2. 验证安装
docker --version
docker-compose --version
第二步:创建基础 Docker 镜像(仅提供Linux环境)
# 进入Docker构建目录
cd ~/Documents/writer/writer_build_engin_shell/docker_shell_build
# 创建最简Docker镜像(只有Linux系统)
cat > Dockerfile << 'EOF'
# 明确指定平台为 linux/amd64,提供纯净Linux环境
FROM --platform=linux/amd64 mirrors.tencent.com/ci/tlinux3_ci:latest
# 设置默认工作目录
WORKDIR /writer/flutter_sdk
# 镜像只提供Linux环境,不安装任何工具
CMD ["/bin/bash"]
EOF
第三步:构建 Docker 镜像
# 构建纯净Linux镜像
docker build -t flutter-engine-linux .
# 验证镜像(应该很小,只包含Linux系统)
docker images | grep flutter-engine-linux
第四步:创建 Docker 容器(关键:卷挂载实现文件共享)
容器创建和命名详解
# 第一次创建容器时,需要指定容器名称
# 这里我们创建一个名为 flutter_sync_dev 的容器
docker run -it \
--name flutter_sync_dev \
-v /Users/wangjinshan/Documents/writer/flutter_sdk:/writer/flutter_sdk \
-v /depot_tools:/depot_tools \
flutter-engine-linux bash
# 解释:
# --name flutter_sync_dev # 给容器命名为 flutter_sync_dev
# -v 路径1:路径2 # 卷挂载,实现文件共享
# flutter-engine-linux # 使用的镜像名
# bash # 启动后执行的命令
容器状态管理
# 第一次创建后,容器就存在了,可以查看
docker ps -a | grep flutter_sync_dev
# 输出示例:
# CONTAINER ID IMAGE STATUS NAMES
# abc123def456 flutter-engine-linux Up flutter_sync_dev
# 如果容器停止了,可以重新启动
docker start flutter_sync_dev
# 如果容器正在运行,可以直接进入
docker exec -it flutter_sync_dev bash
第一次创建 vs 后续使用
# 第一次创建容器(只需要执行一次)
docker run -it \
--name flutter_sync_dev \
-v /Users/wangjinshan/Documents/writer/flutter_sdk:/writer/flutter_sdk \
-v /depot_tools:/depot_tools \
flutter-engine-linux bash
# 容器创建后,后续使用只需要:
# 1. 启动容器(如果停止了)
docker start flutter_sync_dev
# 2. 进入容器
docker exec -it flutter_sync_dev bash
容器生命周期管理
# 查看容器状态
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(包括停止的)
# 容器操作
docker start flutter_sync_dev # 启动容器
docker stop flutter_sync_dev # 停止容器
docker restart flutter_sync_dev # 重启容器
docker rm flutter_sync_dev # 删除容器(会丢失容器内的配置)
# 如果容器被删除了,需要重新创建
docker run -it --name flutter_sync_dev \
-v /Users/wangjinshan/Documents/writer/flutter_sdk:/writer/flutter_sdk \
-v /depot_tools:/depot_tools \
flutter-engine-linux bash
第五步:在容器内配置所有开发环境
进入容器的不同方式
# 方式1:创建容器的同时进入(第一次)
docker run -it --name flutter_sync_dev \
-v /Users/wangjinshan/Documents/writer/flutter_sdk:/writer/flutter_sdk \
-v /depot_tools:/depot_tools \
flutter-engine-linux bash
# 方式2:进入已存在的容器(常用)
docker exec -it flutter_sync_dev bash
# 方式3:启动并进入容器(如果容器停止了)
docker start flutter_sync_dev && docker exec -it flutter_sync_dev bash
容器内环境配置
# 现在我们在 flutter_sync_dev 容器内
# 容器内安装所有必需工具
apt-get update && apt-get install -y \
curl git python3 python3-pip build-essential \
pkg-config libnss3-dev libatk-bridge2.0-dev
# 配置环境变量(在容器内执行)
export PATH="/depot_tools:$PATH"
export DEPOT_TOOLS_UPDATE=0
# 验证工具(在容器内执行)
which gclient gn ninja
# 检查卷挂载是否成功
ls -la /writer/flutter_sdk # 应该能看到Mac上的文件
为什么使用 flutter_sync_dev 这个名字?
# 容器命名的考虑:
# flutter_sync_dev = flutter + sync + dev
# flutter: 项目名称
# sync: 主要用途是同步和编译
# dev: 开发环境
# 您也可以使用其他名字,比如:
docker run -it --name flutter-engine-container ...
docker run -it --name my-flutter-dev ...
docker run -it --name flutter-build-env ...
# 重要的是保持一致,后续都用同一个名字
实际使用流程示例
# === 第一天开发 ===
# 1. 创建容器
docker run -it --name flutter_sync_dev \
-v /Users/wangjinshan/Documents/writer/flutter_sdk:/writer/flutter_sdk \
-v /depot_tools:/depot_tools \
flutter-engine-linux bash
# 2. 在容器内配置环境
apt-get update && apt-get install -y curl git python3 build-essential
export PATH="/depot_tools:$PATH"
# 3. 退出容器
exit
# === 第二天开发 ===
# 1. 直接进入已存在的容器
docker exec -it flutter_sync_dev bash
# 2. 环境变量可能需要重新设置
export PATH="/depot_tools:$PATH"
export DEPOT_TOOLS_UPDATE=0
# 3. 开始工作
cd /writer/flutter_sdk
gclient sync
详细说明目录
- 2.1 Docker核心概念正确理解
- 2.2 Mac与Docker文件系统共享策略
- 2.3 Docker镜像设计原则
- 2.4 容器环境配置详解
- 2.5 Mac与Linux环境切换机制
- 2.6 环境清理与重置脚本
- 2.7 项目目录结构详解
- 2.8 蓝盾流水线集成准备
2.1 Docker核心概念正确理解
Images vs Container 的本质区别
Images(镜像)- 只提供Linux环境
# 镜像是静态的、只读的Linux系统模板
# 我们的设计:镜像只包含纯净的Linux系统,不包含任何开发工具
# 查看镜像(应该很小,只有Linux系统)
docker images flutter-engine-linux
# REPOSITORY TAG IMAGE ID CREATED SIZE
# flutter-engine-linux latest abc123def456 2 hours ago 500MB
Container(容器)- 真正的运行环境
# 容器是镜像的运行实例,是真正的执行环境
# 我们的设计:所有工具、配置、环境变量都在容器中设置
# 查看运行中的容器
docker ps
# CONTAINER ID IMAGE STATUS NAMES
# def456abc789 flutter-engine-linux Up flutter-engine-container
为什么镜像不放工具?
- 灵活性: 不同项目可能需要不同版本的工具
- 体积: 镜像越小,构建和分发越快
- 维护: 工具更新不需要重新构建镜像
- 一致性: 通过卷挂载确保Mac和Docker使用完全相同的文件
# 错误的做法(不要这样)
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
git python3 build-essential # ❌ 镜像变大,不灵活
# 正确的做法
FROM --platform=linux/amd64 mirrors.tencent.com/ci/tlinux3_ci:latest
WORKDIR /writer/flutter_sdk
CMD ["/bin/bash"] # ✅ 镜像小,纯净Linux环境
2.2 Mac与Docker文件系统共享策略
核心设计思想:同一个内存文件夹
文件系统架构图
┌─────────────────────────────────────────────┐
│ macOS 宿主机 │
│ /Users/wangjinshan/Documents/writer/ │
│ ├── flutter_sdk/ ←─┐ │
│ ├── writer_build_engin_shell/ │ │
│ └── android/ │ │
└─────────────────────────────────┼────────────┘
│ Docker卷挂载
┌─────────────────────────────────┼────────────┐
│ Docker 容器 │ │
│ /writer/flutter_sdk/ ←───┘ │
│ ├── .gclient │
│ ├── flutter/ │
│ ├── out/ │
│ └── third_party/ │
└─────────────────────────────────────────────┘
卷挂载详细配置
完整的卷挂载脚本
#!/bin/bash
# 文件名:run_container.sh
# 用途:启动Docker容器并正确挂载卷
set -e
# 项目根目录
WRITER_ROOT="/Users/wangjinshan/Documents/writer"
FLUTTER_SDK_DIR="$WRITER_ROOT/flutter_sdk"
DEPOT_TOOLS_DIR="/depot_tools"
# 容器配置
CONTAINER_NAME="flutter-engine-container"
IMAGE_NAME="flutter-engine-linux"
echo "=== 启动Flutter Engine Docker容器 ==="
echo "项目根目录: $WRITER_ROOT"
echo "Flutter SDK: $FLUTTER_SDK_DIR"
# 检查目录是否存在
if [ ! -d "$FLUTTER_SDK_DIR" ]; then
echo "错误: Flutter SDK目录不存在: $FLUTTER_SDK_DIR"
echo "请先完成第一章的环境配置"
exit 1
fi
# 停止并删除已存在的容器
if docker ps -a | grep -q "$CONTAINER_NAME"; then
echo "清理已存在的容器..."
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
fi
# 启动容器,关键:卷挂载实现文件共享
echo "启动新容器..."
docker run -it \
--name "$CONTAINER_NAME" \
--hostname flutter-linux \
-v "$FLUTTER_SDK_DIR:/writer/flutter_sdk" \
-v "$DEPOT_TOOLS_DIR:/depot_tools" \
-v "$WRITER_ROOT/writer_build_engin_shell:/writer/scripts" \
--workdir="/writer/flutter_sdk" \
--memory=8g \
--cpus=4 \
"$IMAGE_NAME"
echo "容器已启动,文件系统已共享"
文件共享验证
验证Mac和Docker是否真正共享文件
# 在Mac上创建测试文件
echo "Hello from Mac" > ~/Documents/writer/flutter_sdk/mac_test.txt
# 在Docker容器内查看
docker exec flutter-engine-container cat /writer/flutter_sdk/mac_test.txt
# 输出: Hello from Mac
# 在Docker容器内创建文件
docker exec flutter-engine-container sh -c 'echo "Hello from Docker" > /writer/flutter_sdk/docker_test.txt'
# 在Mac上查看
cat ~/Documents/writer/flutter_sdk/docker_test.txt
# 输出: Hello from Docker
2.3 Docker镜像设计原则
最小化镜像设计
我们的Dockerfile(极简设计)
# 文件名:Dockerfile
# 位置:~/Documents/writer/writer_build_engin_shell/docker_shell_build/Dockerfile
# 使用腾讯云镜像,确保平台兼容性
FROM --platform=linux/amd64 mirrors.tencent.com/ci/tlinux3_ci:latest
# 设置基本环境变量
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
# 设置工作目录(与Mac卷挂载路径一致)
WORKDIR /writer/flutter_sdk
# 不安装任何工具,保持镜像纯净
# 所有工具将在容器运行时安装
# 默认启动bash
CMD ["/bin/bash"]
为什么不在镜像中预装工具?
对比说明
# ❌ 错误做法:镜像臃肿,不灵活
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
git curl python3 build-essential \
pkg-config libnss3-dev
# 问题:
# 1. 镜像体积大(2GB+)
# 2. 工具版本固定,难以更新
# 3. 不同项目可能需要不同工具版本
# ✅ 正确做法:镜像纯净,运行时安装
FROM --platform=linux/amd64 mirrors.tencent.com/ci/tlinux3_ci:latest
WORKDIR /writer/flutter_sdk
CMD ["/bin/bash"]
# 优点:
# 1. 镜像体积小(500MB)
# 2. 工具版本灵活
# 3. 容器启动快
2.4 容器环境配置详解
容器内完整环境配置
一键环境配置脚本
#!/bin/bash
# 文件名:setup_container_env.sh
# 位置:~/Documents/writer/writer_build_engin_shell/docker_shell_build/scripts/
# 用途:在Docker容器内配置所有开发环境
set -e
echo "=== Docker容器环境配置 ==="
# 检查是否在容器内
if [ ! -f /.dockerenv ]; then
echo "错误: 此脚本只能在Docker容器内运行"
exit 1
fi
# 更新系统包
echo "1. 更新系统包..."
apt-get update
# 安装基础工具
echo "2. 安装基础开发工具..."
apt-get install -y \
curl \
wget \
git \
vim \
unzip \
python3 \
python3-pip \
python3-setuptools
# 安装编译工具链
echo "3. 安装编译工具链..."
apt-get install -y \
build-essential \
clang \
cmake \
ninja-build
# 安装Flutter Engine特定依赖
echo "4. 安装Flutter Engine依赖..."
apt-get install -y \
pkg-config \
libnss3-dev \
libatk-bridge2.0-dev \
libdrm-dev \
libxkbcommon-dev \
libgtk-3-dev \
libgles2-mesa-dev
# 清理包缓存
echo "5. 清理缓存..."
apt-get clean
rm -rf /var/lib/apt/lists/*
# 配置depot_tools环境变量
echo "6. 配置depot_tools..."
if [ -d "/depot_tools" ]; then
echo 'export PATH="/depot_tools:$PATH"' >> ~/.bashrc
echo 'export DEPOT_TOOLS_UPDATE=0' >> ~/.bashrc
export PATH="/depot_tools:$PATH"
export DEPOT_TOOLS_UPDATE=0
echo "✓ depot_tools 配置完成"
else
echo "⚠ depot_tools 目录不存在,请检查卷挂载"
fi
# 配置Git
echo "7. 配置Git..."
git config --global user.name "Flutter CI"
git config --global user.email "ci@flutter.dev"
git config --global init.defaultBranch main
git config --global safe.directory '*'
# 验证环境
echo "8. 验证环境..."
echo "Python: $(python3 --version)"
echo "Git: $(git --version)"
if command -v gclient &> /dev/null; then
echo "gclient: $(gclient --version)"
else
echo "⚠ gclient 未找到"
fi
echo "=== 容器环境配置完成 ==="
容器内环境配置示例
# 进入容器
docker exec -it flutter-engine-container bash
# 执行环境配置脚本
bash /writer/scripts/setup_container_env.sh
# 手动验证工具安装
which gclient
which gn
which ninja
2.5 Mac与Linux环境切换机制
环境切换的核心问题
为什么需要清理?
- 编译产物不兼容: Mac和Linux的编译产物二进制格式不同
- 工具版本差异: Mac和Linux可能使用不同版本的构建工具
- 路径差异: 绝对路径在不同系统下不同
- 权限问题: 文件所有者和权限在两个系统间可能冲突
需要清理的内容详解
清理内容清单
# 1. 编译产物目录
out/ # 所有编译输出
build/ # 构建配置文件
# 2. 工具生成的缓存
.gclient_entries # gclient状态文件
.cipd/ # CIPD工具缓存
buildtools/ # 构建工具(平台相关)
# 3. Python字节码
**/__pycache__/ # Python缓存文件
**/*.pyc # Python编译文件
# 4. Git工作区状态
flutter/.git/index # Git索引文件
third_party/*/.git/index # 第三方仓库索引
# 5. 临时文件
tmp/ # 临时目录
*.tmp # 临时文件
*.log # 日志文件
环境切换脚本
智能环境切换脚本
#!/bin/bash
# 文件名:switch_environment.sh
# 位置:~/Documents/writer/writer_build_engin_shell/
# 用途:在Mac和Linux环境间切换时清理不兼容内容
set -e
FLUTTER_SDK_DIR="$HOME/Documents/writer/flutter_sdk"
CURRENT_ENV_FILE="$FLUTTER_SDK_DIR/.current_env"
# 检测当前环境
detect_environment() {
if [ -f /.dockerenv ]; then
echo "linux"
else
echo "mac"
fi
}
# 获取上次使用的环境
get_last_environment() {
if [ -f "$CURRENT_ENV_FILE" ]; then
cat "$CURRENT_ENV_FILE"
else
echo "unknown"
fi
}
# 清理环境相关文件
clean_environment() {
local flutter_sdk="$1"
echo "清理环境相关文件..."
# 进入Flutter SDK目录
cd "$flutter_sdk"
# 清理编译产物
echo " 清理编译产物..."
rm -rf out/
rm -rf build/obj/
# 清理工具缓存
echo " 清理工具缓存..."
rm -rf .gclient_entries
rm -rf .cipd/
rm -rf buildtools/
# 清理Python缓存
echo " 清理Python缓存..."
find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
# 清理Git索引(保留源码)
echo " 重置Git工作区..."
if [ -d "flutter/.git" ]; then
cd flutter
git reset --hard HEAD
git clean -fd
cd ..
fi
# 清理第三方依赖(会重新下载)
find third_party -name ".git" -type d | while read -r git_dir; do
repo_dir=$(dirname "$git_dir")
echo " 重置仓库: $repo_dir"
cd "$repo_dir"
git reset --hard HEAD 2>/dev/null || true
git clean -fd 2>/dev/null || true
cd "$flutter_sdk"
done
# 清理临时文件
echo " 清理临时文件..."
rm -rf tmp/
find . -name "*.tmp" -delete 2>/dev/null || true
find . -name "*.log" -delete 2>/dev/null || true
echo "环境清理完成"
}
# 主函数
main() {
local current_env=$(detect_environment)
local last_env=$(get_last_environment)
echo "=== Flutter Engine 环境切换 ==="
echo "当前环境: $current_env"
echo "上次环境: $last_env"
# 检查是否需要清理
if [ "$current_env" != "$last_env" ] && [ "$last_env" != "unknown" ]; then
echo ""
echo "⚠ 检测到环境切换:$last_env -> $current_env"
echo "需要清理不兼容的文件..."
echo ""
read -p "是否继续清理?(y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
clean_environment "$FLUTTER_SDK_DIR"
else
echo "跳过清理,但强烈建议清理后再编译"
fi
else
echo "环境未切换,无需清理"
fi
# 更新环境标记
echo "$current_env" > "$CURRENT_ENV_FILE"
echo "环境检查完成"
}
main "$@"
自动化环境检查
集成到编译脚本中
#!/bin/bash
# 在compile_engine_linux.sh中添加环境检查
# 在编译开始前检查环境
check_environment_switch() {
local switch_script="/writer/scripts/switch_environment.sh"
if [ -f "$switch_script" ]; then
echo "检查环境切换..."
bash "$switch_script"
else
echo "⚠ 环境切换脚本未找到,建议手动清理"
fi
}
# 在主函数开始处调用
main() {
check_environment_switch
# ...existing code...
}
2.6 环境清理与重置脚本
完整的清理脚本集合
深度清理脚本
#!/bin/bash
# 文件名:deep_clean.sh
# 用途:深度清理Flutter Engine工作空间
set -e
FLUTTER_SDK_DIR="$HOME/Documents/writer/flutter_sdk"
echo "=== Flutter Engine 深度清理 ==="
echo "目标目录: $FLUTTER_SDK_DIR"
# 确认操作
echo ""
echo "⚠ 警告:此操作将删除所有编译产物和缓存"
echo "⚠ 源码将保留,但需要重新运行 gclient sync"
echo ""
read -p "确认继续?(yes/NO): " -r
if [ "$REPLY" != "yes" ]; then
echo "操作已取消"
exit 0
fi
cd "$FLUTTER_SDK_DIR"
# 保留源码,删除其他所有内容
echo "开始深度清理..."
# 备份重要配置
echo "备份配置文件..."
cp .gclient .gclient.backup 2>/dev/null || echo "无.gclient文件需要备份"
# 删除编译相关目录
echo "删除编译产物..."
rm -rf out/
rm -rf build/
# 删除工具和缓存
echo "删除工具缓存..."
rm -rf .gclient_entries
rm -rf .cipd/
rm -rf buildtools/
rm -rf tools/
# 保留flutter目录,但清理其状态
if [ -d "flutter" ]; then
echo "清理flutter仓库状态..."
cd flutter
git reset --hard HEAD
git clean -fdx
cd ..
fi
# 删除第三方依赖(会重新下载)
echo "删除第三方依赖..."
rm -rf third_party/
# 恢复配置文件
echo "恢复配置文件..."
if [ -f ".gclient.backup" ]; then
mv .gclient.backup .gclient
fi
echo ""
echo "=== 深度清理完成 ==="
echo "下一步:"
echo "1. 运行 gclient sync 重新同步依赖"
echo "2. 等待依赖下载完成(可能需要30分钟-2小时)"
echo "3. 重新编译"
快速清理脚本
#!/bin/bash
# 文件名:quick_clean.sh
# 用途:快速清理编译产物,保留依赖
set -e
FLUTTER_SDK_DIR="$HOME/Documents/writer/flutter_sdk"
echo "=== 快速清理编译产物 ==="
cd "$FLUTTER_SDK_DIR"
# 只清理编译产物和缓存
echo "清理编译产物..."
rm -rf out/
echo "清理构建缓存..."
rm -rf build/obj/
rm -rf .gclient_entries
echo "清理Python缓存..."
find . -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true
find . -name "*.pyc" -delete 2>/dev/null || true
echo "快速清理完成,可以直接重新编译"
2.7 项目目录结构详解
完整的目录结构说明
/Users/wangjinshan/Documents/writer/
├── android/ # Android项目
│ ├── app/
│ │ ├── libs/ # 自定义engine产物存放处
│ │ │ ├── flutter.jar # 自定义Java部分
│ │ │ └── arm64-v8a/
│ │ │ └── libflutter.so # 自定义native部分
│ │ └── src/main/java/
│ │ └── fix/ # Android修复代码
│ └── gradle/ # Gradle配置
│
├── ios/ # iOS项目
│ ├── Flutter.framework/ # iOS自定义engine
│ └── fix/ # iOS修复代码
│
├── flutter_sdk/ # Flutter Engine源码(Mac/Docker共享)
│ ├── .gclient # gclient配置文件
│ ├── .current_env # 当前环境标记文件
│ ├── flutter/ # Flutter Engine核心源码
│ │ ├── shell/ # Shell层代码
│ │ │ └── platform/android/ # Android平台代码
│ │ │ └── io/flutter/plugin/editing/ # 光标问题修复位置
│ │ └── tools/gn # 构建配置工具
│ ├── out/ # 编译输出目录
│ │ ├── android_release_arm64/ # Android ARM64 Release
│ │ │ ├── flutter.jar # Java部分产物
│ │ │ └── libflutter.so # Native部分产物
│ │ └── ios_release_arm64/ # iOS ARM64 Release
│ │ └── Flutter.framework/ # iOS Framework
│ ├── third_party/ # 第三方依赖
│ │ ├── skia/ # Skia图形库
│ │ ├── dart/ # Dart VM
│ │ └── icu/ # ICU国际化库
│ └── build/ # 构建系统文件
│
├── writer_build_engin_shell/ # 构建脚本和配置
│ ├── docker_shell_build/ # Docker相关文件
│ │ ├── Dockerfile # Docker镜像定义
│ │ ├── scripts/ # 容器内脚本
│ │ │ ├── setup_container_env.sh # 容器环境配置
│ │ │ ├── container_entry.sh # 容器入口脚本
│ │ │ └── compile_engine_linux.sh # Linux编译脚本
│ │ └── docker-compose.yml # Docker Compose配置
│ ├── compile_engine.sh # Mac编译脚本
│ ├── switch_environment.sh # 环境切换脚本
│ ├── deep_clean.sh # 深度清理脚本
│ ├── quick_clean.sh # 快速清理脚本
│ └── md/ # 文档目录
│ ├── 01_preparation_work.md # 第一章
│ ├── 02_docker_environment.md # 第二章
│ └── readme.md # 总目录
│
└── writer-flutter/ # Flutter应用项目
├── lib/ # Flutter应用代码
├── android/ # Android部分
│ └── app/build.gradle # 配置使用自定义engine
├── ios/ # iOS部分
└── pubspec.yaml # Flutter项目配置
目录设计原理
1. 文件共享设计
# Mac和Docker共享同一个flutter_sdk目录
# Mac路径: /Users/wangjinshan/Documents/writer/flutter_sdk
# Docker路径: /writer/flutter_sdk
# 实际上是同一个物理位置,通过Docker卷挂载实现
2. 脚本分离设计
# Mac脚本
writer_build_engin_shell/compile_engine.sh # Mac环境编译
# Linux脚本
writer_build_engin_shell/docker_shell_build/scripts/compile_engine_linux.sh
echo "错误: 不支持debug模式,请使用 release 或 profile"
exit 1
fi
shift 2
;;
--platform)
TARGET_PLATFORM="$2"
shift 2
;;
--cpu)
TARGET_CPU="$2"
shift 2
;;
--clean)
CLEAN_BUILD=true
shift
;;
--help|-h)
echo "用法: $0 [选项]"
echo "选项:"
echo " --mode <profile|release> 构建模式"
echo " --platform <android|linux> 目标平台"
echo " --cpu <arm|arm64|x64> 目标CPU架构"
echo " --clean 清理构建"
exit 0
;;
*)
echo "未知参数: $1"
exit 1
;;
esac
done
# 检查当前目录
if [ ! -f ".gclient" ] || [ ! -d "flutter" ]; then
echo "错误: 请在Flutter Engine源码根目录下运行此脚本"
exit 1
fi
# 检查Linux依赖
check_dependencies() {
echo "检查Linux编译依赖..."
required_packages=("build-essential" "git" "python3" "pkg-config")
missing_packages=()
for package in "${required_packages[@]}"; do
if ! dpkg -l | grep -q "^ii $package "; then
missing_packages+=("$package")
fi
done
if [ ${#missing_packages[@]} -ne 0 ]; then
echo "缺少以下包: ${missing_packages[*]}"
echo "请运行: sudo apt install ${missing_packages[*]}"
exit 1
fi
}
check_dependencies
echo "构建配置:"
echo " 模式: $TARGET_MODE"
echo " 平台: $TARGET_PLATFORM"
echo " CPU: $TARGET_CPU"
# 清理构建目录
if [ "$CLEAN_BUILD" = true ]; then
echo "清理构建目录..."
rm -rf out/
fi
# 构建输出目录
OUTPUT_DIR="out/${TARGET_PLATFORM}_${TARGET_MODE}_${TARGET_CPU}"
# 配置GN参数
echo "配置构建环境..."
GN_ARGS="--${TARGET_PLATFORM}"
if [ "$TARGET_PLATFORM" = "android" ]; then
GN_ARGS+=" --android-cpu ${TARGET_CPU}"
elif [ "$TARGET_PLATFORM" = "linux" ]; then
GN_ARGS+=" --linux-cpu ${TARGET_CPU}"
fi
GN_ARGS+=" --runtime-mode ${TARGET_MODE} --optimized"
# 执行GN配置
echo "执行: ./flutter/tools/gn $GN_ARGS"
./flutter/tools/gn $GN_ARGS
# 获取CPU核心数并检查内存
CORES=$(nproc)
MEMORY_GB=$(free -g | awk '/^Mem:/{print $2}')
if [ "$MEMORY_GB" -lt 8 ]; then
echo "警告: 系统内存少于8GB,限制并行任务数"
CORES=$((CORES / 2))
fi
echo "使用 $CORES 个CPU核心进行编译"
# 开始编译
echo "开始编译..."
start_time=$(date +%s)
ninja -C "$OUTPUT_DIR" -j"$CORES"
end_time=$(date +%s)
build_time=$((end_time - start_time))
echo "=== 编译完成 ==="
echo "编译时间: ${build_time}秒"
echo "输出目录: $OUTPUT_DIR"
# 验证构建产物
echo "验证构建产物..."
if [ "$TARGET_PLATFORM" = "android" ]; then
if [ -f "$OUTPUT_DIR/flutter.jar" ]; then
echo "✓ flutter.jar 构建成功"
else
echo "✗ flutter.jar 构建失败"
fi
if [ -f "$OUTPUT_DIR/libflutter.so" ]; then
echo "✓ libflutter.so 构建成功"
else
echo "✗ libflutter.so 构建失败"
fi
fi
echo "Linux编译脚本执行完成"
2.7 Docker网络与端口映射
网络配置基础
查看Docker网络
# 列出所有网络
docker network ls
# 查看默认bridge网络详情
docker network inspect bridge
# 创建自定义网络
docker network create flutter-network
# 删除网络
docker network rm flutter-network
容器网络连接
# 连接容器到网络
docker network connect flutter-network flutter-engine-container
# 断开网络连接
docker network disconnect flutter-network flutter-engine-container
# 创建容器时指定网络
docker run -it --network flutter-network flutter-engine-dev
端口映射配置
虽然Flutter Engine编译通常不需要端口映射,但在某些调试场景下可能需要:
# 映射端口(如果需要Web调试)
docker run -it \
-p 8080:8080 \
-p 9090:9090 \
flutter-engine-dev
# 映射所有端口
docker run -it -P flutter-engine-dev
# 查看端口映射
docker port flutter-engine-container
2.8 蓝盾流水线集成准备
蓝盾流水线概述
蓝盾(BlueKing CI)是腾讯开源的一站式DevOps平台,Flutter Engine的CI/CD流程需要在蓝盾的Docker环境中运行。
蓝盾环境特点:
- 基于Docker容器运行
- 使用Ubuntu Linux环境
- 资源有限(CPU/内存)
- 网络访问受限
- 需要优化构建时间
蓝盾专用Docker配置
# 文件名:Dockerfile.blueking
# 用途:蓝盾流水线专用镜像
FROM ubuntu:20.04
# 蓝盾环境变量
ENV DEBIAN_FRONTEND=noninteractive \
WORKSPACE=/data/landun/workspace \
BK_CI_BUILD_NUM=${BK_CI_BUILD_NUM} \
BK_CI_PIPELINE_ID=${BK_CI_PIPELINE_ID}
# 安装基础依赖(精简版)
RUN apt-get update && apt-get install -y \
curl git python3 python3-pip \
build-essential pkg-config \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# 创建工作目录
WORKDIR $WORKSPACE
# 复制必要的脚本
COPY scripts/ /opt/scripts/
RUN chmod +x /opt/scripts/*.sh
# 设置入口点
ENTRYPOINT ["/opt/scripts/blueking_entry.sh"]
蓝盾流水线脚本
#!/bin/bash
# 文件名:blueking_entry.sh
# 用途:蓝盾流水线入口脚本
set -e
echo "=== 蓝盾Flutter Engine构建流水线 ==="
# 环境信息
echo "构建信息:"
echo " 流水线ID: ${BK_CI_PIPELINE_ID}"
echo " 构建号: ${BK_CI_BUILD_NUM}"
echo " 工作空间: ${WORKSPACE}"
# 检查环境
check_environment() {
echo "检查构建环境..."
# 检查磁盘空间
available_space=$(df -h $WORKSPACE | tail -1 | awk '{print $4}')
echo "可用空间: $available_space"
# 检查内存
memory_info=$(free -h | grep '^Mem:')
echo "内存信息: $memory_info"
# 检查CPU
cpu_count=$(nproc)
echo "CPU核心数: $cpu_count"
}
# 配置depot_tools
setup_depot_tools() {
echo "配置depot_tools..."
if [ ! -d "/depot_tools" ]; then
echo "下载depot_tools..."
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /depot_tools
fi
export PATH="/depot_tools:$PATH"
export DEPOT_TOOLS_UPDATE=0
}
# 同步源码
sync_source() {
echo "同步Flutter Engine源码..."
if [ ! -f ".gclient" ]; then
echo "初始化gclient配置..."
cat > .gclient << 'EOF'
solutions = [
{
"managed": False,
"name": ".",
"url": "https://github.com/flutter/flutter.git@3.29.0",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
EOF
fi
# 使用较少的并行任务以适应蓝盾环境
gclient sync --verbose --jobs=2
}
# 执行构建
build_engine() {
echo "开始构建Flutter Engine..."
# 使用release模式和较少的并行任务
./compile_engine_linux.sh \
--mode release \
--platform android \
--cpu arm64
}
# 上传产物
upload_artifacts() {
echo "准备构建产物..."
OUTPUT_DIR="out/android_release_arm64"
ARTIFACT_DIR="artifacts"
mkdir -p "$ARTIFACT_DIR"
# 复制关键文件
if [ -f "$OUTPUT_DIR/flutter.jar" ]; then
cp "$OUTPUT_DIR/flutter.jar" "$ARTIFACT_DIR/"
echo "✓ flutter.jar 已复制"
fi
if [ -f "$OUTPUT_DIR/libflutter.so" ]; then
cp "$OUTPUT_DIR/libflutter.so" "$ARTIFACT_DIR/"
echo "✓ libflutter.so 已复制"
fi
# 创建版本信息文件
cat > "$ARTIFACT_DIR/build_info.json" << EOF
{
"pipeline_id": "${BK_CI_PIPELINE_ID}",
"build_num": "${BK_CI_BUILD_NUM}",
"build_time": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"git_commit": "$(git rev-parse HEAD)",
"flutter_version": "3.29.0"
}
EOF
echo "构建产物已准备完成"
}
# 主函数
main() {
check_environment
setup_depot_tools
sync_source
build_engine
upload_artifacts
echo "=== 蓝盾构建流水线完成 ==="
}
main "$@"
Docker Compose配置
# 文件名:docker-compose.yml
# 用途:本地测试蓝盾环境
version: '3.8'
services:
flutter-engine-build:
build:
context: .
dockerfile: Dockerfile.blueking
container_name: flutter-engine-blueking
volumes:
- ./:/workspace
- flutter-cache:/tmp/flutter-cache
environment:
- BK_CI_BUILD_NUM=local-001
- BK_CI_PIPELINE_ID=test-pipeline
working_dir: /workspace
command: /bin/bash
flutter-engine-dev:
build:
context: .
dockerfile: Dockerfile
container_name: flutter-engine-local
volumes:
- ./:/workspace
- /depot_tools:/depot_tools
environment:
- PATH=/depot_tools:$PATH
- DEPOT_TOOLS_UPDATE=0
working_dir: /workspace
tty: true
stdin_open: true
volumes:
flutter-cache:
driver: local
容器管理脚本
#!/bin/bash
# 文件名:docker_manager.sh
# 用途:Docker容器管理脚本
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# 显示帮助信息
show_help() {
echo "Flutter Engine Docker 管理脚本"
echo ""
echo "用法: $0 <command> [options]"
echo ""
echo "命令:"
echo " build 构建Docker镜像"
echo " run 运行开发容器"
echo " test 运行蓝盾测试环境"
echo " clean 清理Docker资源"
echo " logs 查看容器日志"
echo " exec 进入运行中的容器"
echo ""
echo "示例:"
echo " $0 build # 构建镜像"
echo " $0 run # 运行开发容器"
echo " $0 test # 测试蓝盾环境"
echo " $0 exec flutter-dev # 进入开发容器"
}
# 构建镜像
build_images() {
echo "构建Flutter Engine Docker镜像..."
# 构建开发环境镜像
docker build -t flutter-engine-dev:latest .
# 构建蓝盾环境镜像
docker build -f Dockerfile.blueking -t flutter-engine-blueking:latest .
echo "镜像构建完成"
}
# 运行开发容器
run_dev_container() {
echo "启动Flutter Engine开发容器..."
docker-compose up -d flutter-engine-dev
docker-compose exec flutter-engine-dev /bin/bash
}
# 测试蓝盾环境
test_blueking_env() {
echo "测试蓝盾构建环境..."
docker-compose up --build flutter-engine-build
}
# 清理Docker资源
clean_docker() {
echo "清理Docker资源..."
# 停止所有容器
docker-compose down
# 删除悬空镜像
docker image prune -f
# 删除未使用的卷
docker volume prune -f
echo "清理完成"
}
# 查看日志
show_logs() {
local service=${1:-flutter-engine-dev}
docker-compose logs -f "$service"
}
# 进入容器
exec_container() {
local service=${1:-flutter-engine-dev}
docker-compose exec "$service" /bin/bash
}
# 主函数
main() {
case "${1:-help}" in
build)
build_images
;;
run)
run_dev_container
;;
test)
test_blueking_env
;;
clean)
clean_docker
;;
logs)
show_logs "$2"
;;
exec)
exec_container "$2"
;;
help|--help|-h)
show_help
;;
*)
echo "未知命令: $1"
show_help
exit 1
;;
esac
}
main "$@"
小结
本章详细介绍了Flutter Engine开发的Docker环境配置:
核心内容回顾:
- Docker基础概念: 镜像、容器、数据卷的原理和使用
- Dockerfile配置: 从基础到优化的多种配置方案
- 镜像管理: 构建、标签、清理等管理操作
- 容器运行: 创建、启动、监控容器的完整流程
- 数据共享: Volume挂载和文件共享策略
- 环境脚本: Linux环境下的编译脚本配置
- 蓝盾集成: 为蓝盾流水线定制的Docker配置
关键要点:
- Docker环境统一了开发、测试、生产环境
- 使用release模式进行所有构建
- 合理配置资源限制以适应CI环境
- 通过数据卷实现Mac和Docker的文件共享
- 为蓝盾流水线优化了镜像大小和构建时间
准备时间:
- Docker环境搭建:1-2小时
- 镜像构建:30-60分钟
- 容器配置调试:1-2小时
完成本章配置后,即可在统一的Docker环境中进行Flutter Engine开发,为下一章的具体修改工作做好环境准备。