https://developer.android.com/studio/build/multidex.html
-
DEX file 의 method index 는 16bit 로 제한되어 있다.
이는 2^16 인 65,536 갯수 이상의 method reference 를 가질 수 없다는 것이다.
이 숫자에는 android framework methods, library methods, 그리고 너의 코드에 있는 methods 를 포함한 것이다.
64K 가 많아보이지만, android support lib 을 비롯하여 3rd party lib 이 들어가는 순간 쉽게 over 할 수 있다.
자주 쓰이는 Guava 나 Jackson 같은 녀석들은 특히 많은 method 를 가진 lib 으로 유명하다.
-
method limit 으로 빌드를 할 수 없다면 다음 형태의 에러가 발생한다.
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
-
jumboMode 라는 녀석이 있고, 사람들은 이 녀석을 조작하면 해결될 것이라 하는데.. 이 녀석과 이 method limit 은 상관 없다고 한다.
-
MultiDex 를 피하는 방법들은 다음과 같다. ( 돼왕 : 1번 이외에는 사실 권장되지 않는 방법이라 생각한다. )
1. Proguard 를 사용하여 unused function 등을 제거한다.
2. 3rd patry lib 을 사용한다면 & 해당 버전에 대한 분석 등이 끝났다면, 사용하지 않는 녀석들을 trim 해서 새로운 lib 을 만들어 넣는다. (분석, 유지보수 등등이 쉽지 않다.)
3. 3rd paty lib 을 우리 코드로 import 시킨다. 다시 말하면, 필요한 부분만 발췌해서 가져오고 해당 3rd party lib 을 사용하지 않는다.
4. method 들을 native 단으로 이동한다. (JNI, so)
-
MultiDex 란 code 를 잘라서 여러개의 DEX 에 넣는 것을 의미한다.
ART 에서는 결국 여러개의 DEX 파일을 하나의 ELF(executable and linkable format) binary 로 만들기 때문에 괜찮다.
하지만 Dalvik 을 사용하는 LOS 이전 버전에서는 tool chain 이 몇가지 일을 더 수행해야 한다.
1. MultiDex support library 를 포함시켜야 하고, application 이 MultiDexApplication 을 상속하도록 하거나 MultiDex loader 를 직접 invoke 시켜줘야 한다.
2. Build time 이 증가한다.
3. preDexLibraries flag 가 작동하지 않는다. 이 말은 코드 한 줄만 바꾸어도 lib dependency 를 포함해서 re-dex 를 다시해야 하기 때문이다. ART 는 이 제약이 없다. 왜냐하면 모든 DEX file 이 하나의 OAT(Of Ahead Time) file 로 compile 되기 때문이다.
4. Dagger 같은 full class graph 가 필요한 lib 을 사용할 경우, 추가 DEX 파일이 object graph 를 만들기 전에 로드가 완료되어 있어야 한다. 이 말은 app constructor 에서 object graph 를 만들 수 없다는 얘기이다. 대신 attachBaseContext 를 override 해서 여기서 super 를 부른 후 만들어야 한다.
-
MultiDex 를 사용할 때 주의사항들이 있다. 특히 LOS 이전 버전에서..(https://developer.android.com/studio/build/multidex.html#limitations)
두번째 DEX 파일의 크기가 크다면, ANR 이 발생할 수 있다. -> Proguard 를 이용해서 code shrinking 을 해라.
5.0(API 21, LOS) 이전 버전에서 multidex 를 사용한다면 framework 의 linearalloc limit(복잡한 interface 사용시 발생) 때문에 주의를 기울여야 한다. (https://issuetracker.google.com/issues/37008143)
ICS 이전 버전에서는 DEX index limit 전에 linearalloc limit 을 먼저 마딱뜨리기 쉽다. 따라서 그 이전버전에서는 startup 이나 특정 class load 시 죽지 않는지 철저히 테스트해야 한다.
linearalloc limit은 ICS 에서 증가되었지만, 완벽히 문제가 해결된 것은 아니라, LOS 이전 버전도 마찬가지로 테스트가 잘 되어야 한다.
-
build performance 보완을 위해서 minSdkLevel 21 을 가진 flavor 를 만들어 사용하는 것도 idea 중 하나. (단! 이 때 min sdk level api 등의 lint 가 제대로 작동하지 않을테니 이런 것은 주의해야 한다.)
이렇게 하면 incremental build 의 성능이 좋아진다. (적은 change에 대한 새로운 빌드)
-
android 5.0 (LOS) 미만에서는 아래와 같은 설정을 통해 multidex 를 만들 수 있다.
// build.gradle
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
android{
defaultConfig{
..
multiDexEnabled true
}
}
Application 이 없었다면, manifest 에 바로 MultiDexApplication 을 바로 세팅해주면 된다.
<application
android:name="android.support.multidex.MultiDexApplication" >
…
Application 을 사용하고 있었다면 MultiDexApplication 을 상속하도록 고쳐야 한다.
만약 MultiDexApplication 을 상속하도록 하는 것도 쉽지 않다면.. attachBaseContext() 를 override 해서 super 이후에 MultiDex.install(this) 를 호출해주어야 한다.
public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } ... }
MultiDex.install 을 호출하기 전에 reflection 이나 JNI 콜을 하지 않도록 주의해야 한다.
만약 이를 어기면 ClassNotFoundException 나 VerifyError 가 발생한다. ( 다른 dex 파일에 대한 로드가 끝나지 않아서 )
Multidex 가 되면 classes.dex, classes2.dex, classes3.dex 등이 생성된다.
그리고 runtime 에는 특별한 class loader 를 사용해서 DEX files 에 있는 method 를 찾아 수행한다.
-
android 5.0 이상에서는 ART 를 사용한다.
ART 는 기본적으로 multi dex file load 를 제공한다.
ART 가 앱 설치 타임에 classesN.dex 파일들을 찾아서 하나의 .oat 파일로 만들고, 이 녀석으로 수행한다.
그래서 minSdkVersion 21 이상에서는 multidex support lib 을 포함할 필요가 없다.
대신 android.defaultConfig 에 multiDexEnabled 를 true 는 주면 모두 끝이다.
-
Multidex 를 만들 때 build tool 은 어떤 class 를 primary dex 에 넣어야 하는지 복잡한 절차를 걸쳐 결정한다.
startup 때 필요한 class 가 primary DEX 에 없다면 앱은 NoClassDefFoundError 를 뱉으며 죽을 것이다.
이 경우 primary DEX 에 꼭 들어가야 하는 것을 build type 에 multiDexKeepFile 이나 multiDexKeepProguard 로 정의해주어야 한다.
ex1)
// multidex-config.txt
com/example/MyClass.class
com/example/MyOtherClass.class
// build.gradle
android {
buildTypes {
release {
multiDexKeepFile file('multidex-config.txt')
...
}
}
}
ex2)
// multidex-config.pro
-keep class com.example.MyClass
-keep class com.example.MyClassToo
// -keep class com.example.** { *; } 로 해당 package 모두를 명시할 수도 있다.
// build.gradle
android {
buildTypes {
release {
multiDexKeepProguard file('multidex-config.pro')
...
}
}
}
-
multidex 를 사용하면, 어떤 class 를 첫번쨰 dex 에 넣고 어떤 class 를 다른 dex 에 넣을지 결정하는 복잡한 로직을 타면서 build time 이 많이 증가한다.
ART 에서는 (LOS, API 21 이상에서 사용 가능) pre-dexing 이 가능하다.
Android Studio 2.3 이상을 사용한다면 IDE 가 기본으로 LOS 이상 단말에 배포할 때 자동으로 해준다.
-
끝!!
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] AsyncLayoutInflater tutorial (0) | 2020.08.22 |
---|---|
[android] WorkManager 를 사용해보자 (0) | 2020.08.21 |
[android] Define data using entities - Room 에 대해 알아보자 (0) | 2020.08.19 |
[android] Accessing data using Room DAOs - Room 에 대해 알아보자 (0) | 2020.08.18 |
[android] 기초 - Room 에 대해 알아보자 (0) | 2020.08.17 |
댓글