빌드 종속성 추가

Android 스튜디오의 Gradle 빌드 시스템을 사용하면 외부 바이너리 또는 다른 라이브러리 모듈을 빌드에 종속성으로 쉽게 포함할 수 있습니다. 종속성은 시스템 또는 원격 저장소에 위치할 수 있으며 종속성에서 선언하는 전이 종속성도 자동으로 포함됩니다. 이 페이지에서는 Gradle용 Android 플러그인과 관련한 동작 및 구성의 세부정보를 포함하여 Android 프로젝트에서 종속성을 사용하는 방법을 설명합니다. Gradle 종속성에 관한 자세한 개념 가이드를 보려면 Gradle 종속성 관리 가이드도 참조해야 하지만, Android 프로젝트에서는 이 페이지에서 정의하고 있는 종속성 구성만 사용해야 합니다.

종속성 유형

프로젝트에 종속성을 추가하려면 build.gradle 파일의 dependencies 블록에 implementation과 같이 종속성 구성을 지정합니다.

예를 들어 앱 모듈을 위한 다음의 build.gradle 파일은 세 가지 다른 종속성 유형을 포함합니다.

apply plugin: 'com.android.application'

    android { ... }

    dependencies {
        // Dependency on a local library module
        implementation project(":mylibrary")

        // Dependency on local binaries
        implementation fileTree(dir: 'libs', include: ['*.jar'])

        // Dependency on a remote binary
        implementation 'com.example.android:app-magic:12.3'
    }
    

이 유형은 각각 다음과 같이 서로 다른 라이브러리 종속성을 요청합니다.

로컬 라이브러리 모듈 종속성
implementation project(':mylibrary')

'mylibrary'라는 Android 라이브러리 모듈에 관한 종속성을 선언합니다(이 이름은 반드시 settings.gradle 파일에 include:를 사용하여 정의된 라이브러리 이름과 일치해야 함). 앱을 빌드할 때 빌드 시스템은 라이브러리 모듈을 컴파일하고 그 컴파일된 콘텐츠를 APK에 패키징합니다.

로컬 바이너리 종속성
implementation fileTree(dir: 'libs', include: ['*.jar'])

Gradle은 build.gradle 파일의 상대 경로를 읽기 때문에 프로젝트의 module_name/libs/ 디렉터리에 있는 JAR 파일에 관한 종속성을 선언합니다.

또는 다음과 같이 개별 파일을 지정할 수도 있습니다.

implementation files('libs/foo.jar', 'libs/bar.jar')
원격 바이너리 종속성
implementation 'com.example.android:app-magic:12.3'

위의 내용을 길게 풀면 다음과 같습니다.

    implementation group: 'com.example.android', name: 'app-magic', version: '12.3'
    

'com.example.android' 네임스페이스 그룹 안에 있는 'app-magic' 라이브러리의 버전 12.3에 관한 종속성을 선언합니다.

참고: 이와 같은 원격 종속성을 사용하려면 Gradle이 라이브러리를 찾을 수 있도록 적절한 원격 저장소를 선언해야 합니다. 라이브러리가 아직 로컬에 존재하지 않는 경우 Sync Project with Gradle Files(Gradle 파일과 프로젝트 동기화) 를 클릭하거나 빌드를 실행하는 때와 같이 빌드 시 라이브러리가 필요할 때 Gradle은 원격 사이트에서 라이브러리를 가져옵니다.

종속성 구성

dependencies 블록에 여러 다른 종속성 구성 중 하나를 사용하여 라이브러리 종속성을 선언할 수 있습니다(위의 implementation 참고). 각 종속성 구성은 Gradle에 종속성 사용 방법에 관한 서로 다른 안내를 제공합니다. 다음 표는 Android 프로젝트에서 종속성에 사용할 수 있는 각각의 구성을 설명한 것입니다. 또한 이 표는 이러한 구성을 Android Gradle 플러그인 3.0.0부터 지원이 중단된 구성과 비교하여 설명합니다.

새 구성 지원 중단된 구성 동작
implementation compile Gradle이 컴파일 클래스 경로에 종속성을 추가하고 빌드 출력에 종속성을 패키징합니다. 그러나 모듈이 implementation 종속성을 구성한다면 이는 Gradle에게 컴파일 타임에 다른 모듈로 종속성이 유출되면 안 된다고 알려주는 것입니다. 즉, 종속성은 런타임에만 다른 모듈에서 이용할 수 있습니다.

api 또는 compile(지원 중단됨) 대신 종속성 구성을 사용하면 빌드 시스템이 다시 컴파일해야 하는 모듈 수가 줄어들기 때문에 빌드 시간이 크게 향상될 수 있습니다. 예를 들어 implementation 종속성이 API를 변경하면 Gradle은 해당 종속성과 그에 직접적으로 종속된 모듈만 다시 컴파일합니다. 대부분의 앱과 테스트 모듈은 이 구성을 사용해야 합니다.

