[Android] Gradle 과 Android App 의 빌드 시스템

dEpayse
dEpayse_publication
19 min readFeb 3, 2023

--

이번 포스트에서는 Android 의 공식 빌드 시스템으로 사용되고 있는 Gradle 에 대하여 알아보려고 한다. Gradle 의 기본 개념을 잡고, Android 에서 필요할만한 지식들을 위주로 다룬다.

https://commons.wikimedia.org/wiki/File:Gradle_logo.png

Gradle 이란?

오픈 소스 빌드 자동화 툴이다. Gradle 을 사용하여 Compile, Test 등과 같은 일련의 과정을 한 번에 실행하는 등 빌드에 관련된 기능을 제공한다. 프로젝트 및 빌드에 대한 설정은 Gradle 빌드 스크립트(build.gradle)를 통해 할 수 있다. 스크립트 파일의 언어는 Groovy DSL 혹은 Kotlin DSL 을 지원한다.

Android Studio 에서도 기본적으로 Gradle 을 사용하는데, 예시로 Android Studio 에서 앱 모듈을 설정 변경 없이 실행하면 프로젝트를 컴파일하고, 리소스와 결합하여 apk 를 만들고, 서명된 apk 를 만들고, 기기에 설치하는 일련의 과정이 assembleDebug 라는 gradle task 를 통해 진행된다.

  • DSL(Domain Specific Language) : 특정 영역(도메인)에 특화된 언어로 Java, Kotlin 등 다양한 소프트웨어를 만들 수 있는 범용 프로그래밍 언어인 GPL(General Purpose Language) 과 반대되는 개념이다. Gradle 에서 말하는 DSL 은 DSL 중에서도 내부 DSL 에 속하는데, 이는 범용 언어로 작성된 프로그램의 일부이며, 따라서 범용 언어와 동일한 문법을 사용한다. 즉 호스트 언어인 범용 언어를 특별한 방법으로 사용하는 것을 말한다.

특징

  • 빌드 최적화 — 바뀐 파일들만 다시 빌드, Build Cache 를 통해 이전 빌드의 결과물을 다른 빌드에서 사용, 데몬 프로세스의 보관 등을 통해 빌드 최적화
  • JDK 필요 — JVM을 기반으로 동작하기 때문에 사용하려면 JDK 설치 필요

Interfaces

Gradle 의 빌드 과정에서 볼 수 있는 인터페이스들이다. Gradle 의 대략적인 빌드 과정을 보기 전에 주요 인터페이스들을 간단하게 알아보자.

1. Script

Gradle 은 작성된 *.gradle 을 읽어들여 Script 인스턴스를 생성한다. Script 인스턴스는 빌드 스크립트를 실행하는 기반이 된다.

2. Gradle

Gradle 인스턴스는 Gradle 설정, 전역 프로퍼티 설정 등 프로젝트에 종속되지 않는, Gradle 의 글로벌한 영역을 담당한다.

3. Settings

Gradle 은 프로젝트의 settings.gradle 파일로 Settings 인스턴스를 생성한다. settings.gradle 은 Android Studio 에서 어플리케이션을 목표로 하는 프로젝트 등을 생성할 때 기본적으로 생성해준다.

4. Project

Gradle 은 프로젝트의 build.gradle 파일로 Project 인스턴스를 생성한다. Project 인스턴스는 그 프로젝트의 빌드 과정에 실행되어야 할 Task 인스턴스들을 참조하고 있다. Project 인스턴스는 Task 인스턴스들의 컬렉션이라고도 말할 수 있다. build.gradle 역시 Android Studio 에서 생성하는 프로젝트에 기본적으로 생성되어 있다.

5. Task

build.gradle 파일에 선언된 하나의 task 는 하나의 Task 인스턴스가 된다. Task 인스턴스는 자신이 선언된 Project 인스턴스에 종속된다. 하나의 Task 인스턴스는 java 파일 컴파일, java doc 생성과 같이, 빌드 과정 중 수행되어야 할 하나의 과정을 의미한다. 하나의 task 는 자신이 실행될 Action 인스턴스들을 참조하고 있다. Project 인스턴스가 Task 인스턴스들의 컬렉션이듯, Task 인스턴스는 Action 인스턴스들의 컬렉션이라고 할 수 있다.

