🔑 buildConfigField란?
buildConfigField는 Android Gradle 플러그인에서 제공하는 기능으로, 빌드 시점에 상수를 생성하여 앱 코드에서 사용할 수 있게 해주는 메커니즘입니다.
📁 전체 파일 구조
프로젝트 루트/
├── app/
│ ├── build.gradle.kts (또는 build.gradle)
│ └── src/main/java/.../
├── secrets.properties # API 키들을 저장하는 파일
├── gradle.properties
└── .gitignore # secrets.properties 제외
🔧 설정 과정 (단계별)
1단계: secrets.properties 파일 생성
# secrets.properties (프로젝트 루트에 생성)
GOOGLE_MAPS_API_KEY=AIzaSyC4YourGoogleMapsApiKey
GOOGLE_PLACES_API_KEY=AIzaSyC4YourGooglePlacesApiKey
KAKAO_APP_KEY=your_kakao_app_key
KAKAO_REST_API_KEY=your_kakao_rest_api_key
KAKAO_JAVASCRIPT_KEY=your_kakao_javascript_key
KAKAO_ADMIN_KEY=your_kakao_admin_key
NAVER_CLIENT_ID=your_naver_client_id
NAVER_CLIENT_SECRET=your_naver_client_secret
FIREBASE_API_KEY=your_firebase_api_key
FIREBASE_PROJECT_ID=your_firebase_project_id
WEATHER_API_KEY=your_weather_api_key
DELIVERY_API_KEY=your_delivery_api_key
2단계: .gitignore에 추가
# API Keys
secrets.properties
local.properties
3단계: build.gradle.kts에서 설정
// app/build.gradle.kts
android {
// secrets.properties 파일 읽기
val secretsProperties = Properties().apply {
val secretsPropertiesFile = rootProject.file("secrets.properties")
if (secretsPropertiesFile.exists()) {
load(secretsPropertiesFile.inputStream())
}
}
defaultConfig {
// BuildConfig 필드 생성
buildConfigField("String", "GOOGLE_MAPS_API_KEY",
"\"${secretsProperties.getProperty("GOOGLE_MAPS_API_KEY") ?: ""}\"")
buildConfigField("String", "KAKAO_APP_KEY",
"\"${secretsProperties.getProperty("KAKAO_APP_KEY") ?: ""}\"")
// ... 나머지 필드들
}
buildFeatures {
buildConfig = true # BuildConfig 생성 활성화
}
}
🏗️ BuildConfig 파일 생성 과정
빌드 시점에 자동 생성되는 파일
// app/build/generated/source/buildConfig/debug/com/yourpackage/BuildConfig.java
package com.yourpackage;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.yourpackage";
public static final String BUILD_TYPE = "debug";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// 우리가 추가한 API 키들
public static final String GOOGLE_MAPS_API_KEY = "AIzaSyC4YourGoogleMapsApiKey";
public static final String KAKAO_APP_KEY = "your_kakao_app_key";
public static final String NAVER_CLIENT_ID = "your_naver_client_id";
// ... 모든 API 키들
}
🎯 왜 이 방식을 사용하는가?
1. 보안성 (Security)
// ❌ 나쁜 예 - 소스코드에 직접 노출
class ApiService {
companion object {
const val API_KEY = "AIzaSyC4YourActualApiKey" // 🚨 GitHub에 노출됨!
}
}
// ✅ 좋은 예 - BuildConfig 사용
class ApiService {
companion object {
val API_KEY = BuildConfig.GOOGLE_MAPS_API_KEY // 🔒 안전함
}
}
2. 환경별 다른 키 사용
// build.gradle.kts
android {
buildTypes {
debug {
buildConfigField("String", "API_URL", "\"https://dev-api.example.com\"")
buildConfigField("String", "API_KEY", "\"debug_api_key\"")
}
release {
buildConfigField("String", "API_URL", "\"https://api.example.com\"")
buildConfigField("String", "API_KEY", "\"production_api_key\"")
}
}
}
3. 팀 협업 용이성
- 각 개발자가 자신만의 secrets.properties 파일을 가짐
- Git에는 API 키가 노출되지 않음
- 새로운 팀원은 secrets.properties.sample 파일을 참고하여 설정
📱 실제 사용 예시
Kotlin에서 사용
class GoogleMapsRepository {
private val apiKey = BuildConfig.GOOGLE_MAPS_API_KEY
fun getPlaces(location: String) {
val url = "https://maps.googleapis.com/maps/api/place/search/json" +
"?key=$apiKey&location=$location"
// API 호출
}
}
class KakaoService {
private val restApiKey = BuildConfig.KAKAO_REST_API_KEY
private val jsKey = BuildConfig.KAKAO_JAVASCRIPT_KEY
fun searchAddress(query: String) {
// Kakao API 호출
}
}
Compose에서 사용
@Composable
fun GoogleMapScreen() {
val context = LocalContext.current
AndroidView(
factory = { ctx ->
MapView(ctx).apply {
onCreate(null)
getMapAsync { googleMap ->
// BuildConfig의 API 키 사용
// 이미 Manifest에 설정되어 있어야 함
}
}
}
)
}
⚙️ 문법 상세 분석
buildConfigField("String", "GOOGLE_MAPS_API_KEY", "\"${secretsProperties.getProperty("GOOGLE_MAPS_API_KEY") ?: ""}\"")
각 부분 설명:
- "String": 생성될 상수의 타입
- "GOOGLE_MAPS_API_KEY": BuildConfig에서 사용할 변수명
- secretsProperties.getProperty("GOOGLE_MAPS_API_KEY"): secrets.properties 파일에서 값 읽기
- ?: "": null일 경우 빈 문자열 반환 (Elvis 연산자)
- \"...\": 문자열 리터럴을 위한 이스케이프
🔄 빌드 과정에서 일어나는 일
1. Gradle이 secrets.properties 파일을 읽음
↓
2. 각 buildConfigField에서 값을 추출
↓
3. BuildConfig.java 파일을 자동 생성
↓
4. 컴파일 시점에 상수값들이 코드에 삽입됨
↓
5. 런타임에서 BuildConfig.FIELD_NAME으로 접근 가능
🛡️ 보안 모범 사례
1. CI/CD 환경에서의 처리
# GitHub Actions 예시
- name: Create secrets.properties
run: |
echo "GOOGLE_MAPS_API_KEY=${{ secrets.GOOGLE_MAPS_API_KEY }}" >> secrets.properties
echo "KAKAO_APP_KEY=${{ secrets.KAKAO_APP_KEY }}" >> secrets.properties
2. ProGuard/R8에서 난독화 제외
# proguard-rules.pro
-keep class *.BuildConfig { *; }
-keepclassmembers class *.BuildConfig {
public static final java.lang.String *;
}
3. Fallback 값 설정
buildConfigField("String", "API_KEY",
"\"${secretsProperties.getProperty("API_KEY") ?: "default_debug_key"}\"")
🚨 주의사항
- APK 역컴파일: BuildConfig의 값들은 APK를 역컴파일하면 볼 수 있음
- 진짜 보안: 매우 민감한 정보는 서버에서 처리하는 것이 좋음
- 빌드 캐시: API 키 변경 후 Clean Build 필요할 수 있음
- 타입 안전성: 잘못된 타입 지정 시 컴파일 에러 발생
📋 대안 방법들
1. Gradle Properties 사용
// gradle.properties
googleMapsApiKey=your_api_key
// build.gradle.kts
buildConfigField("String", "API_KEY", "\"${project.findProperty("googleMapsApiKey")}\"")
2. 환경변수 사용
buildConfigField("String", "API_KEY", "\"${System.getenv("GOOGLE_MAPS_API_KEY") ?: ""}\"")
3. Secrets Gradle Plugin 사용
// build.gradle.kts
plugins {
id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin")
}
이렇게 buildConfigField를 사용하면 API 키의 보안성을 유지하면서도 개발 편의성을 극대화할 수 있습니다!
'Android' 카테고리의 다른 글
Android에서 UAAL(Unity as a Library) 활용 가이드 (2) | 2025.07.31 |
---|---|
[AOS] 사이드 프로젝트(dogdom #2) ViewBinding (0) | 2024.03.30 |
[AOS] 사이드 프로젝트 (dogdom #1) (0) | 2024.03.24 |
[AOS] 사이드 프로젝트 (dogdom #0) (0) | 2024.03.24 |