Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

빌드 속도 최적화

빌드 시간이 오래 걸리면 개발 프로세스가 느려집니다. 이 페이지에서는 빌드 속도 병목 현상을 해결하는 데 도움이 되는 몇 가지 기법을 소개합니다.

빌드 속도를 개선하는 일반적인 방법은 다음과 같습니다.

  1. 대부분의 Android 스튜디오 프로젝트에서 즉시 활용할 수 있는 몇 단계를 통해 빌드 구성을 최적화합니다.
  2. 개발자의 프로젝트나 워크스테이션에만 있을 수 있는 까다로운 병목 현상을 식별하고 진단하기 위해 빌드를 프로파일링합니다.

앱 개발 시 가능하면 개발자는 Android 7.0(API 수준 24) 이상이 실행되는 기기에 앱을 배포해야 합니다. 더 새로운 버전의 Android 플랫폼은 업데이트를 앱으로 푸시하기 위한 더 나은 메커니즘을 구현합니다. 이러한 메커니즘에는 Android 런타임(ART)다중 DEX 파일 기본 지원이 있습니다.

참고: 이 페이지에 설명된 최적화를 전혀 사용하지 않더라도, 최초의 클린 빌드 후에는 이후의 빌드(클린 및 증분 빌드)가 더 빠르게 실행된다는 사실을 느끼실 수 있습니다. 그 이유는 성능 향상을 위한 '준비' 기간이 Gradle 데몬에 있기 때문이며, 이것은 다른 JVM 프로세스와 유사합니다.

빌드 구성 최적화

다음 도움말에 따라 Android 스튜디오 프로젝트의 빌드 속도를 개선해 보세요.

도구를 최신 상태로 유지

Android 도구는 거의 모든 업데이트에서 빌드 최적화 기능과 새로운 기능을 수신하며, 이 페이지의 일부 도움말에서는 개발자가 최신 버전을 사용 중이라고 가정합니다. 최신 최적화 기능을 활용하려면 다음을 최신 상태로 유지하세요.

개발 시 빌드 변형 생성

앱 출시를 준비할 때 필요한 상당수 구성은 앱 개발 중에는 필요 없습니다. 불필요한 빌드 프로세스를 사용 설정하면 증분 및 클린 빌드의 속도가 느려지므로, 앱 개발 중에 필요한 빌드 구성만을 유지하도록 빌드 변형을 구성하세요. 다음 샘플은 출시 버전 구성에 관해 'dev' 버전 'prod' 버전을 만듭니다.

android {
  ...
  defaultConfig {...}
  buildTypes {...}
  productFlavors {
    // When building a variant that uses this flavor, the following configurations
    // override those in the defaultConfig block.
    dev {
      // To avoid using legacy multidex when building from the command line,
      // set minSdkVersion to 21 or higher. When using Android Studio 2.3 or higher,
      // the build automatically avoids legacy multidex when deploying to a device running
      // API level 21 or higher—regardless of what you set as your minSdkVersion.
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
    }

    prod {
      // If you've configured the defaultConfig block for the release version of
      // your app, you can leave this block empty and Gradle uses configurations in
      // the defaultConfig block instead. You still need to create this flavor.
      // Otherwise, all variants use the "dev" flavor configurations.
    }
  }
}

빌드 구성이 이미 제품 버전을 사용하여 서로 다른 버전의 앱을 만드는 경우 버전 차원을 사용하여 'dev' 및 'prod' 구성을 이 제품 버전과 결합할 수 있습니다. 예를 들어 'demo' 및 'full' 버전을 이미 구성한 경우 다음 샘플 구성을 사용하여 'devDemo' 및 'prodFull'과 같은 결합된 버전을 만들 수 있습니다.

android {
  ...
  defaultConfig {...}
  buildTypes {...}

  // Specifies the flavor dimensions you want to use. The order in which you
  // list each dimension determines its priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.

  flavorDimensions "stage", "mode"

  productFlavors {
    dev {
      dimension "stage"
      minSdkVersion 21
      versionNameSuffix "-dev"
      applicationIdSuffix '.dev'
      ...
    }

    prod {
      dimension "stage"
      ...
    }

    demo {
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }
  }
}

단일 변형 프로젝트 동기화 사용 설정

