Thêm phần phụ thuộc của bản dựng

Hệ thống xây dựng Gradle trong Android Studio giúp bạn dễ dàng đưa các tệp nhị phân bên ngoài hoặc các mô-đun thư viện khác vào bản dựng dưới dạng các phần phụ thuộc. Các phần phụ thuộc có thể nằm trên máy hoặc trong một kho lưu trữ từ xa, đồng thời các phần phụ thuộc bắc cầu mà các phần phụ thuộc đó khai báo cũng tự động được đưa vào. Trang này mô tả cách sử dụng các phần phụ thuộc với dự án Android, gồm có thông tin chi tiết về các hành vi và cấu hình dành riêng cho trình bổ trợ Android cho Gradle. Để được hướng dẫn khái niệm chuyên sâu hơn về phần phụ thuộc Gradle, bạn cũng nên xem Hướng dẫn quản lý phần phụ thuộc Gradle nhưng hãy nhớ rằng dự án Android của bạn chỉ được sử dụng các Cấu hình phần phụ thuộc được xác định trên trang này.

Kiểu phần phụ thuộc

Để thêm một phần phụ thuộc vào dự án, hãy chỉ định cấu hình phần phụ thuộc (chẳng hạn như implementation) trong khối dependencies của tệp build.gradle trong mô-đun của bạn.

Ví dụ: tệp build.gradle sau đây của một mô-đun ứng dụng bao gồm ba kiểu phần phụ thuộc khác nhau:

Groovy

plugins {
  id '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'
}

Kotlin

plugins {
    id("com.android.application")
}

android { ... }

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

    // Dependency on local binaries
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))

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

Mỗi kiểu trong số này yêu cầu một loại phần phụ thuộc thư viện khác nhau như sau:

Phần phụ thuộc mô-đun thư viện cục bộ

Groovy

implementation project(':mylibrary')

Kotlin

implementation(project(":mylibrary"))

Đoạn mã này khai báo phần phụ thuộc trên một mô-đun thư viện Android có tên là "mylibrary" (tên này phải khớp với tên thư viện được khai báo với include: trong tệp settings.gradle của bạn). Khi tạo bản dựng ứng dụng, hệ thống xây dựng sẽ biên dịch mô-đun thư viện và đóng gói các nội dung kết quả biên dịch trong ứng dụng.

Phần phụ thuộc tệp nhị phân cục bộ

Groovy

  implementation fileTree(dir: 'libs', include: ['*.jar'])
  

Kotlin

  implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
  

Gradle khai báo các phần phụ thuộc trên các tệp JAR bên trong thư mục module_name/libs/ của dự án (vì Gradle đọc các đường dẫn liên quan đến tệp build.gradle).

Ngoài ra, bạn có thể chỉ định các tệp riêng lẻ như sau:

Groovy

  implementation files('libs/foo.jar', 'libs/bar.jar')
  

Kotlin

  implementation(files("libs/foo.jar", "libs/bar.jar"))
  
Phần phụ thuộc tệp nhị phân từ xa

Groovy

  implementation 'com.example.android:app-magic:12.3'
  

Kotlin

  implementation("com.example.android:app-magic:12.3")
  

Đây thực ra là cách viết ngắn gọn của nội dung sau:

Groovy

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

Kotlin

  implementation(group = "com.example.android", name = "app-magic", version = "12.3")

Đoạn mã này khai báo một phần phụ thuộc trên phiên bản 12.3 của thư viện "app-magic", trong nhóm không gian tên "com.example.android".

Lưu ý: Các phần phụ thuộc từ xa như thế này yêu cầu bạn phải khai báo kho lưu trữ từ xa thích hợp để Gradle sẽ tìm thư viện trong đó. Nếu thư viện chưa tồn tại trên phạm vi cục bộ, Gradle sẽ lấy thư viện đó từ trang web từ xa khi được bản dựng yêu cầu (chẳng hạn như khi nhấp vào Đồng bộ hoá dự án bằng các tệp Gradle hoặc khi chạy một bản dựng).

Nếu bạn cần một phần phụ thuộc AGP vào thời điểm biên dịch, hãy đảm bảo rằng phần phụ thuộc mà bạn thêm là một phần phụ thuộc rõ ràng. Vì AGP sử dụng các cấu hình api/implementation trong nội bộ, cho nên một số cấu phần phần mềm có thể bị xoá khỏi đường dẫn lớp biên dịch, cũng như đường dẫn lớp biên dịch có thể thay đổi.

Phần phụ thuộc gốc

Kể từ phiên bản Trình bổ trợ Android cho Gradle 4.0, bạn có thể nhập các phần phụ thuộc gốc theo cách được mô tả trong tài liệu này.

Tuỳ thuộc vào một AAR hiển thị, các thư viện gốc sẽ được tự động cung cấp cho hệ thống xây dựng được sử dụng bởi externalNativeBuild. Để truy cập các thư viện gốc từ mã của bạn, bạn phải liên kết với các thư viện đó trong tập lệnh bản dựng gốc. Hãy xem phần Sử dụng phần phụ thuộc gốc trong tài liệu này.

Cấu hình phần phụ thuộc

Bên trong khối dependencies, bạn có thể khai báo phần phụ thuộc thư viện bằng cách sử dụng một trong nhiều cấu hình phần phụ thuộc (chẳng hạn như implementation hiển thị ở trên). Mỗi cấu hình phần phụ thuộc cung cấp cho Gradle các hướng dẫn khác nhau về cách sử dụng phần phụ thuộc. Bảng sau đây mô tả từng cấu hình phần phụ thuộc có thể sử dụng trong dự án Android. Bảng mô tả cũng so sánh các cấu hình này với các cấu hình không dùng nữa kể từ phiên bản Trình bổ trợ Android cho Gradle 3.0.0.

Cấu hình Hành vi
implementation Gradle thêm phần phụ thuộc vào đường dẫn lớp biên dịch và đóng gói phần phụ thuộc đó vào đầu ra của bản dựng. Tuy nhiên, khi mô-đun của bạn định cấu hình một phần phụ thuộc implementation thì Gradle sẽ được cho biết rằng bạn không muốn mô-đun này làm rò rỉ phần phụ thuộc đó ra các mô-đun khác tại thời điểm biên dịch. Điều này nghĩa là phần phụ thuộc chỉ có trong các mô-đun khác vào thời gian chạy.

