Tổng quan về bản dựng Gradle

Ứng dụng Android thường được xây dựng bằng hệ thống xây dựng Gradle. Trước khi tìm hiểu chi tiết về cách định cấu hình bản dựng, chúng ta sẽ khám phá các khái niệm đằng sau bản dựng để bạn có thể xem toàn bộ hệ thống.

Bản dựng là gì?

Hệ thống xây dựng chuyển đổi mã nguồn của bạn thành một ứng dụng có thể thực thi. Bản dựng thường liên quan đến nhiều công cụ để phân tích, biên dịch, liên kết và đóng gói ứng dụng hoặc thư viện của bạn. Gradle sử dụng phương pháp dựa trên tác vụ để sắp xếp và chạy các lệnh này.

Tác vụ đóng gói các lệnh chuyển dữ liệu đầu vào thành dữ liệu đầu ra. Trình bổ trợ xác định các nhiệm vụ và cấu hình của nhiệm vụ. Việc áp dụng một trình bổ trợ cho bản dựng sẽ đăng ký các tác vụ của trình bổ trợ đó và kết nối các tác vụ đó với nhau bằng cách sử dụng dữ liệu đầu vào và đầu ra của chúng. Ví dụ: việc áp dụng Trình bổ trợ Android cho Gradle (AGP) cho tệp bản dựng sẽ đăng ký tất cả các tác vụ cần thiết để tạo một tệp APK hoặc Thư viện Android. Trình bổ trợ java-library cho phép bạn tạo tệp jar từ mã nguồn Java. Các trình bổ trợ tương tự cũng có cho Kotlin và các ngôn ngữ khác, nhưng các trình bổ trợ khác được dùng để mở rộng trình bổ trợ. Ví dụ: trình bổ trợ protobuf dùng để thêm tính năng hỗ trợ protobuf vào các trình bổ trợ hiện có như AGP hoặc java-library.

Gradle ưu tiên quy ước hơn cấu hình, vì vậy, các trình bổ trợ sẽ đi kèm với các giá trị mặc định phù hợp, nhưng bạn có thể định cấu hình thêm cho bản dựng thông qua Ngôn ngữ dành riêng cho miền (DSL) khai báo. DSL được thiết kế để bạn có thể chỉ định nội dung cần xây dựng, thay vì cách xây dựng. Logic trong các trình bổ trợ quản lý "cách thức". Cấu hình đó được chỉ định trên một số tệp bản dựng trong dự án (và dự án phụ).

Dữ liệu đầu vào của tác vụ có thể là tệp và thư mục cũng như thông tin khác được mã hoá dưới dạng các kiểu Java (số nguyên, chuỗi hoặc lớp tuỳ chỉnh). Kết quả đầu ra chỉ có thể là thư mục hoặc tệp vì chúng phải được ghi trên ổ đĩa. Việc kết nối đầu ra của một tác vụ với đầu vào của một tác vụ khác sẽ liên kết các tác vụ với nhau để một tác vụ phải chạy trước tác vụ kia.

Mặc dù Gradle hỗ trợ viết mã tuỳ ý và khai báo tác vụ trong tệp bản dựng, nhưng điều này có thể khiến công cụ khó hiểu bản dựng của bạn hơn và khiến bạn khó duy trì hơn. Ví dụ: bạn có thể viết mã kiểm thử cho mã bên trong trình bổ trợ nhưng không thể viết trong tệp bản dựng. Thay vào đó, bạn nên hạn chế logic bản dựng và khai báo tác vụ cho các trình bổ trợ (do bạn hoặc người khác xác định) và khai báo cách bạn muốn sử dụng logic đó trong tệp bản dựng.

Điều gì xảy ra khi bản dựng Gradle chạy?