6. Action

build.gradle 파일로 생성된 Task 인스턴스가 실제 실행할 동작을 의미하는 인스턴스이다. Action 인스턴스는 자신이 선언된 Task 인스턴스에 종속된다.

Gradle 빌드 과정

미리 정해진 단계(Lifecycle Phases)에 따라 빌드를 수행한다. 각 단계에 맞는 script 를 읽어들이고, 각 파일에 성격에 해당하는 인스턴스를 생성한다.

  1. Initialization

Gradle 자체의 설정, 전역 프로퍼티 설정 등 현재 빌드 대상 프로젝트에 종속되지는 않지만 공통으로 적용되어야할 동작을 초기화한다. 그레이들이 빌드할 대상 프로젝트가 이 시점에 결정된다.

구체적인 동작은, init 관련 파일을 읽어 Gradle 인스턴스를 생성한다. 그리고 프로젝트의 settings.gradle 파일로 Settings 인스턴스를 생성한다. Gradle 이 빌드할 대상 프로젝트가 결정되면 build.gradle 을 참조하여 각 프로젝트의 Project 인스턴스를 생성하여 빌드 수행을 준비한다.

2. Configuration

현재 빌드 대상 프로젝트를 위한 설정을 적용한다. build.gradle 파일을 바탕으로, Initialization 단계에서 생성된 Project 인스턴스들에 빌드 설정을 적용한다. build.gradle 파일의 allprojects task 는 이 단계에서 실행된다.

3. Execution

Configuration 단계에서 준비된 내용을 바탕으로 Task 들이 실행될 순서 등을 정리하고, TaskAction 들을 실행한다.

Gradle Wrapper

Gradle 도 실행가능한 파일이 있고, 버전이 존재한다. 그런데 만약 PC 마다 다른 Gradle 로 빌드하게 된다면, 일정한 빌드를 보장할 수 없다. Gradle 은 gradle wrapper 를 제공하는데, 이를 이용하면 다른 환경에서도 동일한 빌드를 보장할 수 있다. Gradle 은 Gradle wrapper 사용을 권장하고, Android 역시 기본적으로 gradle wrapper 를 사용하여 빌드한다.

# wrapper 세팅 시 생성되는 파일 구조
.
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat

wrapper 세팅을 하면 gradle-wrapper.jar, gradle-wrapper.properties 와 실행 파일인 gradlew, gradlew.bat 이 생성되는데, 각각의 역할은 다음과 같다.

  • gradle-wrapper.jar : executable jar 파일으로, 필요한 버전의 gradle 을 실행할 수 있는지 확인하고, 없으면 zip 파일 다운로드와 압축 해제까지 실행해주는 파일이다.
  • gradle-wrapper.properties : gradle-wrapper.jar 파일에서 사용할 변수들을 포함한다. 사용할 gradle 버전은 이 파일의 distributionUrl 을 통해 확인하거나 변경할 수 있다.
  • gradlew, gradlew.bat : Gradle 을 Wrapper 로 실행할 수 있게 해주는 실행 파일이다. gradlew 는 Unix 에서 실행 가능한 파일,gradlew.bat 파일은 Windows 에서 실행 가능한 파일이다.

gradle-wrapper.jar 동작 과정