Việc sử dụng cấu hình phần phụ thuộc này thay vì api hoặc compile (đã ngừng hoạt động) có thể sẽ cải thiện đáng kể thời gian tạo bản dựng vì cấu hình này làm giảm số lượng mô-đun mà hệ thống xây dựng cần biên dịch lại. Chẳng hạn, nếu một phần phụ thuộc implementation thay đổi API của mình thì Gradle sẽ chỉ biên dịch lại phần phụ thuộc đó cùng những mô-đun phụ thuộc trực tiếp. Hầu hết các mô-đun ứng dụng và mô-đun kiểm thử nên sử dụng cấu hình này.

api Gradle thêm phần phụ thuộc vào đường dẫn lớp biên dịch và đầu ra bản dựng. Khi một mô-đun đưa phần một phụ thuộc api vào, Gradle sẽ được cho biết rằng mô-đun muốn xuất phần phụ thuộc đó bắc cầu sang các mô-đun khác để người dùng có thể truy cập trong cả thời gian chạy và biên dịch.

Cấu hình này hoạt động giống như compile (hiện không còn được dùng nữa), nhưng bạn nên sử dụng một cách thận trọng và chỉ dùng với các phần phụ thuộc mà bạn cần xuất bắc cầu sang những đối tượng sử dụng khác ở cấp độ cao hơn. Đó là vì, nếu một phần phụ thuộc api thay đổi API bên ngoài thì Gradle sẽ biên dịch lại tất cả các mô-đun có quyền truy cập vào phần phụ thuộc đó tại thời điểm biên dịch. Vì vậy, việc có một số lượng lớn các phần phụ thuộc api có thể gia tăng đáng kể thời gian tạo bản dựng. Trừ khi bạn muốn hiển thị API của một phần phụ thuộc cho một mô-đun riêng, các mô-đun thư viện nên sử dụng các phần phụ thuộc implementation.

compileOnly Gradle chỉ thêm phần phụ thuộc vào đường dẫn lớp biên dịch (nghĩa là phần phụ thuộc này không được thêm vào đầu ra của bản dựng). Điều này rất hữu ích khi tạo một mô-đun Android và cần có phần phụ thuộc trong quá trình biên dịch, nhưng không bắt buộc phải thêm phần phụ thuộc này tại thời gian chạy.

Nếu sử dụng cấu hình này, bạn phải đưa điều kiện thời gian chạy vào mô-đun thư viện để kiểm tra xem phần phụ thuộc có sẵn hay không, sau đó thay đổi linh hoạt hành vi của mô-đun để vẫn có thể hoạt động nếu như phần phụ thuộc không được cung cấp. Điều này giúp giảm kích thước của ứng dụng cuối cùng bằng cách không thêm các phần phụ thuộc bắc cầu không quan trọng. Hành vi của cấu hình này giống như provided (hiện đã ngừng hoạt động).

Lưu ý: Bạn không thể dùng cấu hình compileOnly với các phần phụ thuộc AAR.

runtimeOnly Gradle chỉ thêm phần phụ thuộc vào đầu ra của bản dựng, để sử dụng trong thời gian chạy. Điều đó có nghĩa là phần phụ thuộc này sẽ không được thêm vào đường dẫn lớp biên dịch. Hành vi của cấu hình này giống như apk (hiện đã ngừng hoạt động).
annotationProcessor

Để thêm một phần phụ thuộc trên một thư viện là trình xử lý chú thích, bạn phải thêm tệp đó vào đường dẫn lớp xử lý chú thích bằng cách sử dụng cấu hình annotationProcessor. Đó là vì việc sử dụng cấu hình này giúp cải thiện hiệu năng của bản dựng bằng cách tách đường dẫn lớp biên dịch ra khỏi đường dẫn lớp xử lý chú thích. Nếu tìm thấy trình xử lý chú thích trên đường dẫn lớp biên dịch, Gradle sẽ vô hiệu hoá tính năng miễn trừ biên dịch (compile avoidance) vì tính năng này sẽ tác động tiêu cực đến thời gian tạo bản dựng (Gradle phiên bản 5.0 trở lên sẽ bỏ qua các trình xử lý chú thích trên đường dẫn lớp biên dịch).

Trình bổ trợ Android cho Gradle giả định một phần phụ thuộc là trình xử lý chú thích nếu tệp JAR của phần phụ thuộc đó có chứa tệp sau:

META-INF/services/javax.annotation.processing.Processor

Nếu trình bổ trợ phát hiện một trình xử lý chú thích trên đường dẫn lớp biên dịch, một lỗi bản dựng sẽ xảy ra.

Lưu ý: Bạn nên sử dụng kapt để khai báo các phần phụ thuộc của trình xử lý chú thích trong các dự án Kotlin.

lintChecks

Sử dụng cấu hình này để đưa các phần kiểm tra lỗi mã nguồn (lint check) vào cho Gradle thực thi khi tạo bản dựng dự án.

Lưu ý: Khi sử dụng trình bổ trợ Android cho Gradle phiên bản 3.4.0 trở lên, cấu hình phần phụ thuộc này không còn đóng gói các phần kiểm tra lỗi mã nguồn trong các dự án Thư viện Android của bạn nữa. Để đưa các phần phụ thuộc kiểm tra lỗi mã nguồn vào các thư viện AAR, hãy dùng cấu hình lintPublish được mô tả bên dưới.

lintPublish Sử dụng cấu hình này trong các dự án thư viện Android để đưa các phần kiểm tra lỗi mã nguồn (lint check) mà bạn muốn Gradle biên dịch vào một tệp lint.jar và gói trong AAR của bạn. Điều này khiến các dự án sử dụng AAR của bạn cũng áp dụng phần kiểm tra lỗi mã nguồn đó. Nếu trước đó bạn đã sử dụng cấu hình phần phụ thuộc lintChecks để đưa kết quả kiểm tra lỗi mã nguồn vào trong AAR đã xuất bản, thì bạn cần di chuyển các phần phụ thuộc đó để sử dụng cấu hình lintPublish.