Quá trình tạo bản dựng Gradle chạy theo ba giai đoạn. Mỗi giai đoạn này thực thi các phần mã khác nhau mà bạn xác định trong tệp bản dựng.

  • Khởi chạy xác định dự án và dự án phụ nào được đưa vào bản dựng, đồng thời thiết lập đường dẫn lớp chứa tệp bản dựng và trình bổ trợ được áp dụng. Giai đoạn này tập trung vào tệp cài đặt, nơi bạn khai báo các dự án cần xây dựng và vị trí để tìm nạp trình bổ trợ và thư viện.
  • Cấu hình đăng ký các tác vụ cho từng dự án và thực thi tệp bản dựng để áp dụng thông số kỹ thuật bản dựng của người dùng. Điều quan trọng là bạn phải hiểu rằng mã cấu hình sẽ không có quyền truy cập vào dữ liệu hoặc tệp được tạo trong quá trình thực thi.
  • Thực thi thực hiện việc "xây dựng" thực tế ứng dụng của bạn. Kết quả của cấu hình là một Đồ thị có hướng không chu trình (DAG) của các tác vụ, đại diện cho tất cả các bước xây dựng bắt buộc mà người dùng yêu cầu (các tác vụ được cung cấp trên dòng lệnh hoặc dưới dạng mặc định trong tệp bản dựng). Biểu đồ này thể hiện mối quan hệ giữa các tác vụ, rõ ràng trong phần khai báo của tác vụ hoặc dựa trên dữ liệu đầu vào và đầu ra của tác vụ. Nếu một tác vụ có đầu vào là đầu ra của một tác vụ khác, thì tác vụ đó phải chạy sau tác vụ kia. Giai đoạn này chạy các tác vụ đã lỗi thời theo thứ tự được xác định trong biểu đồ; nếu dữ liệu đầu vào của một tác vụ không thay đổi kể từ lần thực thi gần nhất, thì Gradle sẽ bỏ qua tác vụ đó.

Để biết thêm thông tin, hãy xem Vòng đời bản dựng của Gradle.

DSL cấu hình

Gradle sử dụng Ngôn ngữ miền chuyên biệt (DSL) để định cấu hình bản dựng. Phương pháp khai báo này tập trung vào việc chỉ định dữ liệu của bạn thay vì viết hướng dẫn từng bước (bắt buộc). Bạn có thể viết tệp bản dựng bằng Kotlin hoặc Groovy, nhưng bạn nên sử dụng Kotlin.

DSL giúp mọi người, các chuyên gia về miền và lập trình viên dễ dàng đóng góp vào một dự án, xác định một ngôn ngữ nhỏ biểu thị dữ liệu theo cách tự nhiên hơn. Trình bổ trợ Gradle có thể mở rộng DSL để định cấu hình dữ liệu cần thiết cho các tác vụ.

Ví dụ: việc định cấu hình phần Android của bản dựng có thể có dạng như sau:

Kotlin

