Flutter 개발을 하면서 Gradle을 단순히 빌드 도구로만 인식하고, 그동안은 설정을 그대로 복붙해 사용하는 데 그쳤었다.
하지만 문법이 달라진 문서를 접하면서 단순히 따라 치는 방식에는 한계가 있음을 느꼈고, 이에 Gradle의 기본 개념과 문법을 제대로 이해할 필요성을 깨닫게 되어 이 글을 작성한다.
Gradle
Gradle은 Groovy 를 기반으로 한 오픈소스 빌드 도구이다.
Ant, Maven과 같은 기존의 빌드툴은 xml 형식을 이용하여 정적인 설정정보를 구성했다.
Gradle은 Groovy 라는 언어를 이용하여 코드로서 설정정보를 구성하기 때문에 구조적인 장점이 있다.
아래 코드 예시를 같이 보며 차이점을 한 번 알아보자!
Ant 예시
// build.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 프로젝트 빌드용 Ant 스크립트. build.properties의 내용을 기본 설정으로 사용한다.-->
<project name="common" default="compile">
<property name="src.dir" value="src" />
<target name="clean">
<delete dir="build"/>
</target>
<target name="compile">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes"/>
</target>
<target name="jar">
<mkdir dir="build/jar"/>
<jar destfile="build/jar/HelloWorld.jar" basedir="build/classes">
<manifest>
<attribute name="Main-Class" value="oata.HelloWorld"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="build/jar/HelloWorld.jar" fork="true"/>
</target>
</project>
Ant 는 프로젝트가 커지면 엄청 복잡해진다.
또한 규칙이 없기 때문에 개발자마다 스크립트를 짜는 스타일이 달라 이해하는데 많은 시간이 소요될 수 있다고 한다.
(= 절차적 빌드 도구의 성격을 가져서 사용자가 직접 "어떤 순서로 무엇을 할지" 일일이 적어야 한다)
Ant 는 remote repository 도 사용할 수 없다.
Maven 이나 Gradle 을 사용할 때는 Maven repository 에서 의존성을 찾아서 넣어주기만 하면 되는데, Ant 는 불가능하다. 직접 jar 를 받아서 넣어줘야 한다는 단점이 있다.
Maven 예시
// POM.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Maven 은 Java 용 프로젝트 관리도구로 Apache 의 Ant의 대안으로 만들어졌다.
외부 라이브러리를 관리하고, 표준화된 포맷을 제공한다. 하지만 여전히 POM.xml 라는 xml 로 관리되고 있다.
Maven 은 외부저장소에서 필요한 라이브러리와 플러그인들을 다운로드한 다음, 로컬시스템의 캐시에 모두 저장한다.
Gradle 예시
plugins {
id 'org.springframework.boot' version '2.3.4.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
Apache Maven 과 Apache Ant 의 대안으로써 나온 프로젝트 빌드 관리 툴인데 완전한 오픈소스이다.
Groovy 언어를 사용한 Domain-specific-language, DSL 을 사용한다.
Gradle 스크립트는 Groovy나 Kotlin DSL 로 작성할 수 있다.
- build.gradle → Groovy DSL
- build.gradle.kts → Kotlin DSL
여기서 Domain-specific-language (도메인 특화 언어) 뜻은 말 그대로 특정 목인인 도메인에 맞게 설계된 언어를 뜻한다.
자바, 파이썬, C 같은 언어는 어떤 프로그램이든 만들 수 있는 범용적인 언어라면 SQL, HTML, Regex 는 각각 DB, 웹문서, 문자열 패턴 매칭 도메인에 특화되어 있다는 뜻이다.
Maven 저장소도 그대로 사용 가능하며, xml 형식이 아니라서 Maven 보다 더 간결한 문법을 가지고 있다는 특징이 있다.
캐싱과 병렬 빌드는 역시 지원 가능하다.
찾아보니 요즘은 빌드 속도나 대규모의 멀티 프로젝트 관리 측면에서 Gradle 이 Maven 에 비해 우세를 가지고 있기 때문에 Gradle 사용이 점차 늘어나고 있다고 한다. (하지만 점유율은 Maven 이 아직까지 크다고 함)
Build.gradle
build.gradle 은 Gradle 을 쓰는 프로젝트라면 어디서든 쓰는 빌드 스크립트 파일 이름이다.
- Android: Android Studio 프로젝트는 기본이 Gradle이라 루트와 모듈(app 등) 각각에 build.gradle이 있다
- Spring Boot: Spring Boot는 Maven 또는 Gradle 중 고를 수 있는데, Gradle을 선택하면 프로젝트에 build.gradle이 생긴다
만약 spring boot 의 빌드 도구를 Maven 으로 선택하게 되면 pom.xml 파일에 프로젝트에 필요한 각종 의존성들과 라이브러리, 각 라이브러리의 버전 명시 등의 설정 정보를 역시 xml 형식으로 길게 나열하게 된다.
Android 와 Spring Boot 의 Build.gradle 예시를 찾아보니, 비슷한 모양새였다.
안드로이드
plugins {
id 'com.android.application'
id 'kotlin-android'
}
dependencies {
implementation 'com.google.android.gms:play-services-ads:24.5.0'
}
스프링 부트
plugins {
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
id 'java'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
즉, Gradle 은 "코드를 자동으로 빌드, 테스트, 패키징해주는 빌드 자동화 도구" 여서 안드로이드, 스프링 부트 모두 Gradle 을 써서 프로젝트를 만들고 실행, 배포한다.
근데 plugins 와 dependencies 의 차이점은 뭘까?
Plugins 와 Dependencies
plugin
- Gradle 빌드 시스템의 동작을 확장하거나 새로운 기능을 추가하는 모듈이다.
- 빌드 과정 자체를 바꾸거나 추가한다.
plugins {
id "com.android.application" // 안드로이드 앱 빌드 규칙 추가
id "kotlin-android" // 코틀린 코드 컴파일 지원
id "com.google.gms.google-services" // google-services.json 적용
}
특징 요약
- 빌드 과정에 새로운 task(작업)를 추가하거나 빌드 파이프라인을 확장.
- 예: com.android.application 플러그인이 있어야만 APK/AAB 빌드 가능.
- 빌드 타임에 영향을 준다.
dependencies
- 앱 실행 시 외부 라이브러리나 모듈이다.
dependencies {
implementation "androidx.core:core-ktx:1.12.0"
implementation "com.google.firebase:firebase-analytics"
testImplementation "junit:junit:4.13.2"
}
특징 요약
- 실제 애플리케이션 코드에서 사용하는 API, SDK, 유틸 등을 포함.
- APK/AAB 안에 라이브러리 코드가 함께 묶여 들어간다.
- 런타임/컴파일 타임에 영향을 준다.
Plugins 와 Dependencies 의 관계
- 어떤 기능은 플러그인 + 라이브러리가 짝으로 필요할 때가 있다
예: Crashlytics → 플러그인(com.google.firebase.crashlytics)은 매핑파일 업로드/빌드 연계를 하고,
라이브러리(com.google.firebase:firebase-crashlytics)는 앱에서 크래시를 실제로 수집·전송한다. - 플러그인을 쓴다고 라이브러리가 자동으로 들어오지 않는다.
반대로 라이브러리를 넣었다고 관련 플러그인이 자동 적용되는 것도 아니다. 용도에 따라 둘 다(혹은 하나만) 필요하다.
plugin 버전 관리
문서에서 아래와 같은 코드가 있고, apply false 도 같이 쓰여 있다.
루트 build.gradle.kts
// 최신 버전 작성 방식
plugins {
id("com.google.gms.google-services") version "4.4.3" apply false
// 다른 플러그인들도 여기서 버전만 고정
}
// 과거 버전 작성 방식
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.3'
}
}
위 코드의 의미는 해당 Gradle 플러그인을 “현재 모듈에는 적용하지 않고, 버전만 선언해 둔다” 는 뜻이다.
보통 루트 build.gradle[.kts](또는 settings.gradle의 pluginManagement)에서 이렇게 써서 플러그인 버전을 한 곳에서만 관리하고, 실제 적용은 각 서브모듈에서 하게 만든다.
apply false: 현재(루트) 프로젝트엔 적용 안 함. 하위 모듈에서 필요할 때 id("...") 만 적어 적용할 수 있음.
참고로 apply 를 생략하거나 apply true 면 그 파일의 모듈에 즉시 적용된다.
plugins {
id("com.android.application")
id("com.google.gms.google-services") // 여기서는 버전 없이 적용만!
}
서브 모듈인 App 에서 위와 같이 적용을 시킨다.
즉, 버전은 루트에 한 번만 적으므로 버전 일관성과 업데이트 관리가 쉬워지게 된다.
마무리
이번 글을 포스팅함으로써 Gradle을 단순히 빌드 도구로만 생각하고 복붙해서 쓰던 과거와 달리, 문법과 개념을 정리하면서 “왜 이렇게 동작하는지”를 알게 됐다.
Ant, Maven, Gradle의 차이를 비교해보니 빌드 도구도 진화해왔다는 게 눈에 보였고, plugins vs dependencies, apply false 같은 개념을 알게 되니 앞으로는 버전 관리나 설정을 훨씬 더 체계적으로 할 수 있기를 기대해본다!