Groovy


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')
}

Kotlin


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"))
}

Các cấu hình Gradle không dùng nữa (có sẵn trong AGP 1.0–4.2)

Cấu hình Hành vi
apk Gradle chỉ thêm phần phụ thuộc vào đầu ra của bản dựng để sử dụng trong thời gian chạy. Điều đó có nghĩa là phần phụ thuộc này sẽ không được thêm vào đường dẫn lớp biên dịch.
compile Gradle sẽ thêm phần phụ thuộc vào đường dẫn lớp biên dịch và đầu ra của bản dựng. Xuất phần phụ thuộc sang các mô-đun khác.
provided Gradle chỉ thêm phần phụ thuộc vào đường dẫn lớp biên dịch (nghĩa là không thêm phần phụ thuộc này vào đầu ra của bản dựng).

Tất cả các cấu hình trên đều áp dụng các phần phụ thuộc với tất cả biến thể bản dựng. Thay vào đó, nếu bạn chỉ muốn khai báo một phần phụ thuộc dành riêng cho một nhóm tài nguyên biến thể bản dựng cụ thể hoặc dành cho một nhóm tài nguyên kiểm thử, bạn phải viết hoa tên cấu hình và thêm tiền tố là tên của biến thể bản dựng hoặc tên của nhóm tài nguyên kiểm thử.

Chẳng hạn, để chỉ thêm một phần phụ thuộc implementation vào phiên bản sản phẩm "miễn phí" của bạn (sử dụng phần phụ thuộc nhị phân từ xa), bạn sẽ dùng đoạn mã có dạng như sau:

Groovy

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

Kotlin

dependencies {
    freeImplementation("com.google.firebase:firebase-ads:9.8.0")
}

Tuy nhiên, nếu muốn thêm phần phụ thuộc cho một biến thể kết hợp một phiên bản sản phẩm một kiểu bản dựng, bạn phải khởi tạo tên cấu hình trong khối configurations. Mẫu sau đây thêm phần phụ thuộc runtimeOnly vào biến thể bản dựng "freeDebug" (bằng cách sử dụng một phần phụ thuộc tệp nhị phân cục bộ).

Groovy

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

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

Kotlin

// Initializes a placeholder for the freeDebugRuntimeOnly dependency configuration.
val freeDebugRuntimeOnly by configurations.creating

dependencies {
    freeDebugRuntimeOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
}

Để thêm các phần phụ thuộc implementation cho quy trình kiểm thử cục bộ và quy trình kiểm thử đo lường, bạn có thể xem đoạn mã sau:

Groovy

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 'androidx.test.espresso:espresso-core:3.0.2'
}

Kotlin

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("androidx.test.espresso:espresso-core:3.0.2")
}

Tuy nhiên, một số cấu hình nhất định không có ý nghĩa trong trường hợp này. Chẳng hạn, vì các mô-đun khác không thể phụ thuộc vào androidTest, nên bạn sẽ nhận được cảnh báo sau nếu sử dụng cấu hình androidTestApi:

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

Thêm trình xử lý chú thích

Nếu thêm trình xử lý chú thích vào đường dẫn lớp biên dịch, một thông báo lỗi như sau sẽ xuất hiện:

Error: Annotation processors must be explicitly declared now.

Để khắc phục lỗi này, hãy thêm trình xử lý chú thích vào dự án bằng cách định cấu hình phần phụ thuộc bằng cách sử dụng annotationProcessor như đoạn mã bên dưới:

Groovy

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'
}

Kotlin

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")
}

Lưu ý: Trình bổ trợ Android cho Gradle phiên bản 3.0.0 trở lên không còn hỗ trợ trình bổ trợ android-apt.

Chuyển đối số đến trình xử lý chú thích

Nếu cần chuyển các đối số đến trình xử lý chú thích, bạn có thể sử dụng khối AnnotationProcessorOptions trong cấu hình bản dựng của mô-đun. Chẳng hạn, nếu muốn chuyển các kiểu dữ liệu chính làm cặp khoá-giá trị, bạn có thể sử dụng thuộc tính argument, như minh hoạ bên dưới:

Groovy

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

Kotlin

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += mapOf("key1" to "value1",
                                   "key2" to "value2")
            }
        }
    }
}

Tuy nhiên, khi sử dụng Trình bổ trợ Android cho Gradle phiên bản 3.2.0 trở lên, bạn cần phải chuyển các đối số trình xử lý đại diện cho các tệp hoặc thư mục bằng cách sử dụng giao diện CommandLineArgumentProvider của Gradle.

Việc sử dụng CommandLineArgumentProvider cho phép bạn hoặc tác giả của trình xử lý chú thích có thể cải thiện độ chính xác và hiệu năng của các bản dựng tăng dần (incremental build) an toàn với bộ nhớ đệm bằng cách áp dụng các chú thích kiểu thuộc tính bản dựng tăng dần đối với mỗi đối số.

Chẳng hạn, lớp bên dưới triển khai CommandLineArgumentProvider và chú thích từng đối số cho trình xử lý. Mẫu cũng sử dụng cú pháp ngôn ngữ Groovy và được đưa trực tiếp vào tệp build.gradle của mô-đun.

Groovy

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 {...}

Kotlin

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

    @get:OutputDirectory
    val outputDir: File
) : CommandLineArgumentProvider {
    // 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 fun asArguments(): Iterable<String> {
        // Use the form '-Akey[=value]' to pass your options to the Java compiler.
        return listOf("-AinputDir=${inputDir.singleFile.absolutePath}",
                      "-AoutputDir=${outputDir.absolutePath}")
    }
}

android {...}

Sau khi khai báo một lớp triển khai CommandLineArgumentProvider, bạn cần tạo một thực thể và chuyển thực thể đó tới trình bổ trợ Android bằng cách sử dụng phương thức annotationProcessorOptions.compilerArgumentProvider, như ở đoạn mã bên dưới.