실제 동작이 궁금하여 jadx-gui 를 사용하여 gradle-wrapper.jar 파일 내부의 코드를 직접 확인하고, 분석해보니 아래와 같은 과정임을 알 수 있었다.

  1. executable jar 파일인 gradlew-wrapper.jar 를 실행하면, gradle-wrapper.properties 의 속성들을 사용하여 설정을 초기화한다.
  2. distributionBase + distributionPath 의 하위 폴더인 lib 폴더에 distributionUrl 에 명시된 버전의 gradle-launcher jar 파일이 있으면 바로 해당 버전의 gradle 을 실행할 수 있다.
  3. 만약 2번에서 gradle-launcher jar 파일이 없고, 해당 버전의 gradle zip 파일이 없으면 distributionUrl 을 통해 gradle 을 다운받아 zipStoreBase + zipStorePath 에 gradle zip 파일을 설치한 후, distributionBase + distributionPath 에 압축을 푼다. 이 과정이 완료되면 distributionUrl 에 명시된 버전의 gradle 을 실행할 수 있다.
  4. 해당 gradle 을 사용해 task 를 수행한다.

gradle-wrapper.properties 속성들의 의미

위의 과정을 보면 gradlew-wrapper.properties 에 명시된 속성들이 의미하는 바를 알 수 있다.

  • distributionBase + distributionPath : 사용될 gradle 의 위치를 의미하고, 해당 gradle 이 없을 때 해당하는 버전의 gradle 이 저장되는 곳이다.
  • distributionUrl : 사용할 Gradle 의 버전을 포함하고 있으며, 해당 버전이 위치에 없을 때 이 Url 을 사용하여 압축 파일을 다운로드한다.
  • zipStoreBase + zipStorePath : 다운로드 된 특정 버전 gradle의 압축 파일이 저장되는 위치이다. 압축 파일은 distributionBase + distributionPath 에 압축 해제되어 사용된다.

Android 프로젝트 기본 Gradle Scripts

Fig1. Android default gradle scripts

Fig1 은 Android 프로젝트를 생성했을 때, 보기 형태가 Android 인 상태에서 볼 수 있는 Gradle Script 들이다. 즉, Fig1 에서 볼 수 있는 각 파일들의 실제 디스크 상의 디렉토리는 Fig1 과 다르다. 이 파트에서는 각 파일들이 어떤 역할을 하는지 간단히 알아볼 것이다.

  • build.gradle (Project) — 프로젝트의 빌드 방법이 정의된 빌드 스크립트이다. 디스크 상에서는 프로젝트의 루트 디렉토리에 존재한다.
  • build.gradle (Module) — 모듈의 빌드 방법이 정의된 빌드 스크립트이다. 모듈마다 빌드 스크립트가 존재하며, 디스크 상에서는 모듈의 루트 디렉토리에 존재한다.
  • proguard-rules.pro — 작성한 코드가 컴파일 되어 배포된다고 해도 누군가 디컴파일해서 코드를 보고 악용할 수 있기 때문에, 코드를 난독화 해주는 서비스를 제공한다. 이 난독화에 대한 옵션을 설정하는 파일이다.
  • gradle.properties — 주로 빌드 환경을 설정하는 파일이다. 기본적으로 디스크 상에서는 프로젝트의 루트 디렉토리에 존재하지만, 이 파일은 다른 곳에 있을 수도 있다.
  • gradle-wrapper.properties — Gradle wrapper 에서 봤던 wrapper 관련 설정을 담고 있다. 디스크 상에서는 프로젝트 루트 디렉토리에서 /gradle/wrapper 로 이동하면 볼 수 있다.
  • local.properties — 로컬에서만 사용하는 설정을 포함하는 파일로, PC 마다 SDK 가 설치된 경로가 다를 수 있기 때문에 설치된 SDK 의 위치를 포함하고 있다. 기본적으로 공유되지 않도록 gitignore 에 포함되어 Git 에서 관리되지 않도록 설정된다. 디스크 상에서는 프로젝트의 루트 디렉토리에 존재한다.
  • settins.gradlebuild.gradle 과 다르게 하나의 Gradle 빌드 하나 당 하나만 존재하는 설정 파일이다. 디스크 상에서는 프로젝트의 루트 디렉토리에 존재한다.

이제부터 다루는 내용은 Android 에서 앱 모듈 Gradle 을 다룰 때, 흔하게 볼 수 있는 Plugin(플러그인) 과 Dependency(의존성) 에 관해 알아보려고 한다.

Gradle Plugin