빌드 구성과 프로젝트를 동기화하는 단계는 Android 스튜디오가 프로젝트 구성 방식을 이해하는 데 중요합니다. 하지만 대규모 프로젝트의 경우에는 이 과정에 시간이 오래 걸릴 수 있습니다. 프로젝트에서 빌드 변형을 여러 개 사용하는 경우 이제 프로젝트 동기화를 현재 선택한 변형으로만 제한하여 최적화할 수 있습니다.

이 최적화를 사용 설정하려면 Android 스튜디오 3.3 이상과 Android Gradle 플러그인 3.3.0 이상을 사용해야 합니다. 최적화는 모든 프로젝트에서 기본적으로 사용 설정됩니다.

최적화를 수동으로 사용 설정하려면 File > Settings > Experimental > Gradle(Mac은 Android Studio > Preferences > Experimental > Gradle)을 클릭하고 Only sync the active variant 체크박스를 선택합니다.

참고: 이 최적화는 자바 및 C++ 언어를 포함하는 프로젝트를 완전히 지원하며 Kotlin을 일부 지원합니다. Kotlin 콘텐츠가 포함된 프로젝트의 최적화를 사용 설정하면 Gradle 동기화는 전체 변형을 내부적으로 사용하는 방식으로 되돌아갑니다.

불필요한 리소스의 컴파일 피하기

테스트 중이 아닌 리소스(예: 추가적인 언어 현지화 및 화면 밀도 리소스)는 컴파일과 패키징을 피하세요. 그렇게 하려면 'dev' 버전에 관해 하나의 언어 리소스와 화면 밀도만을 지정하면 됩니다(다음 샘플 참조).

android {
  ...
  productFlavors {
    dev {
      ...
      // The following configuration limits the "dev" flavor to using
      // English stringresources and xxhdpi screen-density resources.
      resConfigs "en", "xxhdpi"
    }
    ...
  }
}

디버그 빌드 시 Crashlytics 사용 중지

Crashlytics 보고서를 실행할 필요가 없는 경우 다음과 같이 플러그인을 사용 중지하여 디버그 빌드의 속도를 높입니다.