Groovy

// 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"))
            }
        }
    }
}

Kotlin

// 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(MyArgsProvider(files("input/path"),
                                                          file("output/path")))
            }
        }
    }
}

Để tìm hiểu thêm về lợi ích của việc triển khai CommandLineArgumentProvider đối với hiệu năng của bản dựng, hãy đọc bài viết Lưu các dự án Java vào bộ đệm.

Tắt tính năng kiểm tra lỗi của trình xử lý chú thích

Nếu bạn có các phần phụ thuộc trên đường dẫn lớp biên dịch chứa các trình xử lý chú thích không cần thiết, bạn có thể tắt tính năng kiểm tra lỗi bằng cách thêm nội dung sau vào tệp build.gradle. Luôn nhớ rằng các trình xử lý chú thích mà bạn thêm vào đường dẫn lớp biên dịch vẫn chưa được thêm vào đường dẫn lớp của bộ xử lý.

Groovy

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

Kotlin

android {
    ...
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                argument("includeCompileClasspath", "false")
            }
        }
    }
}

Nếu sử dụng Kotlin và kapt:

Groovy

android {
    ...
    defaultConfig {
        ...
        kapt {
            includeCompileClasspath false
        }
    }
}

Kotlin

android {
    ...
    defaultConfig {
        ...
        kapt {
            includeCompileClasspath = false
        }
    }
}

Nếu gặp sự cố sau khi di chuyển trình xử lý chú thích của dự án sang đường dẫn lớp của bộ xử lý, bạn có thể thiết lập includeCompileClasspath thành true để cho phép xử lý chú thích trên đường dẫn lớp biên dịch. Tuy nhiên, bạn không nên thiết lập thuộc tính này thành true, và tuỳ chọn này sẽ bị xoá trong bản cập nhật trình bổ trợ Android sắp tới.

Loại trừ các phần phụ thuộc bắc cầu

Khi phát triển trong phạm vi nhất định, một ứng dụng có thể chứa một số phần phụ thuộc, bao gồm cả các phần phụ thuộc trực tiếp và phần phụ thuộc bắc cầu (các thư viện mà thư viện đã nhập của ứng dụng phụ thuộc vào). Để loại trừ các phần phụ thuộc bắc cầu không còn cần thiết nữa, bạn có thể sử dụng từ khoá exclude như minh hoạ bên dưới:

Groovy

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

Kotlin

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

Loại trừ các phần phụ thuộc bắc cầu khỏi cấu hình kiểm thử

Nếu bạn cần loại trừ một số phần phụ thuộc bắc cầu nhất định khỏi các quy trình kiểm thử thì mã mẫu nêu trên có thể không hoạt động như mong đợi. Đó là do cấu hình kiểm thử (ví dụ: androidTestImplementation) mở rộng cấu hình implementation của mô-đun. Nghĩa là khi Gradle giải quyết, thì cấu hình kiểm thử này luôn chứa các phần phụ thuộc implementation.

Vì vậy, bạn phải loại trừ các phần phụ thuộc bắc cầu khỏi các quy trình kiểm thử tại thời điểm thực thi như đoạn mã bên dưới:

Groovy

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

Kotlin

android.testVariants.all {
    compileConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
    runtimeConfiguration.exclude(group = "com.jakewharton.threetenabp", module = "threetenabp")
}

Lưu ý: Bạn vẫn có thể sử dụng từ khoá exclude trong khối phần phụ thuộc như trong mã mẫu nguyên gốc ở phần Loại trừ các phần phụ thuộc bắc cầu để bỏ qua các phần phụ thuộc bắc cầu dành riêng cho cấu hình kiểm thử và không được đưa vào các cấu hình khác.

Định cấu hình các phần phụ thuộc của ứng dụng Wear OS

Việc định cấu hình các phần phụ thuộc cho một mô-đun Wear OS cũng tương tự như các phần phụ thuộc của mọi mô-đun khác; tức là các mô-đun Wear OS sử dụng cùng các cấu hình phần phụ thuộc, chẳng hạn như implementationcompileOnly.

Các mô-đun Wear cũng hỗ trợ việc quản lý phần phụ thuộc nhận biết biến thể. Kết quả là nếu mô-đun cơ sở của ứng dụng có một phần phụ thuộc trên mô-đun Wear, thì mỗi biến thể của mô-đun cơ sở sẽ sử dụng biến thể phù hợp từ mô-đun Wear. Khi xây dựng một ứng dụng đơn giản với một phần phụ thuộc trên một mô-đun Wear duy nhất thì mô-đun Wear sẽ định cấu hình cùng các biến thể như mô-đun cơ sở. Bạn cần chỉ định cấu hình wearApp trong tệp build.gradle của mô-đun cơ sở như đoạn mã dưới đây:

Groovy


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')
}

Kotlin


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"))
}

Nếu có nhiều mô-đun Wear và muốn chỉ định một mô-đun Wear khác nhau cho mỗi phiên bản ứng dụng, bạn có thể sử dụng cấu hình flavorWearApp như sau (tuy nhiên, bạn không thể đưa vào các phần phụ thuộc khác sử dụng cấu hình wearApp):

Groovy


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

Kotlin


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

Kho lưu trữ từ xa

Khi phần phụ thuộc của bạn không phải là thư viện cục bộ hoặc cây tệp (file tree), Gradle sẽ tìm các tệp trong bất kỳ kho lưu trữ trực tuyến nào được chỉ định trong khối dependencyResolutionManagement { repositories {...} } của tệp settings.gradle. Gradle sẽ tìm kiếm kho lưu trữ cho mỗi phần phụ thuộc trong dự án theo thứ tự liệt kê của mỗi kho lưu trữ. Chẳng han, nếu một phần phụ thuộc có sẵn trong cả kho lưu trữ A và B, đồng thời bạn liệt kê A trước, thì Gradle sẽ tải phần phụ thuộc xuống từ kho lưu trữ A.

