봄날은 갔다. 이제 그 정신으로 공부하자

Multidex 2편 - Multidex 라이브러리의 제한사항과 개발빌드에서 Multidex 최적화 본문

Android jetpack

Multidex 2편 - Multidex 라이브러리의 제한사항과 개발빌드에서 Multidex 최적화

길재의 그 정신으로 공부하자 2021. 1. 27. 11:11

이번 글에서는 지난 글에 이어서 조금 심화된 내용인 Multidex 사용시 발생할 수 있는 이슈와 해결방법 그리고 개발 환경에서 최적화에 대해 설명합니다.

 

Multidex 라이브러리 제한사항

Multidex 라이브러리에는 몇 가지 알려진 제한 사항이 있으며 이 라이브러리를 앱 빌드 구성에 통합할 때 이러한 제한 사항을 파악하고 테스트해야 합니다.

 

첫번째 제한 사항

시작 중에 기기 데이터 파티션에 DEX 파일을 설치하는 작업은 복잡하며 보조 DEX 파일이 큰 경우 애플리케이션 응답 없음(ANR) 오류가 발생할 수 있습니다.  이 문제를 방지하려면 앱 축소를하여 DEX 파일의 크기를 최소화하고 코드에서 사용되지 않는 부분을 삭제합니다.

 

두번째 제한 사항

Android 5.0(API 수준 21) 이전 버전에서 실행 중인 경우 멀티덱스를 사용하는 것만으로는 linearalloc 제한을 해결하는 데 충분하지 않습니다.  이 제한은 Android 4.0(API 레벨 14)에서 증가했지만, 완전히 해결되지 않았으므로 Android 4.0보다 낮은 버전에서는 DEX 색인 제한에 도달하기 전에 linearalloc 제한에 도달할 수 있습니다. 

따라서 API 수준 14 미만을 타겟팅한다면 시작 시 또는 특정 클래스 그룹이 로드될 때 앱에 문제가 있을 수 있으므로 이러한 플랫폼 버전은 철저히 테스트해야 합니다.

 

Java.long.NoClassDefFoundError

Multidex 앱의 각 DEX 파일을 빌드할 때 빌드 도구는 앱이 성공적으로 시작될 수 있도록 복잡한 의사결정 과정을 통해 기본 DEX 파일에 어떤 클래스가 필요한지 결정합니다. 

시작 시 필요한 클래스가 기본 DEX 파일에 제공되지 않으면 앱이 java.lang.NoClassDefFoundError 오류와 함께 비정상 종료됩니다.

 

빌드 도구에서 이러한 코드 경로를 인식하므로 앱 코드에서 직접 액세스하는 코드에는 비정상 종료가 발생해서는 안 됩니다. 그러나 사용하는 라이브러리에 복잡한 종속 항목이 있는 경우와 같이 코드 경로가 덜 명확하다면 비정상 종료가 발생할 수 있습니다. 

예를 들어 코드가 네이티브 코드에서 자바 메서드 검사 또는 호출을 사용한다면 이러한 클래스는 기본 DEX 파일에 필요한 것으로 인식되지 않을 수 있습니다.

 

따라서 java.lang.NoClassDefFoundError를 수신한다면

빌드 유형에서 기본 DEX 파일에 필요한 추가 클래스를 multiDexKeepFile 또는 multiDexKeepProguard 속성으로 선언하여 수동으로 지정해야 합니다.  클래스가 multiDexKeepFile 또는 multiDexKeepProguard 파일에서 일치하면 이 클래스는 기본 DEX 파일에 추가됩니다.

 

MultiDexKeepFile 속성

multiDexKeepFile에서 지정한 파일에는 com/example/MyClass.class 형식으로 줄당 클래스 하나가 포함되어야 합니다. 

예를 들어, 다음과 같은 multidex-config.txt라는 파일을 만들 수 있습니다.

com/example/MyClass.class
com/example/MyOtherClass.class

 

그리고 이 파일을 다음과 같이 빌드 유형에 선언할 수 있습니다.

android {
    buildTypes {
        release {
            multiDexKeepFile file('multidex-config.txt')
            ...
        }
    }
}

 

Gradle은 build.gradle 파일에 상대적인 경로를 읽기 때문에 위 예는 multidex-config.txt가 build.gradle 파일과 같은 디렉터리에 있을 때 작동합니다.

 

multiDexKeepProguard 속성

multiDexKeepProguard 파일은 Proguard와 동일한 형식을 사용하고 전체 Proguard 문법을 지원합니다.

multiDexKeepProguard에서 지정한 파일에는 유효한 ProGuard 구문으로 된 -keep 옵션이 포함되어야 합니다. 

예를 들어, -keep com.example.MyClass.class입니다. 다음과 같이 multidex-config.pro라는 파일을 만들 수 있습니다.

-keep class com.example.MyClass
-keep class com.example.MyClassToo

 

패키지에서 모든 클래스를 지정하고 싶다면 파일은 다음과 같은 형식을 취해야 합니다.

-keep class com.example.** { *; } // All classes in the com.example package

 

그리고 이 파일을 다음과 같은 빌드 유형에 관해 선언할 수 있습니다.

android {
    buildTypes {
        release {
            multiDexKeepProguard file('multidex-config.pro')
            ...
        }
    }
}

 

개발 빌드에서 Multidex 최적화

일반적으로 Multidex를 사용하는 증분 빌드는 시간이 더 오래 걸립니다.

이러한 빌드 시간을 줄이려면 pre-dexing을 사용하여 빌드 간에 Multidex 출력을 재사용해야 합니다.

하지만 pre-dexing은 android 5.0 이상에서만 사용할 수 있는 ART가 필요하므로 아래와 같이 build.gradle을 수정하여 개발 버전에서는 android 5.0을 사용하도록 수정해줍니다.

android {
    defaultConfig {
        ...
        multiDexEnabled true
        // 앱의 minSdkVersion 버전
        minSdkVersion 15
    }
    productFlavors {
        // Includes settings you want to keep only while developing your app.
        dev {
            // 명령 줄 빌드를위한 pre-dexing을 사용합니다. 
            // Android 스튜디오 2.3 이상을 사용하는 경우 IDE는 minSdkVersion에 대해 설정 한 항목에 
            // 관계없이 Android 5.0 (API 레벨 21) 이상을 실행하는 기기에 앱을 배포 할 때 
            // pre-dexing을 활성화합니다.
            minSdkVersion 21
        }
        prod {
            // 앱의 프로덕션 버전에 defaultConfig 블록을 구성한 경우, 
            // 이 블록을 비워두면 Gradle이 대신 defaultConfig 블록의 구성을 사용합니다. 
            // 이 블록이 없으면 그렇지 않으면 모든 빌드가  위의 dev 구성을 사용합니다.
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                                                 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation "androidx.multidex:multidex:2.0.1"
}

 

정리

뜬금없이 Multidex 생각나서 간략히 정리한다는게 길어졌네요. _

Comments