[요약] Make your build faster and more robust with the latest Android Gradle plugin (Android Dev Summit '21)
Oct 31, 2021. | By:
pluulove
KSP
- KAPT를 대체하는 Kotlin 용 Annotation Processor
- KAPT 대비 최대 2배 이상 빠르게 실행 → 빌드 속도 향상
- Room, Moshi 등에서 사용 중
non-transitive R classes
- R class에는 해당 프로젝트에 선언된 리소스만 포함되고, 종속성에는 포함되지 않음으로 R 클래스의 크기가 줄어든다
- Refactor > Migrate to Non-transitive R Classes로 실행할 수 있다
- 새로운 모듈을 추가할 때 유용하며 활성화 시 40% 증분 시나리오의 향상이 있다
- Clean Build는 5 ~ 10% 개선
- Arctic Fox에서도 사용할 수 있다
- 이미 AndroidX 라이브러리에서는 사용 중
# gradle.properties
android.nonTransitiveRClass=true
Lint
- checkDependencies가 true로 설정되면 Lint 분석 작업을 모듈별로 병렬로 실행한다
- AGP 7.1 alpha-13부터 Lint 분석 작업은 Gradle 빌드 캐시와 호환된다
- AGP 4.2대비 약 2배의 성능 향상되었으며, AGP 7.1에서 훨씬 극적인 개선이 이루어짐
# gradle.properties
org.gradle.caching=true
일반적인 개선 사항
- Gradle 빌드 캐시를 활성화하기 위해서 gradle.properties에 플래그를 추가해야 한다
- Lint에 충분한 메모리가 할당되었는지 확인해야 한다
- https://googlesamples.github.io/android-custom-lint-rules/user-guide.html#performancetuning
- application module에 lintOptions 블록에 checkDependencies를 true로 설정해야 한다.
- Lint가 더 빠르게 실행되지 않지만, 많은 문제를 포착할 수 있다
- 단일 Lint 보고서를 생성한다
Configuration cache
- 빌드가 시작될 때 Gradle은 빌드 작업을 실행하는 데 사용되는 작업 그래프를 생성한다
- 구성 단계를 호출할 경우 몇 초에서 수십 초까지 걸릴 수 있다
- Configuration cache는 Build Configuration 단계의 출력을 캐싱 후 재사용하는 Gradle 기능이다
- 최신 Kotlin, Gradle, AGP를 사용하는 24개의 하위 프로젝트에서는 Clean Build, public 메소드를 추가하는 증분 빌드, 메소드 본문을 수정하는 증분 빌드 모두 빌드 속도가 20% 향상되었다
- Gradle의 모든 작업이 완전히 구성되면 Gradle은 최종 task 그래프를 계산한다
- Configuration cache는 이 작업 그래프를 저장하고 task 상태를 직렬화하여 캐시에 저장한다
- Configuration cache 재사용이 가능한 경우, 저장된 Configuration cache 항목을 사용하여 task 인스턴스를 생성한다
- 빌드가 Configuration cache와 호환되는지 확인하기 위해 Arctic Fox에서 Build Analyzer에 관련 항목이 추가되었다.
- 현재 Builde configuration으로는 9.8초가 소요되었다.
- Try Configuration cache in a build를 클릭하면, Gradle properties 파일이 업데이트되고, Configuration cache를 활성화하는 플래그가 추가된다
- 빌드가 Configuration cache와 호환되지 않는 경우 빌드가 실패하고 디버깅 정보를 출력한다
Configuration cache와 비호환 사례
다음 예는 Configuration cache와 호횐되지 않는 사례이다.
- git sha를 계산하고 파일에 출력하는 task에는 2가지 Configuration cache 문제가 있다
- 첫 번째는 파일 출력 위치를 반환하는 함수(getOutputFile)에 프로젝트 작업이 있기 때문에 발생했다.
- 두 번째는 task에서 프로젝트의 사용이다. 이것은 Configuration cache가 활성화된 상태에서 액세스할 수 없는
전역 단계
이다.
Configuration cache와 호환 사례
- task properties에 필요한 정보를 저장할 수 있다. 이것들이 Configuration cache에 저장된다
- 외부 프로세스를 실행할 수 있는 Gradle inject service에 의존할 수도 있다
- task 등록 중에 configuration 속성에 출력 위치를 캡처한다. 주입된 Gradle 서비스는 Git 명령을 실행하는 데 사용된다.
- 실제 파일의 출력 위치는 task 등록 시 설정하도록 한다
- Docs
- Gradle documentation : https://docs.gradle.org/current/userguide/configuration_cache.html
- Android Developers Blog post ~ Configuration caching deep dive : https://medium.com/androiddevelopers/configuration-caching-deep-dive-bcb304698070
Extending Android Gradle Plugin
Variant와 Artifact의 의미
- AGP는 Build Type과 Flavor를 통해 variant 객체를 만들고, 각 variant 별 task를 생성한다. 이제 중간 Artifact 중 일부가 공개된다.
AGP 7.0부터는 아래 기능을 사용할 수 있다
- 중간 artifact를 수정
- DSL에 사용자 정의 요소 추가
- Variant API에 사용자 정의 속성을 추가
sample : https://github.com/android/gradle-recipes/tree/agp-7.1/BuildSrc/toyPluginAds2021
- 다음 예제는 Artifact를 수정하여 APK에 Asset를 추가하는 Task이다
- 단일 문자열 입력과 단일 디렉토리 속성 출력이 있으며, 디렉터리의 파일 작성에 쓰인다
- Variant/Artifact API를 사용하여 AddAssetTask를 등록하고 Artifact에 연결한다
- APK에 추가 Asset를 처리하는데 필요한 것은 위 코드가 전부이다
variant.artifacts
.use(taskProvider)
.wiredWith(AddAssetTask::outputDir)
.toAppendTo(MultipleArtifact.ASSETS)
- Task의 출력 디렉토리를 Asset 디렉토리에 추가하고 Task 종속성을 적절히 연결한다
- 여러 다른 중간 Artifact와 상호 작용할 수 있으며 그중 일부는 여기에 표시된다
- AGP는 이전 예제와 다른 방법으로도 Artifact와의 상호 작용을 지원한다
추가 자료는 New APIs in the Android Gradle Plugin(https://medium.com/androiddevelopers/new-apis-in-the-android-gradle-plugin-f5325742e614) 를 참고
Custom DSL API
- 추가 Asset의 콘텐츠를 설정하도록 DSL을 추가할 예정이다
- 최근 AGP에서는 기존 DSL에 사용자 정의 plugin용 DSL을 추가하는 기능을 추가했다. Build Type 별로 Asset 콘텐츠를 설정할 수 있다.
- 먼저 AGP의 DSL을 확장하려면 인터페이스가 필요하다
- 생성한 인터페이스를 AGP의 BuildType DSL에 추가할 수 있다. Product flavors도 가능하다
- onVariants 블록에서 해당 값을 가져와서 task의 입력으로 설정할 수 있다
Custom Variant API
DSL을 확장하는 것과 유사하게 자체 Gradle 속성 또는 공급자를 AGP의 변형 개체에 추가하여 변형 API를 확장할 수도 있습니다.
Variant API 확장 시 DSL 대비 얻는 이점
- Task의 출력으로 설정 가능하며, Task 종속성은 Gradle에서 자동으로 처리
- Variant 별 고유한 값을 쉽게 설정 가능
- 다른 plugin과 쉽게 상호 작용이 가능
- DSL 확장과 유사하게 인터페이스 생성이 필요하며, Provider를 사용한다
- Task의 출력을 사용하여 값을 설정할 수 있다
- build.gradle 파일에서 Variant API를 사용하여 각 Variant 별 고유 값 설정을 더 쉽게 할 수 있다
- Plugin에서 Variant API를 사용할 경우, beforeVariant 블록에서 사용할 수 있다
- 사용자 지정 Variant 인스턴스를 AGP의 Variant 객체에 Provider로 등록한다
- onVariants블록에 Variant extension를 등록할 수 없다
- onVariants 블록에서 액세스할 수 있는 모든 plugin에서 사용하려면 beforeVariants 블록에 등록해야 한다
- onVariants에서는 각 Variant 별로 처리해야 하는 Gradle plugin이 있는 경우에 사용자 정의 Variant 속성을 추가하는 방법이다
- Docs
- Extending AGP : https://developer.android.com/studio/build/extend-agp
- AGP Cookbook : https://github.com/android/gradle-recipes
- Configuration cache 위에서 빌드 되는 기능
- 각 프로젝트별 개별적으로 구성되며 프로젝트 간의 참조는 없다.
- 프로젝트별로 동기화 출력을 캐싱 가능하게 하여 빌드 파일이 변경되면 영향받는 프로젝트만 재구성하도록 한다
- Gradle 7.2에서 org.gradle.unsafe.isolated-projects=true를 통해서 테스트해 볼 수 있다
- Kotlin 증분 컴파일을 개선 중
- 예를 들어 Android 리소스 편집, 외부 종속성 추가, 다른 프로젝트 수정
comments powered by