gitlab-ci 实践:打包Android apk

环境信息

  • 操作系统: Linux
  • 用户: gitlab-runner(后续通过 .gitlab-ci.yml 触发)
  • 工作目录: /home/gitlab-runner/tool/
  • 项目目录: /home/gitlab-runner/androidapk/

1. Java 环境配置

背景:当前 Linux 环境中已安装多个 Java 版本,需要将环境变量切换到 Java 17。如果没有,需要下载安装:

1
2
3
4
# Centos
wget https://download.oracle.com/java/17/archive/jdk-17.0.5_linux-x64_bin.rpm
yum localinstall jdk-17.0.5_linux-x64_bin.rpm
java --version
1
2
3
4
5
6
# 下载 OpenJDK 17
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz

# 解压到指定目录
sudo mkdir -p /usr/local/java
sudo tar -xzf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java/

配置步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 编辑用户配置文件
vi ~/.bashrc

# 2. 添加或修改以下内容
export JAVA_HOME=/usr/local/java/jdk-17
export PATH=$JAVA_HOME/bin:$PATH

# 3. 重新加载配置
source ~/.bashrc

# 4. 验证 Java 版本
java -version
echo $JAVA_HOME

预期输出

1
2
openjdk version "17.x.x" ...
/usr/local/java/jdk-17

2. Gradle 环境配置

背景:由于网络限制,无法直接访问 https://services.gradle.org/,需要手动下载并配置 Gradle。

配置步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 1. 下载 Gradle 8.2(使用国内镜像)
cd /home/gitlab-runner/tool/
wget https://mirrors.cloud.tencent.com/gradle/gradle-8.2-bin.zip

# 2. 解压到工具目录
unzip gradle-8.2-bin.zip -d /home/gitlab-runner/tool/

# 3. 配置环境变量
vi ~/.bashrc

# 添加 Gradle 到 PATH(追加到已有的 Java 配置后)
export JAVA_HOME=/usr/local/java/jdk-17
export PATH=$JAVA_HOME/bin:$PATH
export PATH=/home/gitlab-runner/tool/gradle-8.2/bin:$PATH

# 4. 重新加载配置
source ~/.bashrc

# 5. 验证 Gradle 版本
gradle -v
# Gradle 8.2
# ...

3. Android SDK 配置

Android 打包需要 Android SDK,使用命令行工具安装并配置。

配置步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1. 下载 Android 命令行工具
cd /home/gitlab-runner/tool/
wget https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip

# 如果无法访问 Google 官方地址,使用国内镜像
# wget https://mirrors.cloud.tencent.com/AndroidSDK/commandlinetools-linux-9477386_latest.zip

# 2. 创建目录并解压
mkdir -p android-sdk/cmdline-tools
unzip commandlinetools-linux-9477386_latest.zip -d android-sdk/cmdline-tools/

# 3. 重命名目录(重要:SDK 管理器需要特定的目录结构)
mv android-sdk/cmdline-tools/cmdline-tools android-sdk/cmdline-tools/latest

# 4. 配置环境变量
vi ~/.bashrc

# 添加 Android SDK 相关环境变量
export ANDROID_HOME=/home/gitlab-runner/tool/android-sdk
export ANDROID_SDK_ROOT=$ANDROID_HOME
export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH

# 5. 重新加载配置
source ~/.bashrc

# 6. 接受 Android SDK 许可协议
yes | sdkmanager --licenses

# 7. (可选)安装构建工具和平台
# 根据项目实际需要调整版本号
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"

# 8. (可选)查看项目所需的 SDK 版本
cat /home/gitlab-runner/androidapk/androidaw/build.gradle | grep -E "compileSdk|buildToolsVersion"

验证安装

1
2
3
4
5
6
7
8
9
10
11
12
13
# 验证环境变量
echo $ANDROID_HOME
# 输出: /home/gitlab-runner/tool/android-sdk

# 验证 SDK 工具
sdkmanager --list

# 验证 adb 工具
adb --version

# 查看已安装的平台和构建工具
ls -la $ANDROID_HOME/platforms/
ls -la $ANDROID_HOME/build-tools/

4. Android APK 打包

打包步骤

1
2
3
4
5
6
7
8
9
10
11
# 1. 进入项目目录
cd /home/gitlab-runner/androidapk/

# 2. 执行打包命令(Debug 版本)
gradle :androidaw:assembleDebug

# 或者打包 Release 版本
# gradle :androidaw:assembleRelease

# 3. 查看生成的 APK
ls -lh androidaw/build/outputs/apk/debug/