api compile Gradle은 컴파일 클래스 경로와 빌드 출력에 종속성을 추가합니다. 모듈이 api 종속성을 포함한다면 이는 모듈이 다른 모듈로 종속성을 전이하여 내보내고 싶다는 것을 Gradle에 알려주는 것이므로 다른 모듈에서 런타임과 컴파일 타임에 모두 사용할 수 있습니다.

이 구성은 compile(현재는 지원 중단됨)과 같이 작동하지만 주의해서 사용해야 하며 다른 업스트림 소비자에게 전이하여 내보내야 하는 종속성에만 사용해야 합니다. 그 이유는 api 종속성이 외부 API를 변경하면 Gradle이 컴파일 타임에 해당 종속성에 액세스할 권한이 있는 모듈을 모두 다시 컴파일하기 때문입니다. 따라서 api 종속성 수가 많아지면 빌드 시간이 많이 증가할 수 있습니다. 종속성의 API를 별도의 모듈로 내보내려는 경우가 아니라면 라이브러리 모듈은 대신 implementation 종속성을 사용해야 합니다.

compileOnly provided Gradle은 컴파일 클래스 경로에만 종속성을 추가합니다(즉, 빌드 출력에는 추가되지 않음). 이는 Android 모듈을 만들고 있으며 컴파일 중에 종속성이 필요한 경우에는 유용하지만 런타임에 이를 표시하는 것은 선택사항입니다.

이 구성을 사용하는 경우 라이브러리 모듈은 반드시 런타임 조건을 포함하여 종속성이 사용 가능한지 확인한 다음 제공되지 않는 경우에도 작동할 수 있도록 동작을 적절하게 변경해야 합니다. 이 방법을 사용하면 중요하지 않은 일시적인 종속성을 추가하지 않으므로 최종 APK의 크기를 줄이는 데 도움이 됩니다. 이 구성은 provided(현재는 지원 중단됨)와 동일하게 동작합니다.

runtimeOnly apk Gradle은 런타임 동안 사용하기 위해 빌드 출력에만 종속성을 추가합니다. 즉, 컴파일 클래스 경로에는 추가되지 않습니다. 이 구성은 apk(현재는 지원 중단됨)와 동일하게 동작합니다.
annotationProcessor compile 주석 프로세서인 라이브러리에 종속성을 추가하려면 반드시 annotationProcessor 구성을 사용하여 주석 프로세서 클래스 경로에 추가해야 합니다. 이 구성을 사용하면 주석 프로세서 클래스 경로에서 컴파일 클래스 경로를 분리하여 빌드 성능을 향상할 수 있기 때문입니다. Gradle은 컴파일 클래스 경로에서 주석 프로세서를 찾으면 컴파일 회피를 중지하는데 이는 빌드 시간에 부정적인 영향을 미칩니다(Gradle 5.0 이상에서는 컴파일 클래스 경로에서 찾은 주석 프로세서를 무시함).

JAR 파일이 아래 파일을 포함하고 있으면 Android Gradle 플러그인은 종속성을 주석 프로세서로 가정합니다.
META-INF/services/javax.annotation.processing.Processor 플러그인이 컴파일 클래스 경로에 있는 주석 프로세서를 감지하면 빌드 오류가 발생합니다.
lintChecks 프로젝트를 빌드할 때 Gradle이 실행할 Lint 검사를 포함하려면 이 구성을 사용합니다.

참고: Android Gradle 플러그인 3.4.0 이상을 사용할 때 이 종속성 구성은 더 이상 Lint 검사를 Android 라이브러리 프로젝트에 패키징하지 않습니다. AAR 라이브러리에 Lint 검사 종속성을 포함하려면 아래 설명한 lintPublish 구성을 사용하세요.

lintPublish Gradle이 lint.jar 파일로 컴파일하고 AAR로 패키징할 Lint 검사를 포함하려면 Android 라이브러리 프로젝트에 이 구성을 사용하세요. 그러면 AAR을 사용하는 프로젝트에서 Lint 검사도 적용합니다. 이전에 lintChecks 종속성 구성을 사용하여 게시된 AAR에 Lint 검사를 포함하고 있었다면 대신 lintPublish 구성을 사용하기 위해 종속성을 이전해야 합니다.

    dependencies {
      // Executes lint checks from the ':checks' project
      // at build time.
      lintChecks project(':checks')
      // Compiles lint checks from the ':checks-to-publish'
      // into a lint.jar file and publishes it to your
      // Android library.
      lintPublish project(':checks-to-publish')
    }

위의 구성은 종속성을 모든 빌드 변형에 적용합니다. 대신 하나의 특정 빌드 변형 소스 집합 또는 테스트 소스 집합을 위해 종속성을 선언하려면 반드시 구성 이름을 대문자로 지정하고 빌드 변형이나 테스트 소스 집합의 이름을 접두어로 붙여야 합니다.

예를 들어 'free' 제품 버전에만 implementation 종속성을 추가하려면(원격 바이너리 종속성 사용) 다음과 같이 설정합니다.

dependencies {
        freeImplementation 'com.google.firebase:firebase-ads:9.8.0'
    }
    

