빌드 에러 메시지
The number of method references in a .dex file cannot exceed 64K.
혹은 아래와 같은 런타임 에러 메시지
java.lang.NoSuchMethodError: No virtual method getScanFilter()Lcom/aasd/BleScanFilter; in class Lcom/abcd$Companion; or its super classes (declaration of 'com.abcd' appears in /data/data/com.abcd/code_cache/.overlay/base.apk/classes2.dex)
코딩을 하다보면 위와 같은 빌드 에러메시지가 발생하는 경우가 있습니다. 안드로이드 프로젝트 같은 경우 기본적으로 하나의 Dalvik Executable(Dex)형식의 실행가능한 바이트 코드 파일이 포함됩니다. 하지만, Dex파일은 메소드의 개수 65,536개가 최대이고, 메소드의 개수가 넘어갈 경우 여러개의 Dex파일을 로드할 수 있도록 멀티덱스 설정을 해주어야 합니다.
Gradle 설정
App의 build.gradle에 라이브러리 추가와 "multiDexEnable true"
를 추가해줍니다.
android {
defaultConfig {
multiDexEnabled true
}
}
dependencies {
implementation "androidx.multidex:multidex:2.0.1"
}
멀티덱스 설정하기
Application 클래스를 따로 만들지 않을 경우
Manifest.xml의 application 탭에 "androidx.multidex.MultiDexApplication"
를 추가해줍니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:name="androidx.multidex.MultiDexApplication" >
...
</application>
</manifest>
Application이 이미 존재할 경우
MultiDexApplication()을 상속해주면 멀티덱스를 설정하게 됩니다.
class MyApplication : MultiDexApplication() {...}
Application이 이미 존재하며, 다른 Application을 이미 상속할 경우
MultiDex.install(this)를 호출하면 멀티덱스를 설정하게 됩니다.
class MyApplication : SomeOtherApplication() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
추가하게 되면 apk에 여러개의 dex파일을 생성할 수 있게 됩니다.
MultiDex 사용시 주의점
primary Dex 파일 설정
MultiDex을 설정하게 되면, Primary Dex파일
이라는 것이 필요하게 됩니다.
Primary Dex파일이라는 것이 무엇이냐 앱이 성공적으로 start 할 수 있도록 필요한 Class들을 담은 Dex파일입니다. MultiDex를 설정하기 전, 단일 Dex 파일로 구성하였을 경우에는 이러한 Primary Dex파일 설정을 해줄 필요가 없었습니다. 왜냐하면, 단일 Dex 자체가 무조건 Primary Dex파일이기 때문입니다.
다시 돌아가서, Primary Dex파일에 앱을 실행할 때 필요한 Class들이 없다면, java.lang.NoClassDefFoundError
를 호출하며 앱이 죽을 것입니다. 그러므로, Primary Dex파일에 필요한 클래스들을 multiDexKeepFile
혹은 multiDexKeepProguard
로 정의해주어야 합니다.
1. multiDexKeepFile 설정
예를들면, 아래와 같은 형식으로 앱 실행에 필요한 클래스들을 multidex-config.txt
라는 파일에 추가합니다.
com/example/FirstClass.class
com/example/SecondClass.class
그리고 아래와 같이 추가하면 Primary Dex
에 클래스들을 추가할 수 있습니다.
android {
buildTypes {
release {
multiDexKeepFile file('multidex-config.txt')
}
}
}
2. multiDexKeepProguard 설정
프로가드 형식으로도 Primary Dex파일을 구성할 수 있습니다.
예를들면, multidex-config.pro
라는 파일을 아래와 같이 구성할 수 있습니다.
-keep class com.example.FirstClass
-keep class com.example.SecondClass
-keep class com.example.** { *; } // All classes in the com.example package
-keep public enum com.example.**{ // All enum classes in the com.example package
*;
}
android {
buildTypes {
release {
multiDexKeepProguard file('multidex-config.pro')
...
}
}
}
Multidex 사용하기 전에 Proguard로 최적화 하기
하지만, 이렇게 앱의 크기가 많이 커져서 dex파일이 늘어날 경우에는 빌드속도가 느려질 수 있으므로 Multidex를 적용하기 전에, 프로가드를 적용한다면 최적화 할 수 있습니다. 프로가드는 기본적으로 난독화를 적용하여 앱 보안에 사용되지만 프로가드를 사용하여 필요한 클래스들만 남기고 나머지 클래스들은 제거하여 Dex파일을 최소한으로 줄일 수 있습니다.
프로가드를 설정하게 되면 debug 과정에서 필요한 정보들도 함께 지워지므로 release 빌드할때만 프로가드 설정을 해주는 것이 필요합니다.
proguard-debug.pro
의 프로가드 설정으로는 아래와 같이 난독화를 수행하지 않도록 지정해줍니다.
-dontobfuscate // 난독화 수행하지 않음
-keepattributes SoureFile,LineNumberTable // 소스파일 정보와 라인 넘버 정보를 유지하도록 합니다.
minifyEnabled true -> 난독화를 수행합니다.
shrinkResources true -> 리소스 축소.
android {
...
buildTypes {
debug {
minifyEnabled true // Enables code shrinking, obfuscation, and optimization
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' // 동일 프로가드 설정
proguardFile 'proguard-debug.pro' // 디버그용 프로가드 설정
}
release {
shrinkResources true // 리소스 축소
minifyEnabled true // Enables code shrinking, obfuscation, and optimization
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' // 동일 프로가드 설정
}
}
}
프로가드 적용 후 apk 파일
멀티덱스 적용 한 후의 여러개의 dex파일이 생성된 것과는 다르게 dex파일이 현저하게 줄어들어 다시 단일 dex로 돌아간 것을 확인할 수 있습니다
멀티덱스 적용 apk 파일(old) vs 프로가드 적용 후 apk 파일 (new)
이전 멀티덱스를 적용한 apk파일과 비교 해보면 더욱 더 현저하게 줄어든 것을 확인하실 수 있습니다.
또 주의할 점은, 난독화를 적용했을 경우에 코드에 리플렉션을 사용한 부분이 있다면 클래스명이나 메소드이름을 찾지 못하므로 추가로 proguard에서 난독화 해제를 해주어야합니다.
참고