Android 릴리즈 서명 자동화 - keystore.properties로 안전하게 설정하기
이 글에서 다루는 것
Play Store에 앱을 배포하려면 반드시 릴리즈 서명(signing)이 필요합니다.
keystore.properties를 활용해build.gradle에서 빌드할 때 자동으로 서명되도록 설정하는 방법을 정리합니다.
민감한 키 정보를 코드 바깥의 별도 파일로 분리하고,.gitignore로 Git에서 제외한 뒤,build.gradle에서 해당 파일을 읽어 서명 설정에 적용하는 방식입니다.
전체 구조
keystore.properties과 keystore 파일 새로 추가합니다.
your_project/
├── android/
│ ├── keystore.properties ← 키 정보 (Git 제외)
│ └── app/
│ └── build.gradle
└── my-release-key.jks ← keystore 파일 (Git 제외)
1단계: keystore 파일 생성
아직 keystore가 없다면 아래 명령어로 생성합니다.
keytool -genkey -v -keystore my-release-key.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias my-key-alias
생성된 .jks 파일은 프로젝트 루트 또는 android/ 디렉토리 안에 보관합니다.
2단계: keystore.properties 생성
프로젝트의 android/ 폴더 안에 keystore.properties 파일을 만들고 키 정보를 작성합니다.
storeFile=../../my-release-key.jks
storePassword=your_store_password
keyAlias=my-key-alias
keyPassword=your_key_password
storeFile경로는android/app/build.gradle기준 상대경로입니다. Flutter 프로젝트에서 keystore를 루트에 두었다면../../로 설정합니다.
3단계: .gitignore에 추가
서명 관련 파일은 절대 Git에 올라가서는 안 됩니다.
# Android Signing
keystore.properties
*.jks
*.keystore
4단계: build.gradle 설정 (Groovy DSL)
android/app/build.gradle 상단에 properties 파일을 읽는 코드를 추가하고, signingConfigs와 buildTypes에 적용합니다.
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
// if (exists()) 없이 작성 → 파일이 없으면 즉시 빌드 에러 발생
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
signingConfigs {
release {
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
주의: if (keystorePropertiesFile.exists()) 가드를 추가하면 파일을 못 찾을 때 조용히 넘어가 debug 키로 서명됩니다. 실수를 즉시 알 수 있도록 가드 없이 작성하는 것을 권장합니다.
4단계 (대안): build.gradle.kts 설정 (Kotlin DSL)
최근 생성되는 프로젝트는 Kotlin DSL을 기본으로 사용합니다.
import java.util.Properties
import java.io.FileInputStream
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties().apply {
load(FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
create("release") {
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
5단계: 빌드 및 서명 확인
# Flutter 프로젝트
flutter build appbundle --release
flutter build apk --release
# 일반 Android 프로젝트
./gradlew bundleRelease
./gradlew assembleRelease
빌드 후 서명 정보를 확인해 CN=Android Debug가 아닌 본인 키 정보가 표시되는지 검증합니다.
keytool -printcert -jarfile build/app/outputs/flutter-apk/app-release.apk
서명이 정상 적용됐다면 잘못된 비밀번호 입력 시 아래와 같은 에러가 발생해야 합니다.
FAILURE: Build failed with an exception.
Execution failed for task ':app:signReleaseBundle'.
> Failed to read key my-key-alias from store "...jks": Cannot recover key
이 에러가 나오지 않고 빌드가 성공한다면 signingConfig이 실제로 적용되지 않은 상태이므로 경로 설정을 다시 확인해야 합니다.
CI/CD 환경 설정 (GitHub Actions)
로컬에서는 keystore.properties를 사용하고, CI 환경에서는 Secrets로 대체합니다.
GitHub Secrets 등록 항목
| Secret 이름 | 값 |
|---|---|
KEYSTORE_BASE64 |
base64 my-release-key.jks로 인코딩한 문자열 |
KEY_STORE_PASSWORD |
storePassword |
KEY_ALIAS |
keyAlias |
KEY_PASSWORD |
keyPassword |
workflow .yml 예시
- name: Decode keystore
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > my-release-key.jks
- name: Create keystore.properties
run: |
echo "storeFile=../../my-release-key.jks" > android/keystore.properties
echo "storePassword=${{ secrets.KEY_STORE_PASSWORD }}" >> android/keystore.properties
echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/keystore.properties
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/keystore.properties
- name: Build release AAB
run: flutter build appbundle --release
정리
keystore.properties 방식의 핵심은 민감 정보를 코드에서 완전히 분리하는 것입니다. 로컬에서는 properties 파일로, CI/CD에서는 환경 Secrets로 동일한 build.gradle을 재사용할 수 있어 관리가 단순해집니다.
서명이 올바르게 적용되었는지는 반드시 keytool -printcert로 확인하는 습관을 들이는 것을 추천합니다.