Theo mặc định, các dự án Android Studio mới sẽ chỉ định kho lưu trữ Maven của Googlekho lưu trữ trung tâm Maven làm vị trí lưu trữ trong tệp settings.gradle của dự án, như minh hoạ bên dưới:

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

Nếu bạn cần một nội dung từ kho lưu trữ cục bộ, hãy sử dụng mavenLocal():

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        mavenLocal()
    }
}

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        mavenLocal()
    }
}

Bạn cũng có thể khai báo các kho lưu trữ Maven hoặc Ivy cụ thể như sau:

Groovy


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven {
            url 'https://repo.example.com/maven2'
        }
        maven {
            url 'file://local/repo/'
        }
        ivy {
            url 'https://repo.example.com/ivy'
        }
    }
}

Kotlin


dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        maven(url = "https://repo.example.com/maven2")
        maven(url = "file://local/repo/")
        ivy(url = "https://repo.example.com/ivy")
    }
}

Để biết thêm thông tin, hãy xem Hướng dẫn Kho lưu trữ Gradle.

Kho lưu trữ Maven của Google

Phiên bản mới nhất của các thư viện Android sau đây có sẵn từ kho lưu trữ Maven của Google:

Bạn có thể xem tất cả cấu phần phần mềm có sẵn tại Mục lực kho lưu trữ Maven của Google (xem phần bên dưới để biết về Quyền truy cập có lập trình).

Để thêm một trong những thư viện này vào bản dựng, hãy đưa kho lưu trữ Maven của Google vào trong tệp build.gradle cấp cao nhất:

Groovy


dependencyResolutionManagement {

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    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/'.
    }
}

Kotlin


dependencyResolutionManagement {

    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    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/".
    }
}

Sau đó, hãy thêm thư viện mong muốn vào khối dependencies của mô-đun. Chẳng hạn như, thư viện appcompat có dạng như sau:

Groovy


dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
}

Kotlin


dependencies {
    implementation("com.android.support:appcompat-v7:28.0.0")
}

Tuy nhiên, nếu cố gắng sử dụng một phiên bản cũ hơn của các thư viện trên và không có phần phụ thuộc, thì thư viện đó không có sẵn trong kho lưu trữ Maven và bạn phải tải từ kho lưu trữ ngoại tuyến.

Quyền truy cập có lập trình (Programmatic access)

Để có quyền truy cập có lập trình vào các cấu phần phần mềm Maven của Google, bạn có thể lấy danh sách XML về các nhóm cấu phần phần mềm từ maven.google.com/master-index.xml. Sau đó, bạn có thể xem tên thư viện và phiên bản thư viện của bất kỳ nhóm nào tại:

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

Chẳng hạn như, các thư viện trong nhóm android.arch.lifecycle được liệt kê trên trang maven.google.com/android/arch/lifecycle/group-index.xml.

Bạn cũng có thể tải tệp POM và JAR xuống tại:

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

Ví dụ: maven.google.com/android/arch/lifecycle/compiler/1.0.0/compiler-1. 0.0.pom.

Kho lưu trữ ngoại tuyến từ Trình quản lý SDK

Đối với các thư viện không có trong kho lưu trữ Google Maven (thường là các phiên bản thư viện cũ), bạn phải tải gói Google Repository (Kho lưu trữ Google) ngoại tuyến xuống từ SDK Manager (Trình quản lý SDK).

Sau đó, bạn có thể thêm các thư viện này vào khối dependencies như bình thường.

Các thư viện ngoại tuyến được lưu trong android_sdk/extras/.

Các phần phụ thuộc gốc với trình bổ trợ Android cho Gradle

Các thư viện AAR có thể chứa các phần phụ thuộc gốc mà Trình bổ trợ Android cho Gradle có thể sử dụng. AGP cũng có thể tạo ra các AAR để hiển thị các thư viện gốc cho đối tượng sẽ sử dụng.

Sử dụng phần phụ thuộc gốc

Kể từ phiên bản 4.0 của Trình bổ trợ Android cho Gradle, bạn có thể nhập phần phụ thuộc C/C++ từ các AAR đã liên kết trong tệp build.gradle. Gradle sẽ tự động cung cấp những phần phụ thuộc này cho hệ thống xây dựng gốc, nhưng bạn cần phải định cấu hình hệ thống xây dựng để sử dụng các thư viện và tiêu đề đã nhập. Vì các phần phụ thuộc C/C++ được phân phối dưới dạng các AAR, nên những đường liên kết sau về các AAR tổng quát có thể sẽ hữu ích:

  • Tạo Thư viện Android gồm tài liệu AAR tổng quát và cách tích hợp AAR vào dự án, đặc biệt là khi bạn muốn sử dụng AAR dưới dạng một phần phụ thuộc C/C++ cục bộ.
  • Thêm các phần phụ thuộc của bản dựng để biết thông tin về cách thêm các phần phụ thuộc vào tệp build.gradle, đặc biệt là các phần phụ thuộc từ xa.

Tài liệu này tập trung vào cách định cấu hình hệ thống xây dựng gốc và giả định rằng bạn đã thêm AAR của phần phụ thuộc C/C++ vào môi trường bản dựng Gradle của dự án.

Phần phụ thuộc gốc trong AAR

Các phần phụ thuộc AAR của các mô-đun Gradle có thể làm hiển thị các thư viện gốc để ứng dụng sử dụng. Bên trong AAR, thư mục prefab chứa gói Prefab, bao gồm tiêu đề và thư viện của phần phụ thuộc gốc.

Mỗi phần phụ thuộc có thể hiển thị tối đa một gói Profab, bao gồm một hoặc nhiều mô-đun. Mô-đun Prefab là một thư viện đơn lẻ (có thể là thư viện chia sẻ, thư viện tĩnh hoặc thư viện chỉ chứa tiêu đề).

Để sử dụng các thư viện đó, bạn cần biết tên gói và tên mô-đun. Theo quy ước, tên gói sẽ khớp với tên cấu phần phần mềm Maven và tên mô-đun sẽ khớp với tên thư viện C/C++; nhưng điều này là không bắt buộc. Hãy tham khảo tài liệu về phần phụ thuộc để xác định tên mà phần phụ thuộc đó sử dụng.