打包产物

生成的 APK 文件通常位于:

1
androidaw/build/outputs/apk/debug/androidaw-debug.apk

5. 完整环境变量配置

将以下内容添加到 ~/.bashrc 文件中:

1
2
3
4
5
6
7
8
9
10
11
# Java 环境
export JAVA_HOME=/usr/local/java/jdk-17
export PATH=$JAVA_HOME/bin:$PATH

# Gradle 环境
export PATH=/home/gitlab-runner/tool/gradle-8.2/bin:$PATH

# Android SDK 环境
export ANDROID_HOME=/home/gitlab-runner/tool/android-sdk
export ANDROID_SDK_ROOT=$ANDROID_HOME
export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH

重新加载配置:

1
source ~/.bashrc

6. 常见问题排查

问题 1: Connection reset 错误

原因: 无法访问 Gradle 或 Android SDK 官方下载地址

解决方案: 使用国内镜像源

  • Gradle: https://mirrors.cloud.tencent.com/gradle/
  • Android SDK: https://mirrors.cloud.tencent.com/AndroidSDK/

问题 2: SDK location not found

原因: 未配置 ANDROID_HOME 环境变量

解决方案:

  1. 设置环境变量(推荐)
  2. 或在项目根目录创建 local.properties 文件,添加:
    1
    sdk.dir=/home/gitlab-runner/tool/android-sdk

问题 3: Java 版本不匹配

原因: 不同用户使用了不同的 Java 版本

解决方案: 检查并统一 ~/.bashrc 中的 JAVA_HOME 配置

问题 4: gitlab-runner 执行环境差异

背景:gitlab-runner 以 root 权限启动服务并执行 pipeline

