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

Các ứng dụng Android thường được tạo bằng hệ thống xây dựng Gradle. Trước khi đi sâu vào 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 sẽ 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. 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.

Tasks (Tác vụ) đóng gói các lệnh dịch dữ liệu đầu vào thành dữ liệu đầu ra. Trình bổ trợ xác định các tác vụ và cấu hình của các tác vụ đó. Việc áp dụng 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 các tác vụ đó. Ví dụ: việc áp dụng Trình bổ trợ Android cho Gradle (AGP) vào tệp bản dựng sẽ đăng ký tất cả các tác vụ cần thiết để tạo tệp APK hoặc Thư viện Android. Trình bổ trợ java-library cho phép bạn tạo một tệp jar từ mã nguồn Java. Có các trình bổ trợ tương tự cho Kotlin và các ngôn ngữ khác, nhưng các trình bổ trợ khác là để 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 ngay từ đầu, nhưng bạn có thể định cấu hình thêm bản dựng thông qua Ngôn ngữ cụ thể của miền (DSL) khai báo. DSL được thiết kế để bạn có thể chỉ định nội dung cần tạo, thay vì cách tạo nội dung đó. Logic trong các trình bổ trợ sẽ quản lý "cách". 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ư các thông tin khác được mã hoá dưới dạng loại Java (số nguyên, chuỗi hoặc lớp tuỳ chỉnh). Đầu ra chỉ có thể là thư mục hoặc tệp vì các đầu ra này phải được ghi trên ổ đĩa. Kết nối đầu ra của một tác vụ vào đầu vào của một tác vụ khác, 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ệc viết mã tuỳ ý và khai báo tác vụ trong các 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à bạn khó bảo 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ế khai báo logic bản dựng và 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 một bản dựng Gradle chạy?

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 con nào có trong bản dựng, đồng thời thiết lập các đường dẫn lớp chứa tệp bản dựng và trình bổ trợ đã á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 tạo 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 mỗi 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 "xây dựng" ứng dụng thực tế. Đầu ra của cấu hình là một Biểu đồ không tuần hoàn có hướng (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ó dữ liệu đầ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 đây nhất, 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ữ chuyên biệt cho miền (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 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 cố gắng giúp mọi người, từ chuyên gia trong lĩnh vực đến 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ỏ đại diện cho 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ụ của chúng.

Ví dụ: cấu hình phần Android của bản dựng có thể trông như sau:

Kotlin

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

Groovy

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

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

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

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    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 một lambda để định cấu hình và một thuộc tính có cùng tên để truy cập vào hàm đó. Điều này giúp mã trong tệp bản dựng giống như một thông số kỹ thuật dữ liệu hơn.

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

Hệ thống xây dựng Maven đã giới thiệu một quy cách, hệ thống lưu trữ và quản lý 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), với siêu dữ liệu bao gồm phiên bản và các phần phụ thuộc 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 các phần phụ thuộc 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 bằng 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 đó. Giá trị 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 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 đó chỉ là 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 vào các kho lưu trữ này). Kho lưu trữ công khai cho phép mọi người chia sẻ và sử dụng, còn kho lưu trữ của công ty giữ các phần phụ thuộc nội bộ trong nội bộ.

Bạn cũng có thể mô-đun hoá dự án thành dự án phụ (còn gọi là "mô-đun" trong Android Studio). Dự án phụ cũng có thể được dùng làm phần phụ thuộc. Mỗi dự án con tạo ra các đầu ra (chẳng hạn như tệp jar) mà các dự án con 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 riêng những phần cần tạo 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 chi tiết hơn về cách chỉ định phần phụ thuộc trong phần Thêm phần phụ thuộc của 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 các loại bản dựng này 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 giai đoạn).

Bản dựng gỡ lỗi không rút gọn hoặc làm rối mã nguồn của ứng dụng, giúp tăng tốc bản dựng và giữ nguyên tất cả các biểu tượng. Bản dựng này 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ị. Điều này cho phép bạn khám phá dữ liệu đã lưu trong các 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 đi kèm và các biến thể phần phụ thuộc cho ứng dụng. Ví dụ: bạn có thể muốn tạo phiên bản "minh hoạ" và "đầy đủ" cho ứng dụng của mình, hoặc có thể là phiên bản "miễn phí" và "có tính phí". 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 một 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, 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 tên là <flavor><Buildtype>. Ví dụ: với các loại bản dựng releasedebug, cũng như các phiên bản demofull, AGP sẽ tạo các biến thể:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

Các bước tiếp theo

Giờ đây, 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.