Cấu hình hệ thống xây dựng

Bạn phải bật tính năng prefab cho mô-đun Android của Gradle.

Để thực hiện việc này, hãy thêm nội dung sau vào khối android của tệp build.gradle trong mô-đun:

Groovy

buildFeatures {
  prefab true
}

Kotlin

buildFeatures {
  prefab = true
}

Bạn có thể tuỳ chọn định cấu hình một phiên bản trong tệp gradle.properties của dự án:

android.prefabVersion=2.0.0

Thông thường, phiên bản AGP mặc định được chọn sẽ phù hợp với nhu cầu của bạn. Bạn chỉ nên chọn một phiên bản khác nếu cần giải quyết lỗi, hoặc cần thêm một tính năng mới.

Các phần phụ thuộc đã nhập từ một AAR sẽ hiển thị với CMake thông qua CMAKE_FIND_ROOT_PATH. Giá trị này sẽ được Gradle thiết lập tự động khi CMake được gọi. Cho nên nếu bản dựng sửa đổi biến này, hãy đảm bảo rằng đó là nối thêm thay vì gán cho biến này.

Mỗi phần phụ thuộc hiển thị một gói tệp cấu hình đến bản dựng của bạn. Các gói này được nhập bằng lệnh find_package. Lệnh này tìm kiếm các gói tệp cấu hình khớp với tên gói và phiên bản gói đã cung cấp, cũng như hiển thị các mục tiêu sẽ được khai báo để sử dụng trong bản dựng. Ví dụ: nếu ứng dụng của bạn khai báo libapp.so và libapp.so sử dụng cURL, thì CMakeLists.txt của bạn sẽ gồm như sau:

add_library(app SHARED app.cpp)

# Add these two lines.
find_package(curl REQUIRED CONFIG)
target_link_libraries(app curl::curl)

app.cpp hiện có thể #include "curl/curl.h", libapp.so sẽ tự động được liên kết với libcurl.so khi tạo bản dựng và libcurl.so sẽ được đưa vào ứng dụng.

Phát hành thư viện gốc trong AAR

Chức năng tạo các AAR gốc lần đầu tiên được thêm vào AGP 4.1.

Để xuất các thư viện gốc, hãy thêm đoạn mã sau vào khối android của tệp build.gradle trong dự án thư viện:

Groovy


buildFeatures {
    prefabPublishing true
}

prefab {
    mylibrary {
      headers "src/main/cpp/mylibrary/include"
    }

    myotherlibrary {
        headers "src/main/cpp/myotherlibrary/include"
    }
}

Kotlin


buildFeatures {
    prefabPublishing = true
}

prefab {
    create("mylibrary") {
      headers = "src/main/cpp/mylibrary/include"
    }

    create("myotherlibrary") {
        headers = "src/main/cpp/myotherlibrary/include"
    }
}

Trong ví dụ này, thư viện mylibrarymyotherlibrary từ bản dựng gốc ndk-build hoặc CMake bên ngoài sẽ được đóng gói trong AAR do bản dựng của bạn tạo ra, mỗi thư viện sẽ xuất các tiêu đề từ thư mục được chỉ định đến các phần phụ thuộc.

Thứ tự phần phụ thuộc

Thứ tự liệt kê các phần phụ thuộc của bạn phản ánh rõ mức độ ưu tiên: thư viện đầu tiên có mức độ ưu tiên cao hơn thư viện thứ hai, thư viện thứ hai có mức độ ưu tiên cao hơn thư viện thứ ba, v.v. Thứ tự này rất quan trọng trong trường hợp tài nguyên được hợp nhất hoặc các phần tử tệp kê khai được hợp nhất vào trong ứng dụng từ thư viện.

Ví dụ: nếu dự án của bạn khai báo như sau:

  • Phần phụ thuộc trên LIB_ALIB_B (theo thứ tự đó)
  • LIB_A phụ thuộc vào LIB_CLIB_D (theo thứ tự đó)
  • LIB_B cũng phụ thuộc vào LIB_C

Khi đó, thứ tự phần phụ thuộc cố định sẽ như sau:

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

Điều này đảm bảo rằng cả LIB_ALIB_B đều có thể ghi đè LIB_C; và LIB_D vẫn sẽ có mức độ ưu tiên cao hơn LIB_BLIB_A (phụ thuộc vào LIB_D) có mức độ ưu tiên cao hơn LIB_B.

Để biết thêm thông tin về cách hợp nhất các tệp kê khai từ nhiều nguồn/phần phụ thuộc của các dự án khác nhau, hãy xem Hợp nhất nhiều tệp kê khai.

Hiển thị các phần phụ thuộc của mô-đun

Một số phần phụ thuộc trực tiếp có thể có các phần phụ thuộc riêng. Những phần phụ thuộc riêng đó được gọi là phần phụ thuộc bắc cầu. Thay vì yêu cầu bạn khai báo thủ công từng phần phụ thuộc bắc cầu, Gradle sẽ tự động thu thập và bổ sung các khai báo này cho bạn. Trình bổ trợ Android cho Gradle sẽ cung cấp một tác vụ hiển thị danh sách các phần phụ thuộc mà Gradle sẽ phân giải cho một mô-đun nhất định.

Đối với mỗi mô-đun, báo cáo này cũng sẽ nhóm các phần phụ thuộc dựa trên biến thể bản dựng, nhóm tài nguyên kiểm thử và đường dẫn lớp. Sau đây là báo cáo mẫu về đường dẫn lớp thời gian chạy của một mô-đun ứng dụng được nhóm dựa trên biến thể bản dựng gỡ lỗi và đường dẫn lớp biên dịch của nhóm tài nguyên kiểm thử đo lường.

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
...

Để chạy tác vụ này, hãy tiến hành như sau:

  1. Chọn View (Hiển thị) > Tool Windows (Cửa sổ công cụ) > Gradle (hoặc nhấp vào Gradle trong thanh cửa sổ công cụ).
  2. Mở rộng phần AppName > Tasks (Nhiệm vụ) > android rồi nhấp đúp vào androidDependencies. Sau khi Gradle thực thi nhiệm vụ, cửa sổ Run (Chạy) sẽ mở ra để hiển thị dữ liệu đầu ra.

