Định cấu hình các biến thể ấn bản

Các biến thể của ấn bản cho phép bạn tạo nên trải nghiệm phù hợp hơn với cá nhân người dùng. Thông qua việc định cấu hình các biến thể ấn bản, bạn có thể phát hành nhiều biến thể bản dựng, mỗi biến thể có các thuộc tính riêng.

Việc phát hành nhiều biến thể bản dựng của thư viện cho phép người dùng lựa chọn những tính năng phù hợp với nhu cầu của họ. Ví dụ: bạn có thể phát hành nhiều cấu phần phần mềm cho loại bản dựng gỡ lỗi và phát hành. Cấu phần phần mềm của ấn bản gỡ lỗi phải có mã ghi nhật ký bổ sung, cũng như các phần phụ thuộc để quá trình ghi nhật ký bổ sung này hoạt động.

Trước khi tiếp tục, hãy đảm bảo rằng bạn chuẩn bị để phát hành thư viện.

Sử dụng siêu dữ liệu của mô-đun Gradle

Để phát hành các biến thể của thư viện, bạn phải sử dụng Siêu dữ liệu của mô-đun Gradle (GMM). GMM mô tả ấn bản của bạn và duy trì hoạt động quản lý phần phụ thuộc nhận biết được biến thể. Theo mặc định, GMM sẽ được phát hành cùng với thư viện.

Sau đây là các lợi ích khi dùng GMM:

  • Nếu dùng GMM với Gradle 6.0 trở lên, bạn có thể phát hành nhiều biến thể ấn bản hoặc nhiều cấu phần phần mềm. Mỗi biến thể hoặc mỗi cấu phần phần mềm sẽ có những thuộc tính và phần phụ thuộc riêng. Nếu dùng tệp POM của Maven thay vì GMM, bạn chỉ có thể phát hành một cấu phần phần mềm. Nếu dùng tệp POM, bạn có thể phát hành các cấu phần phần mềm bổ sung bằng thuật toán phân loại, nhưng các cấu phần phần mềm bổ sung không được có các phần phụ thuộc riêng.
  • Gradle tự động tạo một biến thể cho quá trình biên dịch và một cho thời gian chạy, mỗi biến thể có các phần phụ thuộc riêng. Bạn có thể phát hành một biến thể cho quá trình biên dịch và một cho thời gian chạy để người dùng có thể lựa chọn tuỳ theo thời điểm họ sử dụng thư viện của bạn. GMM cho phép người dùng xem các phần phụ thuộc khác nhau cho quá trình biên dịch và thời gian chạy, dựa trên việc sử dụng api, implementation hoặc compileOnly/runtimeOnly của thư viện đã phát hành. Hãy xem phần Cấu hình phần phụ thuộc để biết danh sách đầy đủ các phần phụ thuộc. Bạn có thể thực hiện việc này ngay cả khi chỉ phát hành một biến thể ấn bản.
  • Khi sử dụng môi trường thử nghiệm cố định, bạn có thể phát hành thêm biến thể có siêu dữ liệu hoặc chức năng đặc biệt cho phép người dùng chọn biến thể đó. Bạn có thể thực hiện việc này ngay cả khi chỉ phát hành một biến thể ấn bản.

Tìm hiểu về biến thể ấn bản