android {
  ...
  buildTypes {
    debug {
      ext.enableCrashlytics = false
    }
}

또한 아래와 같이 앱에서 Fabric 지원을 초기화하는 방식을 변경하여 디버그 빌드 시 런타임에 Crashlytics 키트를 사용 중지해야 합니다.

Kotlin

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics.Builder()
        .core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
        .build()
        .also { crashlyticsKit ->
            Fabric.with(this, crashlyticsKit)
        }

자바

// Initializes Fabric for builds that don't use the debug build type.
Crashlytics crashlyticsKit = new Crashlytics.Builder()
    .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
    .build();

Fabric.with(this, crashlyticsKit);

자동 빌드 ID 생성 사용 중지

Crashlytics를 디버그 빌드와 함께 사용하려는 경우, 개발자는 모든 빌드 중에 Crashlytics가 자체의 고유 빌드 ID로 앱 리소스를 업데이트하는 것을 방지함으로써 증분 빌드의 속도를 높일 수 있습니다. 이 빌드 ID는 매니페스트에 의해 참조되는 리소스 파일에 저장되므로 자동 빌드 ID 생성을 사용 중지하면 디버그 빌드 시 Crashlytics와 함께 변경사항을 적용하는 기능을 사용할 수 있습니다.

Crashlytics가 빌드 ID를 자동으로 업데이트하는 것을 막으려면 다음 코드를 build.gradle 파일에 추가하세요.

android {
  ...
  buildTypes {
    debug {
      ext.alwaysUpdateBuildId = false
    }
}

Crashlytics 사용 중에 빌드를 최적화하는 방법에 관한 자세한 내용은 공식 문서를 참조하세요.

디버그 빌드에서 정적 빌드 구성 값 사용

디버그 빌드 유형의 경우 매니페스트 파일이나 리소스 파일에 들어가는 속성에는 항상 정적/하드 코딩 값을 사용해야 합니다.

예를 들어, 매니페스트 파일을 변경하는 동적인 버전 코드, 버전 이름, 리소스 또는 기타 빌드 로직을 사용하는 경우에는 변경할 때마다 전체 APK 빌드가 필요합니다. 단, 실제 변경에는 핫 스왑만 필요할 수도 있습니다. 이러한 동적 속성이 빌드 구성에 필요한 경우 이들 속성을 출시 빌드 변형으로 격리시키고 디버그 빌드에서 값을 정적으로 유지합니다(아래 build.gradle 파일 참조).

int MILLIS_IN_MINUTE = 1000 * 60
int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE

android {
    ...
    defaultConfig {
        // Making either of these two values dynamic in the defaultConfig will
        // require a full APK build and reinstallation because the AndroidManifest.xml
        // must be updated.
        versionCode 1
        versionName "1.0"
        ...
    }

    // The defaultConfig values above are fixed, so your incremental builds don't
    // need to rebuild the manifest (and therefore the whole APK, slowing build times).
    // But for release builds, it's okay. So the following script iterates through
    // all the known variants, finds those that are "release" build types, and
    // changes those properties to something dynamic.
    applicationVariants.all { variant ->
        if (variant.buildType.name == "release") {
            variant.mergedFlavor.versionCode = minutesSinceEpoch;
            variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName;
        }
    }
}

정적 종속 항목 버전 사용

종속 항목을 build.gradle 파일에 선언하는 경우, 끝에 더하기 기호가 있는 버전 번호를 사용해서는 안 됩니다(예: 'com.android.tools.build:gradle:2.+'). 동적 버전 번호를 사용할 경우 예상치 못한 버전 업데이트가 발생할 수 있고 버전 차이를 확인하기가 어려울 수 있으며 Gradle의 업데이트 확인으로 인해 빌드 속도가 느려질 수 있습니다. 대신 정적/하드 코딩 버전 번호를 사용해야 합니다.

라이브러리 모듈 생성

Android 라이브러리 모듈로 변환할 수 있는 코드를 앱에서 찾습니다. 이런 방식으로 코드를 모듈화할 경우, 빌드 시스템은 수정되는 모듈만을 컴파일할 수 있으며 향후 빌드를 위해 이러한 출력을 캐시할 수 있습니다. 또한 병렬 프로젝트 실행의 효과가 향상됩니다(최적화를 사용 설정하는 경우).

맞춤 빌드 로직을 위한 작업 생성

빌드 프로필을 생성한 후에 빌드 시간의 상당 부분이 '프로젝트 구성' 단계에 사용된 것으로 나타난다면 build.gradle 스크립트를 검토하고 맞춤 Gradle 작업에 포함할 수 있는 코드를 찾습니다. 일부 빌드 로직을 작업으로 옮겨놓으면 필요할 때만 이 작업이 실행되고, 이후 빌드에 사용하기 위해 결과를 캐시할 수 있으며, 이 빌드 로직을 병렬로 실행할 수 있게 됩니다(병렬 프로젝트 실행을 사용 설정한 경우). 자세히 알아보려면 공식 Gradle 문서를 참조하세요.

도움말: 빌드에 맞춤 작업이 다수 포함된 경우 맞춤 작업 클래스를 생성하여 build.gradle 파일을 단순하게 만들 수 있습니다. 클래스를 project-root/buildSrc/src/main/groovy/ 디렉터리에 추가해 놓으면 Gradle은 프로젝트의 모든 build.gradle 파일에 관해 이들 클래스를 클래스 경로에 자동으로 포함합니다.

WebP로 이미지 변환

WebP는 손실 압축(예: JPEG)과 투명도(예: PNG)를 제공하는 이미지 파일 형식이지만 JPEG나 PNG보다 더 나은 압축을 제공할 수 있습니다. 이미지 파일 크기를 줄이면 빌드 시간 압축을 하지 않고도 빌드 속도를 높일 수 있습니다(특히 많은 이미지 리소스가 앱에 사용되는 경우). 그러나 WebP 이미지의 압축을 해제하는 동안 기기 CPU 사용량이 약간 증가할 수 있습니다. Android 스튜디오를 사용하면 WebP로 이미지를 쉽게 변환할 수 있습니다.

PNG 크런칭 사용 중지

WebP로 PNG 이미지를 변환할 수 없는 경우(또는 변환을 원치 않는 경우) 앱을 빌드할 때마다 자동 이미지 압축을 사용 중지하여 빌드 속도를 높일 수 있습니다. Android 플러그인 3.0.0 이상을 사용하는 경우 '디버그' 빌드 유형에서만 PNG 크런칭이 기본적으로 사용 중지됩니다. 다른 빌드 유형에서도 이 최적화를 사용 중지하려면 build.gradle 파일에 다음을 추가합니다.

android {
    buildTypes {
        release {
            // Disables PNG crunching for the release build type.
            crunchPngs false
        }
    }

// If you're using an older version of the plugin, use the
// following:
//  aaptOptions {
//      cruncherEnabled false
//  }
}

빌드 유형이나 제품 버전은 이 속성을 정의하지 않으므로 출시 버전의 앱을 빌드할 때 이 속성을 true로 수동 설정해야 합니다.

증분 주석 프로세서 사용

Android Gradle 플러그인 3.3.0 이상에서는 증분 주석 프로세서의 지원이 향상됩니다. 따라서 증분 빌드 속도를 높이려면 Android Gradle 플러그인을 업데이트하고 가능한 경우 증분 주석 프로세서만 사용해야 합니다.

참고: 이 기능은 Gradle 버전 4.10.1 이상에서만 호환됩니다. 단, Gradle 5.1은 제외됩니다(Gradle 문제 #8194 참조).

시작하려면 증분 주석 프로세서를 지원하는 다음과 같은 인기 있는 주석 프로세서 테이블을 참조하세요. 전체 목록은 인기 주석 프로세서 지원 상태를 참조하세요. 일부 주석 프로세서에는 최적화를 위해 추가 단계가 필요할 수 있으므로 각 주석 프로세서에 관한 문서를 참조해야 합니다.

또한 앱에서 Kotlin을 사용하는 경우 kapt 1.3.30 이상을 사용해야 Kotlin 코드에 증분 주석 프로세서를 지원할 수 있습니다. 이 동작을 직접 사용 설정해야 하는지를 알아보려면 공식 문서를 참조하세요.

증분 빌드를 지원하지 않는 주석 프로세서를 하나 이상 사용해야 하는 경우 주석이 증분 처리되지 않습니다. 하지만 프로젝트에서 kapt를 사용하는 경우 자바 컴파일은 계속 증분됩니다.

증분 주석 프로세서 지원

프로젝트 이름주석 프로세서 클래스 이름지원 시기...
DataBindingandroid.databinding.annotationprocessor.ProcessDataBindingAGP 3.5
Roomandroidx.room.RoomProcessor2.3.0-alpha02

2.20: room.incremental 옵션을 사용하세요.
ButterKnifebutterknife.compiler.ButterKnifeProcessor10.2.0
Glidecom.bumptech.glide.annotation.compiler.GlideAnnotationProcessor4.9.0
Daggerdagger.internal.codegen.ComponentProcessor2.18
Lifecycleandroidx.lifecycle.LifecycleProcessor2.2.0-alpha02
AutoServicecom.google.auto.service.processor.AutoServiceProcessor1.0-rc7
Daggerdagger.android.processor.AndroidProcessor2.18
Realmio.realm.processor.RealmProcessor5.11.0
Lomboklombok.launch.AnnotationProcessorHider$AnnotationProcessor1.16.22
Lomboklombok.launch.AnnotationProcessorHider$ClaimingProcessor1.16.22

JVM 가비지 수집기 구성

Gradle에서 사용하는 최적의 JVM 가비지 수집기를 구성하여 빌드 성능을 개선할 수 있습니다. JDK 8은 기본적으로 병렬 가비지 수집기를 사용하도록 구성되어 있지만, JDK 9 이상에서는 G1 가비지 수집기를 사용하도록 구성됩니다.

빌드 성능을 개선하려면 병렬 가비지 수집기로 Gradle 빌드를 테스트하는 것이 좋습니다. gradle.properties에서 다음을 설정합니다.

org.gradle.jvmargs=-XX:+UseParallelGC

다른 옵션이 이미 이 필드에 설정되어 있으면 새 옵션을 추가합니다.

org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC

다양한 구성으로 빌드 속도를 측정하려면 빌드 프로파일링을 참고하세요.