Để biết thêm thông tin về cách quản lý các phần phụ thuộc trong Gradle, hãy xem bài viết Kiến thức cơ bản về quản lý phần phụ thuộc trong phần Hướng dẫn sử dụng Gradle.

Sửa lỗi phân giải phần phụ thuộc

Khi bạn thêm nhiều phần phụ thuộc vào dự án ứng dụng, những phần phụ thuộc trực tiếp và bắc cầu đó có thể xung đột với nhau. Trình bổ trợ Android cho Gradle sẽ cố gắng giải quyết những xung đột này một cách linh hoạt, nhưng một số xung đột có thể dẫn đến lỗi biên dịch hoặc lỗi thời gian chạy.

Để kiểm tra xem những phần phụ thuộc đang gây ra lỗi, hãy kiểm tra cây phần phụ thuộc của ứng dụng và tìm các phần phụ thuộc xuất hiện nhiều lần hoặc có các phiên bản xung đột.

Nếu không thể dễ dàng xác định được các phần phụ thuộc trùng lặp, hãy thử sử dụng giao diện người dùng của Android Studio để tìm các phần phụ thuộc có chứa lớp trùng lặp đó như sau:

  1. Chọn Navigate > Class (Di chuyển > Lớp) từ thanh trình đơn.
  2. Trong hộp thoại tìm kiếm vừa bật lên, hãy nhớ đánh dấu vào hộp Include non-project items (Bao gồm các mục không thuộc dự án).
  3. Nhập tên của lớp xuất hiện trong lỗi bản dựng.
  4. Kiểm tra kết quả của các phần phụ thuộc có chứa lớp đó.

Các phần sau đây mô tả các loại lỗi phân giải phần phụ thuộc mà bạn có thể gặp phải và cách khắc phục.

Sửa lỗi trùng lặp lớp

Nếu một lớp xuất hiện nhiều lần trên đường dẫn lớp thời gian chạy, một lỗi tương tự như sau sẽ xảy ra:

Program type already present com.example.MyClass

Lỗi này thường xảy ra do một trong các trường hợp sau:

  • Một phần phụ thuộc nhị phân có chứa một thư viện mà ứng dụng của bạn cũng đưa vào dưới dạng một phần phụ thuộc trực tiếp. Chẳng hạn, ứng dụng của bạn khai báo một phần phụ thuộc trực tiếp trong Thư viện A và Thư viện B, nhưng Thư viện A đã đưa Thư viện B vào tệp nhị phân của mình.
    • Để giải quyết vấn đề này, hãy xoá Thư viện B ở dạng phần phụ thuộc trực tiếp.
  • Ứng dụng của bạn có phần phụ thuộc tệp nhị phân cục bộ và phần phụ thuộc tệp nhị phân từ xa trên cùng một thư viện.
    • Để giải quyết vấn đề này, hãy xoá một trong các phần phụ thuộc nhị phân.

Khắc phục xung đột giữa các đường dẫn lớp

Khi Gradle phân giải đường dẫn lớp biên dịch, trước tiên sẽ phân giải đường dẫn lớp thời gian chạy và sử dụng kết quả đó để xác định phiên bản của các phần phụ thuộc sẽ được thêm vào đường dẫn lớp biên dịch. Nói cách khác, đường dẫn lớp thời gian chạy xác định số phiên bản bắt buộc đối với các phần phụ thuộc giống nhau trên đường dẫn hạ nguồn.

Đường dẫn lớp thời gian chạy của ứng dụng cũng xác định số phiên bản mà Gradle yêu cầu để so khớp với các phần phụ thuộc trong đường dẫn lớp thời gian chạy dành cho APK kiểm thử của ứng dụng. Hình 1 mô tả sơ đồ hệ phân cấp các đường dẫn lớp.

Hình 1. Số phiên bản của các phần phụ thuộc xuất hiện trên nhiều đường dẫn lớp phải khớp với hệ phân cấp này.

Xung đột khi các phiên bản khác nhau của cùng một phần phụ thuộc xuất hiện trên nhiều đường dẫn lớp có thể xảy ra khi ứng dụng của bạn có một phiên bản của một phần phụ thuộc sử dụng cấu hình phần phụ thuộc implementation và một mô-đun thư viện sử dụng một phiên bản khác của phần phụ thuộc đó bằng cấu hình runtimeOnly.

Khi phân giải các phần phụ thuộc trên đường dẫn lớp thời gian chạy và đường dẫn lớp biên dịch, Trình bổ trợ Android cho Gradle phiên bản 3.3.0 trở lên sẽ cố gắng tự động khắc phục một số xung đột phiên bản nhất định. Chẳng hạn, nếu đường dẫn lớp thời gian chạy bao gồm Thư viện A phiên bản 2.0 và đường dẫn lớp biên dịch bao gồm Thư viện A phiên bản 1.0, thì trình bổ trợ sẽ tự động cập nhật phần phụ thuộc trên đường dẫn lớp biên dịch thành Thư viện A phiên bản 2.0 để tránh lỗi.

Tuy nhiên, nếu đường dẫn lớp thời gian chạy bao gồm Thư viện A phiên bản 1.0 và đường dẫn lớp biên dịch bao gồm Thư viện A phiên bản 2.0, thì trình bổ trợ sẽ hạ cấp phần phụ thuộc trên đường dẫn lớp biên dịch lớp xuống thành Thư viện A phiên bản 1.0 và bạn vẫn sẽ nhận được một lỗi như sau:

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.

