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의 업데이트 확인으로 인해 빌드 속도가 느려질 수 있습니다. 대신 정적/하드 코딩 버전 번호를 사용해야 합니다.

오프라인 모드 사용 설정

네트워크 연결이 느린 경우 Gradle이 종속 항목 해결을 위해 네트워크 리소스를 사용하려고 시도하면 빌드 시간에 영향을 미칠 수도 있습니다. 이 경우 로컬로 캐시한 아티팩트만을 사용하고 네트워크 리소스는 사용하지 않도록 Gradle에 알릴 수 있습니다.

Android 스튜디오에서 빌드할 때 Gradle을 오프라인으로 사용하려면 다음 단계를 진행하세요.

  1. File > Settings(Mac은 Android Studio > Preferences)를 클릭하여 Preferences 창을 엽니다.
  2. 왼쪽 창에서 Build, Execution, Deployment > Gradle을 클릭합니다.
  3. Offline work 체크박스를 선택합니다.
  4. Apply 또는 OK를 클릭합니다.

명령줄에서 빌드 중인 경우 --offline 옵션을 누릅니다.

라이브러리 모듈 생성

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로 수동 설정해야 합니다.

빌드 캐시 사용 설정

빌드 캐시는 프로젝트를 빌드할 때 Gradle용 Android 플러그인이 생성하는 특정 출력(예: 패키지 해제된 AAR 및 사전 덱싱된 원격 종속 항목)을 저장합니다. 클린 빌드는 캐시를 사용하는 동안 훨씬 더 빠릅니다. 그 이유는 빌드 시스템이 후속 빌드 중에 캐시된 파일을 다시 생성하는 것이 아니라 재사용하면 되기 때문입니다.

Android 플러그인 2.3.0 이상을 사용하는 새 프로젝트에서는 기본적으로 빌드 캐시를 사용 설정합니다(명시적으로 빌드 캐시를 사용 중지하지 않는 한). 자세히 알아보려면 빌드 캐시로 클린 빌드 가속화를 참조하세요.

증분 주석 프로세서 사용

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

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

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

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

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

빌드 프로파일링

크기가 큰 프로젝트나 많은 맞춤 빌드 로직이 구현된 프로젝트에서는 병목 현상을 찾아내기 위해 빌드 프로세스를 더 깊이 들여다봐야 할 수 있습니다. 그렇게 하려면 Gradle이 빌드 수명 주기의 각 단계와 각 빌드 작업을 실행하는 데 얼마나 시간이 걸리는지를 프로파일링하면 됩니다. 예를 들어, Gradle이 프로젝트를 구성하는 데 너무 많은 시간을 소모한다고 빌드 프로필에 나타난다면 맞춤 빌드 로직을 구성 단계에서 삭제하라고 제안할 수 있습니다. 또한 mergeDevDebugResources 작업이 빌드 시간의 상당 부분을 차지하는 경우 WebP로 이미지를 변환하거나 PNG 크런칭을 사용 중지하라고 표시할 수도 있습니다.

Android 스튜디오 4.0 이상을 사용하는 경우 빌드 성능 문제를 조사하는 가장 좋은 방법은 빌드 분석 도구를 사용하는 것입니다.

명령줄에서 빌드 프로파일링

Android 스튜디오를 사용하지 않는다면 빌드 속도 문제 해결에는 일반적으로 프로파일링이 사용 설정된 채로 명령줄에서 빌드를 실행하는 작업, 빌드 구성을 조정하는 작업, 변경 결과를 관찰하기 위한 추가 프로파일링 작업이 포함됩니다.