Để hiểu cách hoạt động của các biến thể ấn bản, bạn cần nắm được các bước phát hành cơ bản của Gradle. Sau đây là một số khái niệm chính về ấn bản:

  • Biến thể bản dựng: Là cấu hình mà Gradle dùng để tạo thư viện; đây là sản phẩm kết hợp giữa loại bản dựng và phiên bản sản phẩm. Để tìm hiểu thêm, hãy xem phần Bảng thuật ngữ về bản dựng Android.
  • Cấu phần phần mềm: Tệp hoặc thư mục mà bản dựng tạo ra. Trong ngữ cảnh phát hành thư viện, cấu phần phần mềm thường là tệp JAR hoặc AAR.
  • Biến thể ấn bản: Là cấu phần phần mềm có các phần phụ thuộc, tính năng và thuộc tính có liên quan. Xin lưu ý rằng Gradle gọi các biến thể ấn bản là biến thể. Tuy nhiên, tài liệu này sẽ dùng tên gọi biến thể ấn bản để phân biệt với biến thể bản dựng.
  • Thuộc tính: Gradle dùng thuộc tính để xác định và chọn biến thể ấn bản khi có nhiều lựa chọn. Ví dụ: org.gradle.usage=java-apiorg.gradle.jvm.version=11 là các thuộc tính của biến thể.
  • Thành phần phần mềm: Là một đối tượng trong Gradle có thể lưu giữ một hoặc nhiều biến thể ấn bản và được phát hành cho một tập toạ độ Maven duy nhất (groupdId:artifactId:version). Thành phần phần mềm hiển thị trong DSL của Gradle thông qua Project.getComponents().
  • Ấn bản: Là những thứ được phát hành vào kho lưu trữ và người dùng sẽ sử dụng. Các ấn bản có chứa một thành phần phần mềm và siêu dữ liệu của thành phần đó, chẳng hạn như mã nhận dạng (groupId:artifactId:version).

Trình bổ trợ Android cho Gradle (AGP) 7.1 ra mắt ngôn ngữ miền chuyên biệt (DSL) để kiểm soát xem biến thể bản dựng nào được dùng trong quá trình phát hành và biến thể nào bị bỏ qua. DSL cho phép bạn tạo các thực thể của SoftwareComponent có chứa:

  • Một biến thể ấn bản từ một biến thể bản dựng
  • Nhiều biến thể ấn bản từ nhiều biến thể bản dựng

Khi tạo thành phần phần mềm có nhiều biến thể ấn bản, AGP sẽ thiết lập các thuộc tính trên từng biến thể để người dùng có thể chọn đúng biến thể họ cần. Những thuộc tính này được lấy trực tiếp từ loại bản dựng và phiên bản mà bạn dùng để tạo biến thể bản dựng. Nếu tạo thành phần chỉ có một biến thể ấn bản duy nhất thì không cần dùng đến các thuộc tính vì không phải phân biệt biến thể.

Tạo thành phần phần mềm chỉ có một biến thể ấn bản

Đoạn mã sau đây định cấu hình thành phần phần mềm có một biến thể ấn bản được tạo từ biến thể bản dựng release, cũng như thêm JAR nguồn làm cấu phần phần mềm phụ:

Kotlin

android {
  publishing {
    singleVariant("release") {
        withSourcesJar()
    }
  }
}

Groovy

android {
  publishing {
    singleVariant('release') {
        withSourcesJar()
    }
  }
}

Bạn có thể tạo nhiều thành phần, mỗi thành phần có một biến thể ấn bản, sau đó phân phối các thành phần đó trên nhiều toạ độ Maven. Trong trường hợp này, thuộc tính sẽ không được đặt trên biến thể ấn bản. Bạn không thể biết được rằng biến thể ấn bản này là của biến thể bản dựng release nếu chỉ nhìn vào siêu dữ liệu của ấn bản. Vì chỉ có một biến thể ấn bản có liên quan, nên bạn không cần phân biệt.

Tạo một thành phần phần mềm có nhiều biến thể ấn bản

Bạn có thể chọn tất cả hoặc một nhóm nhỏ các biến thể bản dựng để đưa vào một thành phần phần mềm. AGP sẽ tự động dùng tên loại bản dựng, tên phiên bản sản phẩm và tên nhóm phiên bản sản phẩm để tạo các thuộc tính sao cho dự án đang dùng có thể phân biệt các biến thể.

Để phát hành tất cả biến thể bản dựng trong một thành phần, hãy chỉ định allVariants() trong khối multipleVariants{} của tệp build.gradle ở cấp độ mô-đun:

Kotlin

android {
  publishing {
    multipleVariants {
      allVariants()
      withJavadocJar()
    }
  }
}

Groovy

android {
  publishing {
    multipleVariants {
      allVariants()
      withJavadocJar()
    }
  }
}

Đoạn mã này sẽ tạo một thành phần duy nhất có tên default. Để đặt tên khác cho thành phần, hãy dùng multipleVariants({name}). Trong trường hợp này, tất cả loại bản dựng và nhóm phiên bản sản phẩm được dùng làm thuộc tính.