Android 에서는 프로젝트를 빌드하기 위해서 Android Gradle Plugin 을 기본적으로 사용한다. 이 파트에서는 Gradle 의 Plugin 이 무엇이고, 기본적인 Android Gradle Plugin 과 Kotlin 으로 개발하기 위해 필요한 Kotlin Android Gradle Plugin 에 대해서 간단히 보려고 한다.

Gradle Plugin 이란 단순히 패키지org.gradle.apiPlugin 인터페이스를 구현한 클래스이다. 주요한 기능이라 하면 Gradle Task 들을 포함하고, 컴파일 할 때 특정 기능을 수행하는 등의 기능 등이 있다. 아래 링크에서 Gradle Api 7.6 버전의 Plugin 명세서를 볼 수 있다.

Android Gradle Plugin(AGP)

터미널의 프로젝트 루트 디렉토리에서 ./gradlew assembleDebug 을 실행하면 프로젝트가 빌드되고 apk 가 생성되는 이유는 assembleDebug 라는 task 를 com.android.application id 를 갖는 Gradle Plugin 에 포함해놓았기 때문이다. com.android.application은 Gradle Plugin 의 group id 이고, 편리한 빌드를 위해 android 를 제공하는 구글에서 Gradle Plugin 을 만들어 Gradle Plugin 에 많은 사람들이 이용할 수 있도록 올려 놓은 것이라고 볼 수 있다. com.android.application 이 plugin 으로 추가되어 있다면, assembleDebug 말고도 터미널의 프로젝트 루트 디렉토리에서./gradlew tasks --all 을 입력하면 실행할 수 있는 모든 task 들을 볼 수 있다.

상단에서 언급했듯, Android 의 빌드, 테스트, 실행 등과 관련된 task 들의 모음은 com.android.application 에 포함되어 있어서, 이 plugin 을 프로젝트와 모듈 단위의 build.gradle 에 추가해주면 해당 모듈에서 plugin 에 정의된 task 를 사용할 수 있다.

그러나 Android Gradle Plugin 은 요구하는 gradle 의 버전 범위가 있으니, 적용할 때 gradle-wrapper.properties 파일에서 현재 프로젝트에서 사용하고 있는 gradle 의 버전을 확인하고 사용하면 된다. 이 관계는 아래 링크에서 확인할 수 있다.

Android Studio 와 호환되는 Android Gradle Plugin 버전의 범위도 있는데, 이 역시 문서에서 찾아볼 수 있다.

Kotlin Android Gradle Plugin

Android 프로젝트에서 Kotlin 을 사용하기 위해 build.gradle 에 Kotlin 플러그인을 추가해주어야 한다.

Kotlin 의 gradle plugin group id 는 org.jetbrains.kotlin.android 이고, artifact id 는 kotlin-android 이다. Kotlin 언어를 선택한 프로젝트를 생성하거나 Kotlin 파일을 생성하면 Android Studio Chipmunk 에서는 자동으로 이 플러그인을 추가해준다.

이는 Android Studio 의 Kotlin Plugin 과는 다르다. 위에서도 언급했듯 Gradle Plugin 은 gradle 싱크 및 빌드 시 사용되지만, Android Studio 의 Kotlin Plugin 은 Android Studio IDE 에서 Kotlin 을 사용할 수 있게 해주는 것을 말한다. 아래는 Jetbrains Kotlin GitHub 에서 찾은 Kotlin Android Gradle Plugin 코드를 나타낸 파일의 GitHub 링크이다.

아래의 두 링크는 Android 개발 시 유용하게 사용할 수 있는 Kotlin Gradle Plugin 의 Github 링크이다.

Custom Gradle Plugin