그러나 제품 버전 빌드 유형이 결합한 변형을 위해 종속성을 추가하려면 반드시 configurations 블록에서 구성 이름을 초기화해야 합니다. 아래 샘플에서는 runtimeOnly 종속성을 'freeDebug' 빌드 변형에 추가합니다(로컬 바이너리 종속성 사용).

configurations {
        // Initializes a placeholder for the freeDebugRuntimeOnly dependency
        // configuration.
        freeDebugRuntimeOnly {}
    }

    dependencies {
        freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar'])
    }
    

로컬 테스트와 계측 테스트를 위해 implementation 종속성을 추가하는 방법은 다음과 같습니다.

dependencies {
        // Adds a remote binary dependency only for local tests.
        testImplementation 'junit:junit:4.12'

        // Adds a remote binary dependency only for the instrumented test APK.
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    

그러나 이 상황에 맞지 않는 특정 구성이 있습니다. 예를 들어 다른 모듈은 androidTest에 종속될 수 없기 때문에 androidTestApi 구성을 사용하면 아래와 같은 경고가 표시됩니다.

    WARNING: Configuration 'androidTestApi' is obsolete and has been replaced with
    'androidTestImplementation'.
    

주석 프로세서 추가

파일 클래스 경로에 주석 프로세서를 추가하면 다음과 유사한 오류 메시지가 나타납니다.

    Error: Annotation processors must be explicitly declared now.
    

이 오류를 해결하려면 아래와 같이 annotationProcessor를 사용하여 종속성을 구성하는 방식으로 주석 프로세서를 프로젝트에 추가합니다.

    dependencies {
        // Adds libraries defining annotations to only the compile classpath.
        compileOnly 'com.google.dagger:dagger:version-number'
        // Adds the annotation processor dependency to the annotation processor classpath.
        annotationProcessor 'com.google.dagger:dagger-compiler:version-number'
    }
    

참고: Gradle 3.0.0+용 Android 플러그인은 더 이상 android-apt 플러그인을 지원하지 않습니다.

주석 프로세서에 인수 전달

주석 프로세서에 인수를 전달하려면 모듈의 빌드 구성에서 AnnotationProcessorOptions 블록을 사용하면 됩니다. 예를 들어 원시 데이터 유형을 키-값 쌍으로 전달하려면 아래와 같이 argument 속성을 사용할 수 있습니다.

android {
        ...
        defaultConfig {
            ...
            javaCompileOptions {
                annotationProcessorOptions {
                    argument "key1", "value1"
                    argument "key2", "value2"
                }
            }
        }
    }
    

그러나 Android Gradle 3.2.0 이상을 사용하는 경우 Gradle의 CommandLineArgumentProvider 인터페이스를 사용하여 파일이나 디렉터리를 나타내는 프로세서 인수를 전달해야 합니다.

CommandLineArgumentProvider를 사용하면 사용자 또는 주석 프로세서 작성자가 각 인수에 증분 빌드 속성 유형 주석을 적용하여 증분 및 캐시된 클린 빌드의 정확성과 성능을 개선할 수 있습니다.

예를 들어 아래의 클래스는 CommandLineArgumentProvider를 구현하고 프로세서의 각 인수에 주석을 단 것입니다. 또한 이 샘플은 Groovy 언어 구문을 사용하고 모듈의 build.gradle 파일에 직접 포함됩니다.

class MyArgsProvider implements CommandLineArgumentProvider {

        // Annotates each directory as either an input or output for the
        // annotation processor.
        @InputFiles
        // Using this annotation helps Gradle determine which part of the file path
        // should be considered during up-to-date checks.
        @PathSensitive(PathSensitivity.RELATIVE)
        FileCollection inputDir

        @OutputDirectory
        File outputDir

        // The class constructor sets the paths for the input and output directories.
        MyArgsProvider(FileCollection input, File output) {
            inputDir = input
            outputDir = output
        }

        // Specifies each directory as a command line argument for the processor.
        // The Android plugin uses this method to pass the arguments to the
        // annotation processor.
        @Override
        Iterable<String> asArguments() {
            // Use the form '-Akey[=value]' to pass your options to the Java compiler.
            ["-AinputDir=${inputDir.singleFile.absolutePath}",
             "-AoutputDir=${outputDir.absolutePath}"]
        }
    }

    android {...}
    

CommandLineArgumentProvider를 구현하는 클래스를 만든 후에는 아래와 같이 annotationProcessorOptions.compilerArgumentProvider 속성을 사용하여 해당 클래스를 초기화하고 Android 플러그인에 전달해야 합니다.

// This is in your module's build.gradle file.
    android {
        defaultConfig {
            javaCompileOptions {
                annotationProcessorOptions {
                    // Creates a new MyArgsProvider object, specifies the input and
                    // output paths for the constructor, and passes the object
                    // to the Android plugin.
                    compilerArgumentProvider new MyArgsProvider(files("input/path"),
                                             new File("output/path"))
                }
            }
        }
    }
    

CommandLineArgumentProvider 구현을 통해 빌드 성능을 향상하는 방법에 관한 자세한 내용은 자바 프로젝트 캐싱을 참조하세요.

주석 프로세서 오류 검사 중지

불필요한 주석 프로세서를 포함하는 컴파일 클래스 경로에 종속성이 있는 경우 다음을 build.gradle 파일에 추가하여 오류 검사를 중지할 수 있습니다. 컴파일 클래스 경로에 주석 프로세서를 추가해도 프로세서 클래스 경로에는 추가되지 않는다는 점에 유의하시기 바랍니다.

android {
        ...
        defaultConfig {
            ...
            javaCompileOptions {
                annotationProcessorOptions {
                    includeCompileClasspath false
                }
            }
        }
    }
    

프로젝트의 주석 프로세서를 프로세서 클래스 경로로 이전한 후 문제가 발생한다면 includeCompileClasspathtrue로 설정하여 컴파일 클래스 경로의 주석 프로세서를 허용할 수 있습니다. 그러나 이 속성을 true로 설정하는 것은 권장하지 않으며 이렇게 하는 옵션은 향후 Android 플러그인 업데이트에서 삭제될 예정입니다.

전이 종속성 제외

앱의 범위가 커짐에 따라 앱은 직접 종속성과 전이 종속성(앱에 가져온 라이브러리가 종속된 라이브러리)을 비롯한 다수의 종속성을 포함할 수 있습니다. 더 이상 필요하지 않은 전이 종속성을 제외하려면 아래와 같이 exclude 키워드를 사용합니다.

dependencies {
        implementation('some-library') {
            exclude group: 'com.example.imgtools', module: 'native'
        }
    }
    

테스트 구성에서 전이 종속성 제외

테스트에서 특정 전이 종속성을 제외해야 하는 경우 위에 표시한 코드 샘플이 예상한 대로 작동하지 않을 수 있습니다. 그 이유는 테스트 구성(예: androidTestImplementation)이 모듈의 implementation 구성을 확장하기 때문입니다. 즉, Gradle이 구성을 해결할 때 항상 implementation 종속성이 포함됩니다.

따라서 테스트에서 전이 종속성을 제외하려면 아래와 같이 실행 시점에 이를 진행해야 합니다.

android.testVariants.all { variant ->
        variant.getCompileConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
        variant.getRuntimeConfiguration().exclude group: 'com.jakewharton.threetenabp', module: 'threetenabp'
    }
    

참고: 종속성 제외 섹션의 원본 코드 샘플에서 보는 것과 같이 종속성 블록에서 exclude 키워드를 사용하여 테스트 구성에서만 사용하고 다른 구성에는 포함되지 않는 전이 종속성을 생략할 수 있습니다.

변형 인식 종속성 관리 사용

Android 플러그인 3.0.0 이상에는 라이브러리를 사용할 때 자동으로 변형을 매치하는 새로운 종속성 메커니즘이 포함됩니다. 즉, 앱의 debug 변형이 자동으로 라이브러리의 debug 변형 등을 사용합니다. 또한 이 메커니즘은 버전을 사용할 때도 작동하며 앱의 freeDebug 변형은 라이브러리의 freeDebug 변형을 사용합니다.

플러그인이 정확하게 변형을 매치하려면 직접 매치가 불가능한 인스턴스에 매칭 폴백을 제공해야 합니다. 앱은 'staging'이라는 빌드 유형을 구성하지만 라이브러리 종속성 중 하나가 해당 빌드 유형을 구성하지 않는 경우를 고려해 보세요. 플러그인이 앱의 'staging' 버전을 빌드하려고 시도하면 플러그인에서는 사용할 라이브러리 버전을 알 수 없고 다음과 유사한 오류 메시지가 나타납니다.

    Error:Failed to resolve: Could not resolve project :mylibrary.
    Required by:
        project :app
    

변형 매칭과 관련된 빌드 오류 해결

플러그인은 DSL 요소를 포함하고 있어 Gradle이 앱과 종속성 간의 직접적인 변형 매치가 불가능한 상황을 해결하는 방법을 제어할 수 있습니다. 변형 인식 종속성 매칭과 관련된 특정 빌드 오류를 해결하기 위해 사용할 DSL 속성을 결정하려면 아래 표를 참조하세요.

빌드 오류의 원인해결 방법

앱이 라이브러리 종속성에 없는 빌드 유형을 포함합니다.

예를 들어, 앱이 'staging' 빌드 유형을 포함하지만 종속성은 'debug'와 'release' 빌드만 포함합니다.

참고로, 앱에 없는 빌드 유형이 라이브러리 종속성에 포함된 경우는 문제가 되지 않습니다. 그 이유는 플러그인이 앱에 없는 빌드 유형을 종속성에 요청하는 일은 없기 때문입니다.

아래와 같이 matchingFallbacks를 사용하여 주어진 빌드 유형에 맞는 대체 매치를 지정하세요.


    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin should try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
    

앱과 앱의 라이브러리 종속성에 모두 존재하는 버전 차원의 경우 라이브러리에 없는 버전이 앱에 포함됩니다.

예를 들어 앱과 앱의 라이브러리 종속성이 'tier' 버전 차원을 포함합니다. 그러나 앱의 'tier' 차원은 'free'와 'paid' 버전을 포함하지만 종속성은 같은 차원에 대해 'demo'와 'paid' 버전만 포함합니다.

참고로, 앱과 앱의 라이브러리 종속성에 모두 존재하는 버전 차원의 경우 앱에 없는 제품 버전이 라이브러리에 포함되는 것은 문제가 되지 않습니다. 그 이유는 플러그인이 앱에 없는 버전을 종속성에 요청하는 일은 없기 때문입니다.

아래와 같이 matchingFallbacks를 사용하여 앱의 'free' 제품 버전을 위한 대체 매치를 지정하세요.


    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Do not configure matchingFallbacks in the defaultConfig block.
        // Instead, you must specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // should try to use when a dependency's matching dimension does
                // not include a "free" flavor. You may specify as many
                // fallbacks as you like, and the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
    

라이브러리 종속성이 앱에 없는 버전 차원을 포함합니다.

예를 들어, 라이브러리 종속성은 'minApi' 차원의 버전을 포함하지만, 앱은 'tier' 차원의 버전만 포함합니다. 따라서 앱의 'freeDebug' 버전을 빌드할 때 플러그인은 'minApi23Debug' 또는 'minApi18Debug' 중 어느 종속성 버전을 사용할지 알 수 없습니다.

참고로, 라이브러리 종속성에 없는 버전 차원이 앱에 포함된 경우는 문제가 되지 않습니다. 그 이유는 종속성에 있는 차원에만 플러그인이 버전을 매치하기 때문입니다. 예를 들어 종속성이 ABI의 차원을 포함하지 않는다면 앱의 'freeX86Debug' 버전은 단순하게 종속성의 'freeDebug' 버전을 사용합니다.

아래 샘플과 같이 defaultConfig 블록에 있는 missingDimensionStrategy를 사용하여 플러그인이 누락된 각 차원에서 선택해야 하는 기본 버전을 지정합니다. 또한 productFlavors 블록에서 선택한 내용을 재정의할 수 있으며 이 경우 각 버전은 누락된 차원에 대해 다른 매칭 전략을 지정할 수 있습니다.


    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin should try to use from
        // a given dimension. The following tells the plugin that, when encountering
        // a dependency that includes a "minApi" dimension, it should select the
        // "minApi18" flavor. You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // You should specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }
    

Wear OS 앱 종속성 구성

Wear OS 모듈의 종속성 구성은 다른 모듈에서 종속성을 구성하는 것과 비슷합니다. 즉, Wear OS의 종속성은 implementationcompileOnly와 같은 동일한 종속성 구성을 사용합니다.

Wear 모듈은 또한 변형 인식 종속성 관리도 지원합니다. 결과적으로 기본 앱 모듈이 Wear 모듈에 종속된 경우 기본 모듈의 각 변형은 Wear 모듈의 매칭 변형을 사용합니다. 하나의 Wear 모듈에만 종속성을 갖고 그 모듈은 기본 모듈과 동일한 변형을 구성하는 간단한 앱을 빌드한다면 아래와 같이 기본 모듈의 build.gradle 파일에 wearApp 구성을 지정해야 합니다.

dependencies {
        // If the main and Wear app modules have the same variants,
        // variant-aware dependency management automatically matches
        // variants of the main app module with that of the wear module.
        wearApp project(':wearable')
    }
    

여러 개의 Wear 모듈이 있고 앱 버전별로 다른 Wear 모듈을 지정하려면 다음과 같이 flavorWearApp 구성을 사용하세요(단, wearApp 구성을 사용하는 다른 종속성은 포함할 수 없음).

dependencies {
        paidWearApp project(':wear1')
        demoWearApp project(':wear1')
        freeWearApp project(':wear2')
    }
    

원격 저장소

종속성이 로컬 라이브러리나 파일 트리가 아닌 경우 Gradle은 build.gradle 파일의 repositories 블록에서 지정한 온라인 저장소에서 파일을 찾습니다. 각 저장소를 나열하는 순서에 따라 Gradle이 각 프로젝트 종속성의 저장소를 검색하는 순서가 결정됩니다. 예를 들어 어느 종속성이 저장소 A와 B 양쪽에서 모두 이용할 수 있고 사용자가 A를 먼저 나열한 경우 Gradle은 저장소 A에서 종속성을 다운로드합니다.

기본적으로 새 Android 스튜디오 프로젝트는 아래와 같이 프로젝트의 최상위 수준 build.gradle 파일의 저장소 위치로 Google Maven 저장소와 JCenter를 지정합니다.

allprojects {
        repositories {
            google()
            jcenter()
        }
    }
    

Maven 중앙 저장소에서 파일을 가져오려면 mavenCentral()을 추가하고 로컬 저장소에서 가져오려면 mavenLocal()을 사용합니다.

allprojects {
        repositories {
            google()
            jcenter()
            mavenCentral()
            mavenLocal()
        }
    }
    

또는 다음과 같이 특정 Maven이나 Ivy 저장소를 선언할 수 있습니다.

allprojects {
        repositories {
            maven {
                url "https://repo.example.com/maven2"
            }
            maven {
                url "file://local/repo/"
            }
            ivy {
                url "https://repo.example.com/ivy"
            }
        }
    }
    

자세한 내용은 Gradle 저장소 가이드를 참조하세요.

Google Maven 저장소

다음 Android 라이브러리의 가장 최근 버전은 Google Maven 저장소에서 찾을 수 있습니다.

Google Maven 저장소 색인에서 사용할 수 있는 모든 아티팩트를 볼 수 있습니다(프로그래매틱 액세스는 아래를 참조).

이 라이브러리 중 하나를 빌드에 추가하려면 최상위 수준 build.gradle 파일에 Google Maven 저장소를 포함하세요.

allprojects {
        repositories {
            google()

            // If you're using a version of Gradle lower than 4.1, you must instead use:
            // maven {
            //     url 'https://maven.google.com'
            // }
            // An alternative URL is 'https://dl.google.com/dl/android/maven2/'
        }
    }
    

그다음 원하는 라이브러리를 모듈의 dependencies 블록에 추가합니다. 예를 들어 appcompat library는 다음과 같습니다.

dependencies {
        implementation 'com.android.support:appcompat-v7:28.0.0'
    }
    

그러나 위 라이브러리의 이전 버전을 사용하려고 시도할 때 종속성에 오류가 발생하면 그 버전은 Maven 저장소에서 사용할 수 없으며 대신 오프라인 저장소에서 라이브러리를 가져와야 합니다.

프로그래매틱 액세스

Google Maven 아티팩트에 프로그래매틱 액세스하려면 maven.google.com/master-index.xml에서 아티팩트 그룹의 XML 목록을 얻을 수 있습니다. 그러면 다음 경로에서 모든 그룹의 라이브러리 이름과 버전을 볼 수 있습니다.

maven.google.com/group_path/group-index.xml

예를 들어 android.arch.lifecycle 그룹의 라이브러리는 maven.google.com/android/arch/lifecycle/group-index.xml에 나열됩니다.

또한 다음 경로에서 POM과 JAR 파일을 다운로드할 수 있습니다.

maven.google.com/group_path/library/version /library-version.ext

예: maven.google.com/android/arch/lifecycle/compiler/1.0.0/compiler-1.0.0.pom

SDK 관리자의 오프라인 저장소

Google Maven 저장소에서 사용할 수 없는 라이브러리(주로 이전 버전의 라이브러리)를 위해 반드시 SDK 관리자에서 오프라인 Google 저장소 패키지를 다운로드해야 합니다.

그런 다음 평소와 같이 dependencies 블록에 라이브러리를 추가할 수 있습니다.

오프라인 라이브러리는 android_sdk/extras/에 저장됩니다.

종속성 순서

종속성을 나열한 순서는 각각의 우선순위를 나타냅니다. 첫 번째 라이브러리는 두 번째 라이브러리보다 우선순위가 높고 두 번째는 세 번째보다 높습니다. 이 순서는 라이브러리에서 앱으로 리소스가 병합되거나 manifest 요소가 병합되는 이벤트가 있을 때 중요합니다.

예를 들어 프로젝트가 다음과 같이 선언했다고 가정합니다.

  • LIB_ALIB_B에 순서대로 종속성 있음
  • 그다음 LIB_ALIB_CLIB_D에 순서대로 종속됨
  • 그다음 LIB_BLIB_C에 종속됨

그러면 고정 종속성 순서는 다음과 같습니다.

  1. LIB_A
  2. LIB_D
  3. LIB_B
  4. LIB_C

이 순서는 LIB_ALIB_B 모두 LIB_C를 재정의하며 LIB_A(LIB_D에 종속됨)는 LIB_B보다 우선순위가 높기 때문에 LIB_D는 여전히 LIB_B보다 우선순위가 높다는 것을 보장합니다.

다양한 프로젝트 소스/종속성의 manifest를 병합하는 방법에 관한 자세한 내용은 여러 manifest 파일 병합을 참조하세요.

모듈 종속성 보기

일부 직접 종속성은 자체 종속성을 가질 수도 있습니다. 이런 종속성을 전이 종속성이라고 합니다. 각 전이 종속성은 수동으로 선언하지 않아도 Gradle이 자동으로 수집하여 추가합니다. Gradle용 Android 플러그인은 주어진 모듈을 위해 Gradle이 해결하는 종속성 목록을 표시하는 작업을 제공합니다.

각 모듈의 보고서는 또한 빌드 변형, 테스트 소스 집합 및 클래스 경로를 기반으로 종속성을 그룹화합니다. 다음은 디버그 빌드 변형의 앱 모듈 런타임 클래스 경로 및 계측 테스트 소스 집합의 컴파일 클래스 경로를 위한 샘플 보고서입니다.

debugRuntimeClasspath - Dependencies for runtime/packaging
    +--- :mylibrary (variant: debug)
    +--- com.google.android.material:material:1.0.0@aar
    +--- androidx.appcompat:appcompat:1.0.2@aar
    +--- androidx.constraintlayout:constraintlayout:1.1.3@aar
    +--- androidx.fragment:fragment:1.0.0@aar
    +--- androidx.vectordrawable:vectordrawable-animated:1.0.0@aar
    +--- androidx.recyclerview:recyclerview:1.0.0@aar
    +--- androidx.legacy:legacy-support-core-ui:1.0.0@aar
    ...

    debugAndroidTest
    debugAndroidTestCompileClasspath - Dependencies for compilation
    +--- androidx.test.ext:junit:1.1.0@aar
    +--- androidx.test.espresso:espresso-core:3.1.1@aar
    +--- androidx.test:runner:1.1.1@aar
    +--- junit:junit:4.12@jar
    ...
    

이 작업을 실행하려면 다음 절차를 따르세요.

  1. View > Tool Windows > Gradle을 선택하거나 도구 창 메뉴에서 Gradle 을 클릭합니다.
  2. AppName > Tasks > android를 펼치고 androidDependencies를 더블클릭합니다. Gradle에서 작업을 실행하면 Run 창이 열리고 출력 내용이 표시됩니다.

Gradle의 종속성 관리에 관한 자세한 내용은 Gradle 사용자 가이드의 종속성 관리 기본 사항을 참조하세요.

종속성 해결 오류 수정

앱 프로젝트에 여러 종속성을 추가할 때 직접 종속성과 전이 종속성이 서로 충돌할 수 있습니다. Android Gradle 플러그인은 이러한 충돌을 적절히 해결하려 하지만, 일부 충돌은 컴파일 타임 또는 런타임에 오류를 일으킬 수 있습니다.

어느 종속성이 오류의 원인인지 조사하려면 앱 종속성 트리를 검사하고 2회 이상 나타나거나 충돌 버전이 있는 종속성을 찾습니다.

중복 종속성을 쉽게 찾을 수 없다면 다음과 같이 Android 스튜디오의 UI를 사용하여 중복 클래스를 포함하는 종속성을 검색합니다.

  1. 메뉴 바에서 Navigate > Class를 선택합니다.
  2. 팝업 검색 대화상자에서 Include non-project items 옆에 있는 체크박스가 선택되어 있는지 확인합니다.
  3. 빌드 오류에 나타난 클래스의 이름을 입력합니다.
  4. 클래스를 포함하는 종속성의 결과를 검사합니다.

다음 섹션은 발생할 수 있는 종속성 해결 오류의 여러 유형과 해결 방법을 설명합니다.

중복 클래스 오류 수정

한 클래스가 런타임 클래스 경로에 두 번 이상 나타나면 다음과 유사한 오류 메시지가 표시됩니다.

    Program type already present com.example.MyClass
    

이 오류는 일반적으로 다음과 같은 경우에 발생합니다.

  • 바이너리 종속성이 앱에 직접 종속성으로 포함된 라이브러리를 포함합니다. 예를 들어, 앱이 라이브러리 A와 라이브러리 B에 직접 종속성을 선언했지만 바이너리에서 라이브러리 A가 이미 라이브러리 B를 포함한 경우입니다.
    • 이 문제를 해결하려면 라이브러리 B를 직접 종속성에서 삭제합니다.
  • 앱의 동일한 라이브러리에 로컬 바이너리 종속성과 원격 바이너리 종속성이 있습니다.
    • 이 문제를 해결하려면 바이너리 종속성 중 하나를 삭제합니다.

클래스 경로 간 충돌 수정

Gradle이 컴파일 클래스 경로를 해결할 때 먼저 런타임 클래스 경로를 해결하고 그 결과를 사용하여 컴파일 클래스 경로에 추가해야 하는 종속성 버전을 결정합니다. 즉, 런타임 클래스 경로가 다운스트림 클래스 경로의 동일한 종속성에 필요한 버전 번호를 결정합니다.

또한 앱의 런타임 클래스 경로는 Gradle이 앱 테스트 APK의 런타임 클래스 경로에 종속성을 매칭하는 데 필요한 버전 번호를 결정합니다. 그림 1은 클래스 경로의 계층 구조를 설명합니다.

그림 1. 여러 클래스 경로에 나타나는 종속성의 버전 번호는 반드시 이 계층 구조에 따라 매치해야 합니다.

예를 들어, 앱은 implementation 종속성 구성을 사용하여 종속성의 버전을 포함하고 라이브러리 모듈은 runtimeOnly 구성을 사용하여 종속성의 다른 버전을 포함할 때, 여러 클래스 경로에 나타나는 동일한 종속성의 다른 버전에서 충돌이 발생할 수 있습니다.

런타임과 컴파일 타임에 클래스 경로의 종속성을 해결할 때 Android Gradle 플러그인 3.3.0 이상에서는 특정 다운스트림 버전의 충돌을 자동으로 수정하려고 시도합니다. 예를 들어, 런타임 클래스 경로가 라이브러리 A 버전 2.0을 포함하고 컴파일 클래스 경로가 라이브러리 A 버전 1.0을 포함하는 경우 플러그인은 컴파일 클래스 경로의 종속성을 라이브러리 A 버전 2.0으로 자동 업데이트하여 오류를 방지합니다.

그러나 런타임 클래스 경로가 라이브러리 버전 1.0을 포함하고 컴파일 클래스 경로가 라이브러리 A 버전 2.0을 포함하고 있다면 플러그인은 컴파일 클래스 경로의 종속성을 라이브러리 A 버전 1.0으로 다운그레이드하지 않으며 다음과 유사한 오류가 계속 발생합니다.

    Conflict with dependency 'com.example.library:some-lib:2.0' in project 'my-library'.
    Resolved versions for runtime classpath (1.0) and compile classpath (2.0) differ.
    

이 문제를 해결하려면 다음 중 한 가지를 따르세요.

  • 원하는 종속성 버전을 라이브러리 모듈에 api 종속성으로 포함합니다. 즉, 이 종속성을 선언하는 것은 라이브러리 모듈뿐이지만 앱 모듈도 그 종속성의 API에 전이하여 액세스합니다.
  • 또는 두 모듈에 모두 종속성을 선언할 수 있지만 각 모듈이 같은 버전의 종속성을 사용하는지 확인해야 합니다. 프로젝트 전체에 종속성 버전의 일관성을 유지하려면 프로젝트 범위 속성 구성을 고려하세요.

맞춤설정 빌드 논리 적용

이 섹션에서는 Android Gradle 플러그인을 확장하거나 플러그인을 작성할 때 유용한 고급 주제에 관해 설명합니다.

변형 종속성을 맞춤설정 논리로 게시

라이브러리에는 다른 프로젝트 또는 하위 프로젝트에서 사용하려는 기능이 있을 수 있습니다. 라이브러리 게시는 소비자가 라이브러리를 이용할 수 있게 해주는 프로세스입니다. 라이브러리는 컴파일 타임 및 런타임에 소비자가 액세스하는 종속성을 제어할 수 있습니다.

아래에 설명한 대로 소비자가 라이브러리를 이용하기 위해 반드시 사용해야 하는 각 클래스 경로의 전이 종속성을 유지하는 두 개의 별도 구성이 있습니다.

  • variant_nameApiElements: 이 구성은 컴파일 타임에 소비자가 사용할 수 있는 전이 종속성을 유지합니다.
  • variant_nameRuntimeElements: 이 구성은 런타임에 소비자가 사용할 수 있는 전이 종속성을 유지합니다.

다양한 구성 간 관계에 관해 자세히 알아보려면 자바 라이브러리 플러그인 구성을 참조하세요.

맞춤설정 종속성 해결 전략

하나의 프로젝트는 동일 라이브러리의 두 가지 다른 버전에 대한 종속성을 포함할 수 있으며 이 때문에 종속성 충돌이 발생할 수 있습니다. 예를 들어, 프로젝트가 모듈 A의 버전 1과 모듈 B의 버전 2에 종속되고 모듈 A는 모듈 B의 버전 3에 전이 종속된다면 종속성 버전 충돌이 발생합니다.

이 충돌을 해결하기 위해 Android Gradle 플러그인은 다음의 종속성 해결 전략을 사용합니다. 즉, 플러그인이 종속성 그래프에서 동일 모듈의 다른 버전이 있음을 감지하면 플러그인은 기본적으로 버전 번호가 가장 높은 버전을 선택합니다.

그러나 이 전략이 항상 의도한 대로 작동하는 것은 아닙니다. 종속성 해결 전략을 맞춤설정하려면 다음 구성을 사용하여 작업에 필요한 변형의 특정 종속성을 해결해야 합니다.

  • variant_nameCompileClasspath: 이 구성은 주어진 변형의 컴파일 클래스 경로를 위한 해결 전략을 포함합니다.
  • variant_nameRuntimeClasspath: 이 구성은 주어진 변형의 런타임 클래스 경로를 위한 해결 전략을 포함합니다.

Android Gradle 플러그인은 각 변형의 구성 객체에 액세스하는 데 사용할 수 있는 getter를 포함합니다. 따라서 변형 API를 사용하여 아래 예와 같이 종속성 해결을 쿼리할 수 있습니다.

    android {
        applicationVariants.all { variant ->
            // Return compile configuration objects of a variant.
            variant.getCompileConfiguration().resolutionStrategy {
            // Use Gradle's ResolutionStrategy API
            // to customize how this variant resolves dependencies.
                ...
            }
            // Return runtime configuration objects of a variant.
            variant.getRuntimeConfiguration().resolutionStrategy {
                ...
            }
            // Return annotation processor configuration of a variant.
            variant.getAnnotationProcessorConfiguration().resolutionStrategy {
                ...
            }
        }
    }