
안드로이드 개발을 하다 보면 앱 배포와 최적화에 대한 고민이 늘 따라온다. 특히 앱 크기가 커지고 사용자들의 기대치가 높아지면서, 효율적인 배포와 최적화는 선택이 아닌 필수가 되었다. 오늘은 APK에서 AAB로의 전환, 그리고 R8 최적화까지 안드로이드 앱 배포의 진화 과정을 정리해보려고 한다.
APK(Android Package)는 우리가 가장 친숙한 안드로이드 앱 파일 형식이다. ZIP 형식으로 압축되어 있고, 앱 실행에 필요한 모든 것이 들어있다.
APK 파일을 열어보면 다음과 같은 구성 요소들을 볼 수 있다:
하지만 APK 방식에는 근본적인 문제가 있다. 모든 디바이스를 위한 리소스를 하나의 파일에 담아야 한다는 것이다.
예를 들어, 내가 Galaxy S24를 사용하는 한국 사용자라고 해보자:
결과적으로 필요 없는 리소스까지 다운로드하게 되어 앱 크기가 불필요하게 커진다.
2018년, 구글은 Android App Bundle(AAB)이라는 새로운 배포 형식을 발표했다. AAB는 APK의 한계를 극복하기 위해 설계되었다.
AAB는 "중간 형식"이다. 개발자는 AAB를 업로드하고, Google Play가 각 디바이스에 최적화된 APK를 생성해서 배포한다.
// build.gradle 설정
android {
bundle {
language {
enableSplit = true // 언어별 분할
}
density {
enableSplit = true // 화면 밀도별 분할
}
abi {
enableSplit = true // CPU 아키텍처별 분할
}
}
}
AAB의 또 다른 강점은 동적 기능 모듈이다. 모든 기능을 처음부터 설치할 필요 없이, 필요할 때 다운로드할 수 있다.
// 동적 모듈 요청 예시
val request = SplitInstallRequest.newBuilder()
.addModule("premium_features")
.build()
splitInstallManager.startInstall(request)
이커머스 앱에서 AR 기능처럼 일부 사용자만 쓰는 무거운 기능을 분리하면 초기 설치 크기를 크게 줄일 수 있다.
2021년 8월부터 Google Play Store는 신규 앱에 AAB를 의무화했다. 하지만 몇 가지 제약이 있다:
AAB가 리소스 최적화를 담당한다면, R8은 코드 최적화를 책임진다. ProGuard의 후속으로 개발된 R8은 더 빠르고 강력한 최적화를 제공한다.
1. 코드 축소 (Shrinking)
사용하지 않는 코드를 찾아서 제거한다. 실제로 놀라울 정도로 많은 코드가 제거된다.
// 축소 전
public class UserRepository {
public User getUser(int id) { ... } // 사용됨
public void deleteUser(int id) { ... } // 미사용
public List<User> getAllUsers() { ... } // 미사용
private void logAccess() { ... } // 미사용
}
// 축소 후
public class UserRepository {
public User getUser(int id) { ... }
}
2. 난독화 (Obfuscation)
리버스 엔지니어링을 어렵게 만든다. 특히 금융 앱이나 게임처럼 보안이 중요한 경우 필수다.
// 난독화 전
com.myapp.payment.PaymentProcessor.processPayment()
// 난독화 후
a.b.c.a()
3. 최적화 (Optimization)
기본 설정은 간단하다:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true // 리소스도 함께 축소
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
하지만 실제로는 각 프로젝트에 맞는 규칙 설정이 중요하다:
# Retrofit 모델 클래스 유지
-keep class com.myapp.api.model.** { *; }
# Gson을 위한 필드명 유지
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# JavaScript 인터페이스 보호
-keepclassmembers class com.myapp.WebAppInterface {
public *;
}
APK에서 AAB로, ProGuard에서 R8로의 전환은 단순한 도구의 변화가 아니다. 사용자 경험을 개선하고 앱의 품질을 높이는 중요한 진화다.
특히 한국처럼 5G가 보편화되었다고 해도, 앱 크기 최적화는 여전히 중요하다:
다음 릴리즈에 AAB와 R8을 적용해보는 건 어떨까? 처음엔 설정이 번거로울 수 있지만, 한 번 세팅하면 지속적인 이익을 가져다준다. 무엇보다 "우리 앱 용량이 너무 커요"라는 리뷰가 줄어드는 것만으로도 충분한 가치가 있다.