이미 만들어진 Gradle Plugin 인 AGP 와 Kotlin Android Gradle Plugin 을 소개했지만, 물론 내가 원하는 Task 들을 만들 수도 있고, 이런 Task 들을 모아 Custom 한 Gradle Plugin 을 만들어서 사용할 수도 있다. 위에서 Android Gradle Plugin 과 Kotlin Android Gradle Plugin 을 소개한 이유는 Android 개발 시 필요한 공통적인 Task 들을 직접 정의해줄 필요 없이, 만들어놓은 Plugin 만 사용하면 되기 때문이다. 기본적으로 프로젝트를 생성하면 AGP 는 포함되어 있고, Kotlin 언어로 만들면 Kotlin Android Gradle Plugin 역시 포함되어 있다. 본 포스트에서는 Custom 한 Gradle Plugin 을 만드는 자세한 방법까지는 다루지 않는다. 위에서 간단히 언급했듯, Gradle API 에서 제공하는 Plugin 인터페이스를 구현하여 Plugin 을 생성할 수 있다.

Dependencies

Android 에서 이미지를 사용할 때 주로 Glide 라는 이미지 라이브러리를 사용하고, 서버와 통신할 때 주로 Retrofit 이라는 라이브러리를 사용한다. (물론 추후엔 변경될 수 있다.) 이런 라이브러리를 사용할 때 조금만 찾아보면 알 수 있지만, build.gradle 파일의 dependencies 에 버전과 라이브러리 이름 같은 것이 포함된 문자열을 추가하고 Sync 해준다.

Fig2. dependency 사용 예제 및 Sync 버튼

여기서 문자열은 google, maven, jcenter 같은 repository(저장소) 에 저장되어 있는 파일의 주소라고 볼 수 있다.

Gradle Sync 해주면 저장소에서 라이브러리를 가져와서 현재 프로젝트나 모듈에서 사용할 수 있게되는 것이다.

좀 더 구체적으로는 의존성이 선언된 라이브러리를 $GRADLE_USER_HOME/caches/modules-2/files-2.1 의 하위 폴더에 jar 파일들로 저장한다. 폴더명이 모든 PC 에서 같은지는 확신할 수 없지만, gradle 버전과 상관없이 저장되어 있는 파일임을 확인할 수 있었고, jar 파일로 저장되어있는 것을 볼 수 있었다. Android 프로젝트를 빌드할 때 이 jar 파일들을 참조한다는 것을 짐작할 수 있겠다.

이번 포스트에서는 Android 에서 사용되는 빌드 시스템인 Gradle 에 대해 알아보면서 Android 에서는 어떻게 적용되었고 어떤 과정으로 빌드되는지 이해할 수 있도록 Gradle 과 Android 의 핵심 내용들을 다뤄보았다. Android 의 빌드 시스템을 이해하는데 도움이 되었으면 좋겠습니다. :)

Reference

  1. [김정원] “안드로이드 개발자라면 알아야 하는 Gradle 원리” — https://medium.com/@renovatio0424/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%9D%BC%EB%A9%B4-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%98%EB%8A%94-gradle-%EC%9B%90%EB%A6%AC-c39a3299ba6d
  2. [박철우의 블로그] “그레이들 기본” — https://parkcheolu.tistory.com/180
  3. [Dev World] “Gradle 이란 무엇인가? 하는 일, 강점, 빌드 속도가 빠른 이유에 대해 알아보자.” — https://kotlinworld.com/311
  4. [Bryan Herbst] “Understanding the Gradle Wrapper” — https://medium.com/@bherbst/understanding-the-gradle-wrapper-a62f35662ab7
  5. [Gradle Docs] “Build Environment” —https://docs.gradle.org/current/userguide/build_environment.html
  6. [Baeldung] “Guide to the Gradle Wrapper” — https://www.baeldung.com/gradle-wrapper
  7. [Dev World] “Plugin이란 무엇인가? 플러그인 이해하고 Custom Plugin 만들기” — https://kotlinworld.com/323
  8. [랄라라] “DSL(Domain Specific Language) 이해하기” — https://unabated.tistory.com/entry/DSLDomain-Specific-Language-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
  9. [권남] “Gradle 빌드 환경 설정” — https://kwonnam.pe.kr/wiki/gradle/build_env

--

--

dEpayse
dEpayse_publication

나뿐만 아니라 다른 사람들도 이해할 수 있도록 작성하는, 친절한 블로그를 목표로.