Để giải quyết vấn đề này, hãy làm theo một trong những cách sau:

  • Thêm phiên bản phần phụ thuộc mong muốn dưới dạng phần phụ thuộc api vào mô-đun thư viện. Nghĩa là, chỉ có mô-đun thư viện khai báo phần phụ thuộc này, nhưng mô-đun ứng dụng cũng sẽ có quyền truy cập vào API của phần phụ thuộc đó một cách bắc cầu.
  • Ngoài ra, bạn có thể khai báo một phần phụ thuộc nhất định trong cả hai mô-đun, nhưng cũng nên đảm bảo rằng mỗi mô-đun sử dụng cùng một phiên bản của phần phụ thuộc đó. Cân nhắc việc định cấu hình các thuộc tính trên toàn dự án để đảm bảo rằng các phiên bản của từng phần phụ thuộc vẫn nhất quán xuyên suốt dự án của bạn.

Áp dụng logic bản dựng tuỳ chỉnh

Phần này mô tả các chủ đề nâng cao hữu ích khi bạn muốn mở rộng Trình bổ trợ Android cho Gradle hoặc tự viết trình bổ trợ của riêng mình.

Xuất bản các phần phụ thuộc biến thể vào logic tuỳ chỉnh

Thư viện có thể có các chức năng mà các dự án hoặc dự án phụ khác có thể cần sử dụng. Xuất bản một thư viện là quá trình cung cấp đó thư viện cho các đối tượng sử dụng. Các thư viện có thể kiểm soát các phần phụ thuộc mà đối tượng sử dụng sẽ có quyền truy cập tại thời điểm biên dịch và trong thời gian chạy.

Có hai cấu hình riêng biệt chứa các phần phụ thuộc bắc cầu của mỗi đường dẫn lớp mà đối tượng sử dụng sẽ phải cần đến trong quá trình sử dụng thư viện như mô tả dưới đây:

  • variant_nameApiElements: Cấu hình này chứa các phần phụ thuộc bắc cầu có sẵn cho đối tượng sử dụng tại thời điểm biên dịch.
  • variant_nameRuntimeElements: Cấu hình này chứa các phần phụ thuộc bắc cầu có sẵn cho đối tượng sử dụng trong thời gian chạy.

Để tìm hiểu thêm về mối quan hệ giữa các cấu hình khác nhau, hãy truy cập Cấu hình trình bổ trợ Thư viện Java.

Chiến lược giải quyết phần phụ thuộc tuỳ chỉnh

Một dự án có thể chứa một phần phụ thuộc trên hai phiên bản khác nhau của cùng một thư viện, điều này có thể dẫn đến xung đột phần phụ thuộc. Chẳng hạn, nếu dự án của bạn phụ thuộc vào phiên bản 1 của mô-đun A và phiên bản 2 của mô-đun B, và mô-đun A phụ thuộc bắc cầu vào phiên bản 3 của mô-đun B, thì sẽ xảy ra xung đột phiên bản phần phụ thuộc.

Để giải quyết xung đột này, Trình bổ trợ Android cho Gradle sử dụng chiến lược phân giải phần phụ thuộc sau đây: khi trình bổ trợ phát hiện thấy các phiên bản khác nhau của cùng một mô-đun nằm trong biểu đồ phần phụ thuộc thì theo mặc định sẽ chọn mô-đun có số phiên bản cao nhất.

Tuy nhiên, chiến lược này không phải lúc nào cũng hoạt động suôn sẻ như dự kiến. Để tuỳ chỉnh chiến lược phân giải của phần phụ thuộc, hãy sử dụng các cấu hình sau để giải quyết các phần phụ thuộc cụ thể của biến thể cần thiết cho nhiệm vụ của bạn:

  • variant_nameCompileClasspath: Cấu hình này chứa chiến lược phân giải dành cho đường dẫn lớp biên dịch của một biến thể nhất định.
  • variant_nameRuntimeClasspath: Cấu hình này chứa chiến lược phân giải dành cho đường dẫn lớp thời gian chạy của một biến thể nhất định.

Trình bổ trợ Android cho Gradle sẽ chứa đựng những phương thức getter mà bạn có thể sử dụng để truy cập vào các đối tượng cấu hình của từng biến thể. Do đó, bạn có thể sử dụng API biến thể để truy vấn việc phân giải phần phụ thuộc như trong ví dụ bên dưới:

Groovy

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 {
            ...
        }
    }
}

Kotlin

android {
    applicationVariants.all {
        // Return compile configuration objects of a variant.
        compileConfiguration.resolutionStrategy {
        // Use Gradle's ResolutionStrategy API
        // to customize how this variant resolves dependencies.
            ...
        }
        // Return runtime configuration objects of a variant.
        runtimeConfiguration.resolutionStrategy {
            ...
        }
        // Return annotation processor configuration of a variant.
        annotationProcessorConfiguration.resolutionStrategy {
            ...
        }
    }
}

Thông tin phần phụ thuộc dành cho Play Console

Khi xây dựng ứng dụng bằng cách sử dụng AGP phiên bản 4.0.0 trở lên, trình bổ trợ sẽ bao gồm siêu dữ liệu mô tả các phần phụ thuộc thư viện được biên dịch vào ứng dụng của bạn. Khi tải ứng dụng lên, Play Console sẽ kiểm tra siêu dữ liệu này để đưa ra cảnh báo đối với các vấn đề đã biết về SDK và các phần phụ thuộc mà ứng dụng dùng, và trong một số trường hợp, sẽ cung cấp phản hồi hữu ích để giải quyết các vấn đề đó.

Dữ liệu được một khoá chữ ký Google Play nén, mã hoá và lưu trữ trong khối chữ ký của ứng dụng phát hành. Bạn nên lưu giữ tệp phần phụ thuộc này để mang đến trải nghiệm an toàn và tích cực cho người dùng. Tuy nhiên, nếu không muốn chia sẻ thông tin này, bạn có thể chọn không thực hiện như vậy, bằng cách thêm khối dependenciesInfo sau đây trong tệp build.gradle của mô-đun:

android {
    dependenciesInfo {
        // Disables dependency metadata when building APKs.
        includeInApk = false
        // Disables dependency metadata when building Android App Bundles.
        includeInBundle = false
    }
}

Để biết thêm thông tin về các chính sách cũng như vấn đề tiềm ẩn về phần phụ thuộc, hãy xem trang hỗ trợ của chúng tôi về Sử dụng SDK của bên thứ ba trong ứng dụng của bạn.