android {
    namespace = "com.example.app"
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

Groovy

android {
    namespace = 'com.example.app'
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = 'com.example.app'
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

Trong hậu trường, mã DSL tương tự như:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var namespace: String?

    fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
        ...
    }

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

Mỗi khối trong DSL được biểu thị bằng một hàm lấy lambda để định cấu hình và một thuộc tính có cùng tên để truy cập. Điều này khiến mã trong tệp bản dựng của bạn giống như một thông số kỹ thuật dữ liệu.

Phần phụ thuộc bên ngoài

Hệ thống xây dựng Maven đã giới thiệu một hệ thống quản lý, lưu trữ và đặc tả phần phụ thuộc. Thư viện được lưu trữ trong kho lưu trữ (máy chủ hoặc thư mục), cùng với siêu dữ liệu bao gồm phiên bản và phần phụ thuộc của thư viện trên các thư viện khác. Bạn chỉ định kho lưu trữ cần tìm kiếm, phiên bản của phần phụ thuộc mà bạn muốn sử dụng và hệ thống xây dựng sẽ tải các phần phụ thuộc đó xuống trong quá trình xây dựng.

Cấu phần phần mềm Maven được xác định theo tên nhóm (công ty, nhà phát triển, v.v.), tên cấu phần phần mềm (tên thư viện) và phiên bản của cấu phần phần mềm đó. Trạng thái này thường được biểu thị dưới dạng group:artifact:version.

Phương pháp này giúp cải thiện đáng kể việc quản lý bản dựng. Bạn sẽ thường nghe thấy các kho lưu trữ như vậy được gọi là "kho lưu trữ Maven", nhưng tất cả đều liên quan đến cách đóng gói và phát hành cấu phần phần mềm. Các kho lưu trữ và siêu dữ liệu này đã được sử dụng lại trong một số hệ thống xây dựng, bao gồm cả Gradle (và Gradle có thể phát hành lên các kho lưu trữ này). Kho lưu trữ công khai cho phép chia sẻ để mọi người cùng sử dụng, còn kho lưu trữ của công ty lưu giữ các phần phụ thuộc nội bộ trong công ty.

Bạn cũng có thể mô-đun hoá dự án của mình thành dự án con (còn gọi là "mô-đun" trong Android Studio), cũng có thể được dùng làm phần phụ thuộc. Mỗi dự án phụ tạo ra kết quả (chẳng hạn như tệp jar) mà các dự án phụ hoặc dự án cấp cao nhất của bạn có thể sử dụng. Điều này có thể cải thiện thời gian xây dựng bằng cách tách biệt những phần cần được xây dựng lại, cũng như phân tách trách nhiệm tốt hơn trong ứng dụng.

Chúng ta sẽ tìm hiểu kỹ hơn về cách chỉ định các phần phụ thuộc trong phần Thêm phần phụ thuộc vào bản dựng.

Biến thể bản dựng

Khi tạo một ứng dụng Android, bạn thường muốn tạo nhiều biến thể. Các biến thể chứa mã khác nhau hoặc được tạo bằng các tuỳ chọn khác nhau, đồng thời bao gồm các loại bản dựng và phiên bản sản phẩm.

Loại bản dựng thay đổi các tuỳ chọn bản dựng đã khai báo. Theo mặc định, AGP thiết lập các loại bản dựng "phát hành" và "gỡ lỗi", nhưng bạn có thể điều chỉnh và thêm các loại bản dựng khác (có thể là để thử nghiệm nội bộ hoặc thử nghiệm theo giai đoạn).

Bản gỡ lỗi không thu nhỏ hoặc làm rối mã nguồn ứng dụng, giúp tăng tốc quá trình tạo bản dựng và giữ nguyên tất cả biểu tượng. Bản gỡ lỗi cũng đánh dấu ứng dụng là "có thể gỡ lỗi", ký ứng dụng bằng khoá gỡ lỗi chung và cho phép truy cập vào các tệp ứng dụng đã cài đặt trên thiết bị. Nhờ đó, bạn có thể khám phá dữ liệu đã lưu trong tệp và cơ sở dữ liệu trong khi chạy ứng dụng.

Bản phát hành tối ưu hoá ứng dụng, ký ứng dụng bằng khoá phát hành và bảo vệ các tệp ứng dụng đã cài đặt.

Khi sử dụng phiên bản sản phẩm, bạn có thể thay đổi nguồn và biến thể phần phụ thuộc đi kèm cho ứng dụng. Ví dụ: bạn có thể muốn tạo phiên bản "demo" và "full" cho ứng dụng của mình, hoặc có thể là phiên bản "free" và "paid". Bạn viết nguồn chung trong thư mục nhóm tài nguyên "chính" và ghi đè hoặc thêm nguồn trong nhóm tài nguyên được đặt tên theo phiên bản.

AGP tạo các biến thể cho mỗi tổ hợp loại bản dựng và phiên bản sản phẩm. Nếu bạn không xác định phiên bản, thì các biến thể sẽ được đặt tên theo loại bản dựng. Nếu bạn xác định cả hai, biến thể sẽ có tên là <flavor><Buildtype>. Ví dụ: với các loại bản dựng release và debug, cùng với các phiên bản demo và full, AGP sẽ tạo các biến thể:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

Các bước tiếp theo

Bây giờ, khi đã nắm được các khái niệm về bản dựng, hãy xem cấu trúc bản dựng Android trong dự án của bạn.