Bạn cũng có thể chọn biến thể bạn muốn phát hành bằng cách dùng includeBuildTypeValues()includeFlavorDimensionAndValues():

Kotlin

android {
  publishing {
    multipleVariants("custom") {
      includeBuildTypeValues("debug", "release")
      includeFlavorDimensionAndValues(
        dimension = "color",
        values = arrayOf("blue", "pink")
      )
        includeFlavorDimensionAndValues(
          dimension = "shape",
          values = arrayOf("square")
      )
    }
  }
}

Groovy

android {
  publishing {
    multipleVariants('custom') {
      includeBuildTypeValues('debug', 'release')
      includeFlavorDimensionAndValues(
        /*dimension =*/ 'color',
        /*values =*/ 'blue', 'pink'
      )
      includeFlavorDimensionAndValues(
        /*dimension =*/ 'shape',
        /*values =*/ 'square'
      )
    }
  }
}

Trong ví dụ này, thành phần tuỳ chỉnh chứa tất cả các tổ hợp của (debug, release) đối với loại bản dựng, (blue, pink) đối với nhóm color và (square) đối với nhóm shape.

Bạn phải liệt kê tất cả các nhóm phiên bản, kể cả khi bạn chỉ phát hành một giá trị của một nhóm, để AGP biết cần phải dùng giá trị nào cho mỗi nhóm.

Bảng sau liệt kê biến thể ấn bản tạo ra và các thuộc tính có liên quan của biến thể đó.

Biến thể Thuộc tính
blueSquareDebug com.android.build.api.attributes.BuildTypeAttr="debug" com.android.build.api.attributes.ProductFlavorAttr:color="blue"
blueSquareRelease com.android.build.api.attributes.BuildTypeAttr="release"
com.android.build.api.attributes.ProductFlavorAttr:color="blue"
pinkSquareDebug com.android.build.api.attributes.BuildTypeAttr="debug"
com.android.build.api.attributes.ProductFlavorAttr:color="pink"
pinkSquareRelease com.android.build.api.attributes.BuildTypeAttr="release"
com.android.build.api.attributes.ProductFlavorAttr:color="pink"

Trong thực tế, có nhiều biến thể được phát hành. Ví dụ: mỗi biến thể trong số các biến thể ở trên sẽ được phát hành 2 lần, một lần cho quá trình biên dịch và một lần cho thời gian chạy, với các phần phụ thuộc khác nhau (tuỳ vào việc các phần phụ thuộc đã khai báo dùng implementation hay api) và với giá trị khác nhau cho thuộc tính org.gradle.Usage. Tuy nhiên, cấu phần phần mềm (tệp AAR) của 2 biến thể này là như nhau.

Để biết thêm thông tin, hãy xem tài liệu về API publishing.

Vấn đề về khả năng tương thích khi phát hành thư viện nhiều phiên bản

Một dự án sử dụng AGP 7.0 trở xuống không thể sử dụng các thư viện đa phiên bản phát hành bằng AGP 7.1 trở lên. Đây là vấn đề đã biết do việc thay đổi tên thuộc tính cho nhóm phiên bản sản phẩm từ dimensionName thành com.android.build.api.attributes.ProductFlavor:dimensionName trong AGP 7.1. Tuỳ thuộc vào cách thiết lập dự án, bạn có thể sử dụng missingDimensionStrategy trong API biến thể cũ để giải quyết vấn đề này.

Ví dụ: giả sử dự án ứng dụng của bạn chỉ có một nhóm phiên bản sản phẩm phiên bản:

Kotlin

android {
    applicationVariants.forEach { variant ->
        val flavor = variant.productFlavors[0].name
        val attributePrefix = "com.android.build.api.attributes.ProductFlavor"
        val dimensionName = "version"
        variant.missingDimensionStrategy("$attributePrefix:$dimensionName", flavor)
    }
}

Groovy

android {
    applicationVariants.forEach { variant ->
        def flavor = variant.getProductFlavors()[0].name
        def attributePrefix = "com.android.build.api.attributes.ProductFlavor"
        def dimensionName = "version"
        variant.missingDimensionStrategy("$attributePrefix:$dimensionName", flavor)
    }
}