GitHub Actions 安卓 APK CI 签名

GitHub Actions 安卓 APK CI 签名与 Release 全流程实战总结

记录一次 Android 项目使用 GitHub Actions 自动构建、签名、发布 APK 并创建 Release 的完整实践过程。本文重点不是"能跑",而是:为什么会失败、如何定位、以及最终稳定方案,方便后期自己回看,也给后来人少踩坑。


一、背景与目标

背景

  • Android 项目(Kotlin)

  • 使用 GitHub Actions 进行 CI

  • 每次 push master

    • 自动修改版本号
    • 构建 Release APK
    • 使用 正式 keystore 签名
    • 上传服务器
    • 创建 GitHub Release

核心目标

所有 Release APK 必须使用同一份签名证书

否则会出现:

  • 新版本无法覆盖安装
  • 系统提示"签名不一致"

二、整体流程设计(最终形态)

整体 CI 流程如下:

复制代码
push master
   ↓
GitHub Actions
   ↓
恢复 keystore(Base64 → jks)
   ↓
注入签名参数(环境变量)
   ↓
Gradle assembleRelease
   ↓
校验 APK 签名信息
   ↓
创建 GitHub Release

三、核心问题与踩坑记录

❌ 问题 1:base64: invalid input

现象

text 复制代码
base64: invalid input
Error: Process completed with exit code 1

根因

  • keystore 在本地用 base64 编码后
  • GitHub Actions 中使用了不稳定的参数:
bash 复制代码
base64 -di

不同 Linux 发行版对 -d -i 行为并不完全一致。

正确方式(稳定)

bash 复制代码
base64 --decode

❌ 问题 2:Gradle 提示 Keystore file not found

报错信息

text 复制代码
Execution failed for task ':app:validateSigningRelease'
Keystore file 'xxx-release.jks' not found

常见误区

  • keystore 已生成
  • Gradle 使用的路径 ≠ 实际生成路径

例如:

text 复制代码
生成位置: app/reward-release.jks
Gradle 查找: reward-release.jks

👉 路径必须 100% 对齐,否则直接失败。


❌ 问题 3:gradle.properties 写了,但 Gradle 根本没用

一开始采用方案:

bash 复制代码
echo "RELEASE_KEYSTORE_PASSWORD=xxx" >> gradle.properties

build.gradle.kts 实际使用的是:

kotlin 复制代码
System.getenv("RELEASE_KEYSTORE_PASSWORD")

👉 结论

写进 gradle.properties ≠ Gradle 一定会读

这也是 CI 中最隐蔽、最容易误判的问题之一。


四、最终采用的稳定方案(强烈推荐)

核心原则

  • keystore 文件:CI 运行时恢复
  • 敏感信息:只走 GitHub Secrets
  • Gradle :只从 System.getenv() 读取
  • 不污染仓库、不写死密码

五、GitHub Actions 关键配置(最终版)

1️⃣ 恢复 keystore

yaml 复制代码
- name: Restore release keystore
  run: |
    echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 --decode > app/reward-release.jks

2️⃣ 构建 Release APK(注入环境变量)

yaml 复制代码
- name: Build Release APK
  env:
    RELEASE_KEYSTORE_PASSWORD: ${{ secrets.RELEASE_KEYSTORE_PASSWORD }}
    RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
    RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}
  run: ./gradlew assembleRelease --stacktrace --no-daemon

3️⃣ (可选)打印 APK 签名信息

yaml 复制代码
- name: Print APK signing info
  run: |
    $ANDROID_HOME/build-tools/34.0.0/apksigner verify --print-certs app/build/outputs/apk/release/*.apk

用于确认:

  • SHA1 / SHA256
  • 是否为同一签名证书

六、Gradle 签名配置(Kotlin DSL)

kotlin 复制代码
android {
    signingConfigs {
        create("release") {
            storeFile = file("$rootDir/app/reward-release.jks")
            storePassword = System.getenv("RELEASE_KEYSTORE_PASSWORD")
            keyAlias = System.getenv("RELEASE_KEY_ALIAS")
            keyPassword = System.getenv("RELEASE_KEY_PASSWORD")
        }
    }

    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
            isMinifyEnabled = false
        }
    }
}

七、结果验证

✅ 构建结果

  • CI 稳定通过
  • 每次 Release APK 均使用同一证书
  • 新版本可直接覆盖安装旧版本

✅ GitHub Release

  • 每个版本一个 tag
  • Release 附件即签名 APK

八、经验总结(强烈建议记住)

CI 签名问题 99% 排查顺序

只看三件事:

1️⃣ keystore 是否真的恢复成功

2️⃣ Gradle 是否真的使用了它

3️⃣ 路径是否完全一致


最佳实践清单

  • ❌ 不要把 keystore 提交到仓库
  • ❌ 不要把密码写死在 gradle 文件
  • ✅ GitHub Secrets + Base64
  • System.getenv()
  • ✅ CI 中打印签名信息做校验

九、结语

这套方案不是"理论最优",而是:

在真实 CI 环境中被问题反复验证后,最稳定、最不容易踩坑的一种方式。

后续如果要支持 AAB / Play Store / 多渠道包,也可以在此基础上无痛扩展。


相关推荐
code_li1 天前
Android 16KB页面大小适配
java·架构·android-studio
、BeYourself1 天前
Intent :跳转与数据传递的正确打开方式
android·android-studio
我命由我123451 天前
Android 开发 Room 数据库升级问题:A migration from 6 to 7 was required but not found.
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123453 天前
Android 控件 - 最简单的 Notification、Application Context 应用于 Notification
android·java·开发语言·junit·android studio·android jetpack·android-studio
JMchen1233 天前
Android CameraX深度解析:从Camera1到CameraX的相机架构演进
android·java·数码相机·架构·kotlin·移动开发·android-studio
、BeYourself5 天前
TabLayout 与 ViewPager2 的基本使用
android·android-studio
我命由我123455 天前
JUnit - 自定义 Rule
android·java·开发语言·数据库·junit·java-ee·android-studio
、BeYourself8 天前
动作栏 (ActionBar) 与工具栏 (Toolbar) 的基本使用
android·android-studio
我命由我1234512 天前
Android Studio - Android Studio 中的 View Live Telemetry
经验分享·学习·android studio·学习方法·android jetpack·android-studio·android runtime