1
2
3
4
5
6
7
8
9
(base) [root@dgvxl2905 tool]# systemctl status gitlab-runner.service
● gitlab-runner.service - GitLab Runner
Loaded: loaded (/etc/systemd/system/gitlab-runner.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2025-10-14 17:53:18 CST; 16h ago
Main PID: 25908 (gitlab-runner)
Tasks: 12
Memory: 19.6M
CGroup: /system.slice/gitlab-runner.service
└─25908 /usr/local/bin/gitlab-runner run --config /etc/gitlab-runner/config.toml --working-directory /home/tools/gitlab-runner --service gitlab-runner --user gitlab-runner

原因:使用 --user gitlab-runner 只是让进程以 gitlab-runner 用户身份运行,但不会自动加载该用户的完整登录环境(如 .bashrc.bash_profile 等)。这导致使用的是系统默认的 PATH 而非用户自定义的环境变量,这里用到了 root 权限下的环境变量。

解决:在 .gitlab-ci.yml 中显式加载用户环境

1
2
before_script:
- source /home/gitlab-runner/.bashrc

7. 验证清单

配置完成后,依次验证以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ✓ Java 版本
java -version

# ✓ Gradle 版本
gradle -v

# ✓ Android SDK 路径
echo $ANDROID_HOME

# ✓ SDK 管理器
sdkmanager --list

# ✓ ADB 工具
adb --version

# ✓ 环境变量完整性
echo $PATH

全部验证通过后,即可正常执行 Android 打包任务。


8. 实践 gitlab-ci.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
stages:
- build
- deploy

variables:
APK_OUTPUT_DIR: "androidaw/build/outputs/apk/debug"
APK_FILE_NAME: "androidaw-debug.apk"
FTP_TARGET_DIR: "/data01/user/FTP/android_apk"

workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'

before_script:
- source /home/gitlab-runner/.bashrc
- echo "========== 环境信息 =========="
- whoami
- echo "Java 版本:"
- java -version
- echo "Gradle 版本:"
- gradle -v
- echo "Android SDK 路径:"
- echo $ANDROID_HOME
- echo "当前分支: $CI_COMMIT_BRANCH"
- echo "提交信息: $CI_COMMIT_MESSAGE"
- echo "提交者: $CI_COMMIT_AUTHOR"
- echo "============================"

build_apk:
stage: build
tags:
- apk-runner

cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- .gradle/wrapper
- .gradle/caches

script:
- echo "清理旧的构建产物..."
- gradle clean

- echo "开始构建 Debug APK..."
- gradle :androidaw:assembleDebug --stacktrace

# 验证 APK 是否生成成功
- |
if [ ! -f "${APK_OUTPUT_DIR}/${APK_FILE_NAME}" ]; then
echo "错误: APK 文件未生成!"
exit 1
fi

# 显示 APK 信息
- echo "APK 构建成功!"
- ls -lh ${APK_OUTPUT_DIR}/${APK_FILE_NAME}
- echo "APK 大小: $(du -h ${APK_OUTPUT_DIR}/${APK_FILE_NAME} | cut -f1)"

artifacts:
name: "androidaw-debug-${CI_COMMIT_SHORT_SHA}"
paths:
- ${APK_OUTPUT_DIR}/${APK_FILE_NAME}
expire_in: 7 days

# 构建失败时的处理
retry:
max: 2
when:
- runner_system_failure
- stuck_or_timeout_failure

deploy_apk:
stage: deploy
tags:
- apk-runner

dependencies:
- build_apk

script:
- export BUILD_TIME=$(date +"%Y%m%d_%H%M%S")
- export TARGET_APK_NAME="androidaw-debug-${BUILD_TIME}.apk"
- echo "目标文件名: ${TARGET_APK_NAME}"

- mkdir -p ${FTP_TARGET_DIR}

- echo "拷贝 APK 到 FTP 目录..."
- cp ${APK_OUTPUT_DIR}/${APK_FILE_NAME} ${FTP_TARGET_DIR}/${TARGET_APK_NAME}

# 验证拷贝是否成功
- |
if [ ! -f "${FTP_TARGET_DIR}/${TARGET_APK_NAME}" ]; then
echo "错误: APK 拷贝失败!"
exit 1
fi

- echo "============================"
- echo "APK 已拷贝到:${FTP_TARGET_DIR}/${TARGET_APK_NAME}"
- ls -lh ${FTP_TARGET_DIR}/${TARGET_APK_NAME}
- echo "========== 部署成功 =========="

# 创建 latest 软链接,方便获取最新版本
- ln -sf ${TARGET_APK_NAME} ${FTP_TARGET_DIR}/androidaw-debug-latest.apk
- echo "最新版本链接:${FTP_TARGET_DIR}/androidaw-debug-latest.apk"

# 清理旧文件,只保留最近 10 个版本
- |
cd ${FTP_TARGET_DIR}
ls -t androidaw-debug-*.apk | grep -v latest | tail -n +11 | xargs -r rm -f
echo "已清理旧版本 APK,保留最近 10 个版本"

# 仅在构建成功后执行部署
when: on_success


9. gitlab-runner 权限

背景:gitlab-runner 用户无法访问根目录下的文件,运行 pipeline 时,需将一个文件拷贝到根目录下。

通常修改目标目录的所有者是可以的,

1
2
# 将目标目录的所有者改为 gitlab-runner
sudo chown -R gitlab-runner:gitlab-runner /data01/user/FTP/android_apk/

但是目标目录已经被授予了其他用户访问了:

1
drwxr-xr-x  4 autotest autotest 4096 Oct 13 15:50 android_apk

更好的解决:创建共享组

将 gitlab-runner 加入 autotest 组,这样不影响其他用户,权限不变,gitlab-runner 获得写权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 将 gitlab-runner 加入 autotest 组
sudo usermod -aG autotest gitlab-runner

# 2. 给 autotest 组添加写权限
sudo chmod -R 775 /data01/user/FTP/android_apk/

# 3. 设置 SGID 位,使新文件自动属于 autotest 组
sudo chmod g+s /data01/user/FTP/android_apk/

# 4. 让 gitlab-runner 重新加载组信息
# 方式1: gitlab-runner 用户重新登录
# 方式2: 如果是 gitlab-runner 服务,重启服务
sudo systemctl restart gitlab-runner

验证

1
2
3
4
5
6
7
8
9
10
11
# 1. 验证 gitlab-runner 是否在 autotest 组中
groups gitlab-runner
# 应该看到输出中包含 autotest

# 2. 验证目录权限
ls -ld /data01/user/FTP/android_apk/
# 应该显示: drwxrwsr-x ... autotest autotest

# 3. 测试复制命令
sudo su - gitlab-runner
cp /home/gitlab-runner/androidapk/androidaw/build/outputs/apk/debug/androidaw-debug.apk /data01/user/FTP/android_apk/

附录: 项目构建配置优化

配置 Gradle 国内镜像

编辑项目根目录的 gradle/wrapper/gradle-wrapper.properties

1
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.2-bin.zip

编辑 settings.gradlebuild.gradle,添加仓库镜像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pluginManagement {
repositories {
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://maven.aliyun.com/repository/public' }
google()
mavenCentral()
}
}

dependencyResolutionManagement {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/public' }
google()
mavenCentral()
}
}