빌드 프로필을 생성하고 보려면 다음 단계를 따르세요.

  1. 프로젝트 루트에서 명령줄 터미널을 엽니다.
  2. 다음 명령어를 입력하여 클린 빌드를 실행합니다. 빌드를 프로파일링할 때 Gradle은 작업에 관한 입력(예: 소스 코드)이 변하지 않을 때는 이 작업을 건너뛰므로, 개발자는 프로파일링되는 각 빌드 간에 클린 빌드를 실행해야 합니다. 따라서 입력 변화가 없는 두 번째 빌드는 작업이 재실행되지 않기 때문에 항상 더 빠르게 실행됩니다. 그래서 빌드 간에 clean 작업을 실행하면 전체 빌드 프로세스의 프로파일링이 보장됩니다.
    // On Mac or Linux, run the Gradle wrapper using "./gradlew".
    gradlew clean
    
  3. 제품 버전(예: 'dev' 버전) 중 하나의 디버그 빌드를 다음 플래그와 함께 실행합니다.
    gradlew --profile --offline --rerun-tasks assembleFlavorDebug
    
    • --profile: 프로파일링을 사용 설정합니다.
    • --offline: Gradle이 온라인 종속 항목을 가져오는 것을 중지합니다. 이렇게 하면 종속 항목 업데이트를 시도하는 Gradle에 의해 발생하는 모든 지연이 프로파일링 데이터와 충돌하지 않습니다. Gradle이 이미 종속 항목을 다운로드하고 캐시했는지 확인하려면 개발자가 한 번이라도 프로젝트를 이미 빌드했어야 합니다.
    • --rerun-tasks: 모든 작업을 재실행하고 모든 작업 최적화를 무시하도록 Gradle을 강제합니다.
  4. 그림 1. 프로필 보고서의 위치를 나타내는 프로젝트 뷰

    빌드가 완료된 후 Project 창을 사용하여 project-root/build/reports/profile/ 디렉터리로 이동합니다(그림 1 참조).

  5. profile-timestamp.html 파일을 마우스 오른쪽 버튼으로 클릭하고 Open in Browser > Default를 선택합니다. 보고서의 모양은 그림 2와 비슷합니다. 보고서의 각 탭을 검사하여 빌드에 관해 알아보세요. 예를 들어 Task Execution 탭은 Gradle이 각 빌드 작업을 실행하는 데 걸리는 시간을 나타냅니다.

    그림 2. 브라우저에서 보고서 보기

  6. 선택사항: 프로젝트나 빌드 구성을 변경하기 전에 3단계의 명령어를 반복하되 --rerun-tasks 플래그는 생략합니다. Gradle에서는 시간 절약을 위해 입력이 변경되지 않은 작업(이러한 작업은 그림 3의 보고서에서 Task Execution 탭에 UP-TO-DATE로 표시)을 재실행하지 않으므로 실행되면 안 될 때 실행되는 작업을 확인할 수 있습니다. 예를 들어 :app:processDevUniversalDebugManifestUP-TO-DATE로 표시되지 않은 경우 모든 빌드마다 빌드 구성이 매니페스트를 동적으로 업데이트하도록 제안할 수도 있습니다. 그러나 일부 작업은 각 빌드 중에 실행되어야 합니다(예: :app:checkDevDebugManifest).

    그림 3. 작업 실행 결과 보기

이제 빌드 프로필 보고서가 있으므로, 이 보고서의 각 탭에 있는 정보를 검사하여 최적화를 시작할 수 있습니다. 프로젝트와 워크스테이션 간에 이점 차이가 있을 수 있으므로 일부 빌드 설정에서는 실험이 필요합니다. 예를 들어 대량의 코드베이스가 있는 프로젝트는 코드 축소를 통해 미사용 코드를 삭제하고 APK 크기를 축소하는 이점이 있을 수 있습니다. 그러나 더 작은 프로젝트는 코드 축소를 모두 사용 중지할 때 더 이점이 있을 수 있습니다. 또한 Gradle 힙 크기를 늘리면(org.gradle.jvmargs 사용) 메모리 용량이 낮은 시스템에서 성능에 악영향을 미칠 수도 있습니다.

빌드 구성을 변경한 후 위의 단계를 반복하고 새 빌드 프로필을 생성하여 변경 결과를 관찰합니다. 예를 들어, 그림 4는 이 페이지에 설명된 기본적인 최적화를 동일한 샘플 앱에 적용한 후의 보고서를 보여줍니다.

그림 4. 빌드 속도를 최적화한 후의 새 보고서 보기

도움말: 더 강력한 프로파일링 도구가 필요하면 Gradle의 오픈소스 프로파일러를 사용해 보세요.