Tổng quan về Android build config

1. Configure your build

Cấu hình build ứng dụng

  • Hệ thống build Android biên dịch mã nguồn, tài nguyên của 1 dự án thành file APK giúp bạn có thể kiểm thử hoặc tải lên chợ ứng dụng.
  • Android Studio sử dụng Gradle như 1 công cụ hỗ trợ quá trình build, với các tính năng mạnh mẽ như: tự động hóa quá trình build, tạo và quản lý linh hoạt các bản build.
  • Android plugin là 1 plugin làm việc với Gradle để cung cấp những quy trình và cấu hình dành riêng cho việc build và kiểm thử ứng dụng Android.
  • Gradle và Android plugin hoạt động độc lập với Andorid Studio. Điều này có nghĩa là bạn có thể build 1 úng dụng Android mà không cần đến Android Studio. Và dĩ nhiên kết quả build không hoặc có sử dụng Android Studio đều là như nhau.
  • Android plugin cho phép bạn tạo ra các bản build khác nhau 1 cách linh hoạt mà không cần phải thay đổi trực tiếp các file mã nguồn của ứng dụng.

Chú ý: vì Android plugin và Gradle hoạt động độc lập với nhau, nên việc update version của mỗi thành phần không liên quan đến nhau.

Quá trình build ứng dụng

  • Để có được kết quả cuối cùng là file APK thì cần trải qua nhiều quá trình build, kết hợp với các công cụ khác nhau.

  1. Trình biên dịch sẽ chuyển đổi mã nguồn thành file DEX(Dalvik Executable) chứa mã bytecode có thể chạy được trên thiết bị Android hoặc bất kỳ đâu.
  2. APK Packager kết hợp file DEX và các tài nguyên ứng dụng thành 1 file APK duy nhất. Tuy nhiên, trước khi ứng dụng có thể cài đặt và phát hành trên chợ ứng dụng thì file APK phải có chữ ký.
  3. APK Packager tạo chữ ký cho file APK bằng cách sử dụng debug hoặc release keystore.
    a. Chế độ debug thường được sử dụng để kiểm thử, Android Studio tự động tạo debug keystore khi build ứng dụng ở chế độ này.
    b. Chế độ release được sử dụng để phát hành ứng dụng lên chợ ứng dụng, lúc này bạn phải tự tạo 1 release keystore để cung cấp cho quá trình build release này.
  4. Trước khi tạo ra file APK cuối cùng, APK Packager sử dụng công cụ ziplian để tối ưu hóa ứng dụng về bộ nhớ khi chạy trên thiết bị.

2. Custom build configurations

Tùy chỉnh cấu hình build ứng dụng

Gradle và Android plugin cung cấp nhiều tùy chọn để tạo ra 1 bản build linh hoạt:

  • Build types: định nghĩa 1 số thuộc tính để gradle sử dụng khi building và cấu hình cho 1 số giai đoạn khác nhau trong vòng đời phát triển của ứng dụng. Mặc định, Android Studio định nghĩa sẵn 2 loại build type là debug và realse. Ngoài ra bạn có thể tự tạo thêm các loại build type khác.
  • Product flavors: thường dùng để tạo ra các phiên bản khác nhau của ứng dụng như bản mấy phí, bản miễn phí. Product flavors là 1 tùy chọn nên mặc định Android Studio sẽ không có product flavors nào.
  • Build variants: 1 bản build variant là sự kết hợp giữa 1 build type và 1 product flavor, do vậy các cấu hình của 1 build variants sẽ là tập những cấu hình của build type + tập những cấu hình của product flavor. Các build variants này được Android Studio tự động tạo ra từ build type và product flavor.
  • Manifest entries: 1 số thuộc tính của Android Manifest có thể được cấu hình từ build gradle. Những giá trị được thiết lập tại đây, sẽ ghi đè những giá trị trước đó trong Android Manifest. Điều này giúp bạn có thể tạo ra nhiều bản build APK với nhiều thuộc tính khác nhau: tên ứng dụng, min SDK verion, target SDK version.
  • Dependencies: hệ thống build quản lý các phụ thuộc từ các nguồn local cũng như remote. Điều này giúp bạn không cần thực hiện 1 số công việc thủ công như: tìm kiếm, download, copy, paste các thư viện vào project của bạn.
  • Signing: hệ thống build cho phép bạn tạo ra chữ ký để kết hợp với quá trình build. Nếu là build debug, hệ thống sẽ tự động sinh chữ ký để bạn có thể debug nhanh hơn. Nhưng khi build release thì bạn phải tạo chữ ký 1 cách thủ công.
  • Code and resource shrinking: hệ thống build cho phép bạn cấu hình để mã hóa mã nguồn bằng việc sử dụng file ProGuard cho mỗi build variant. Hệ thống sẽ dựa vào file này để thiết lập các quy tắc rút gọn mã nguồn sao cho phù hợp.
  • Mutilple APK support: hệ thống build cho phép bạn tạo ra các bản build APK khác nhau, mỗi bản build chỉ chứa 1 số màn hình nhất định hoặc Application Binary Interface (ABI).

3. Build configuration files

Cách cấu hình build

  • Hầu hết các cấu hình build sẽ được viết trong file build.gradle
  • Các file này sử dụng Domain Specific Language(DSL) - ngôn ngữ dành riêng để mô tả các thao tác logic.
  • Có 2 loại ngôn ngữ DSL phổ biến là Grovy và Kotlin. Nếu viết bằng Grovy, file có dạng build.gradle, nếu viết bằng Kotlin, file có dạng build.gradle.kts
  • Khi tạo mới 1 project, Android Studio sẽ tự động tạo ra 1 số file build config với nội dung có sẵn 1 số config, với cấu trúc thư mục mặc định như sau:

  • Dựa vào hình, bạn có thể thấy các file build cũng là 1 phần của ứng dụng. Và không chỉ có 1 file mà có khá nhiều file, mỗi file sẽ có 1 phạm vi ảnh hưởng nhất định trong ứng dụng.

Lưu ý: ở bài viết này mình sẽ sử dụng Kotlin để viết những file cấu hình, nên các file sẽ có dạng .gradle.kts. Còn trong ảnh là mình lấy trên mạng nên không tiện chỉnh sửa lại, sorry all!

3.1. The Gradle settings file

  • Nằm ở ngoài cùng proejct (root project)
  • Tên file là setting.gradle.kts
  • Dùng để định nghĩa những module có trong 1 ứng dụng. Thông thường khi tạo mới project, nội dụng file như sau:
1
2
3
4
include("app")
// hoặc
include(":app")
// cả 2 cách viết trên đều như nhau
  • Khi ứng dụng có nhiều module, thì các module sẽ được include vào đây:
    1
    2
    3
    4
    5
    include("app", "data", "domain")
    // hoặc có thể viết riêng lẻ
    include("app")
    include("data")
    include("domain)

3.2. The top-level build file

  • Nằm ở ngoài cùng proejct (root project)
  • Tên file là build.gradle.kts
  • Dùng để config nhưng thứ cơ bản dùng chung cho tất cả module của ứng dụng
  • Sử dụng 1 số block build như buildscript, allprojects
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    /**
    * - Block này config những repositories và dependencies cho chính nó
    * - Không nên config những dependencies cho các module ở đây, mà nên config ở từng module riêng lẻ
    */
    buildscript {

    /**
    * - Block này config những repositories Gradle có thể tìm kiếm và tải xuống
    * - Các repositories có thể là remote(google, jcenter, maven central, ivy) hoặc local
    */
    repositories {
    google()
    jcenter()
    }

    /**
    * - Block này confign những dependencies Gradle cần trong quá trình build ứng dụng
    */
    dependencies {
    classpath(kotlin(module = "gradle-plugin", version = "1.3.72"))
    classpath("com.android.tools.build:gradle:4.0.0)
    }
    }

    /**
    * - Block này config những repositories và dependencies được sử dụng cho tất cả các module trong project
    * - Không nên config những dependencies cho các module ở đây, mà nên config ở từng module riêng lẻ
    */
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }

Configure project-wide properties: định nghĩa các biến ở mức root project

  • Cho phép định nghĩa các biến được sử dụng cho tất cả các module trong project
  • Sử dụng block ext
1
2
3
4
5
6
7
8
9
buildscript {...}

allprojects {...}

ext {
// định nghĩa các version của dependency
compileSdkVersion = 28
supportLibVersion = "28.0.0"
}
  • Để truy cập những biến này từ các module khác trong cùng project, sử dụng cú pháp rootProject.ext.property_name
    1
    2
    3
    4
    5
    6
    7
    8
    9
    android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    ...
    }
    ...
    dependencies {
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    ...
    }

3.3. The module-level build file

  • Mỗi module thứ cấp, sẽ có 1 file build.gradle.kts riêng
  • Thường dùng để cấu hình các thông tin như build types, product flavors, dependencies …
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
* cấu hình Android plugin
*/

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

/**
* cấu hình riêng cho Android
*/

android {

/**
* compileSdkVersion: chỉ định Android API level để Gradle sử dụng cho app
*/

compileSdkVersion(28)

/**
* - buildToolsVersion: chỉ định phiên bản của SDK build tools, command-line và compiler
* - Thuộc tính này là 1 tùy chọn vì nó thường được lấy mặc định theo Android Studio
*/

buildToolsVersion("29.0.2")

/**
* Block này chứa config chung cho tất cả các build variant, ghi đè 1 số thuộc tính trong file main/AndroidManifest.xml
*/

defaultConfig {

/**
* - applicationId là định danh duy nhất cho 1 ứng dụng
* - Mặc định, applicationId được lấy theo tên package trong file main/AndroidManifet.xml
*/

applicationId = 'com.example.myapp'

// Chỉ định API level nhỏ nhất có thể chạy được ứng dụng
minSdkVersion(15)

// Chỉ định API level được sử dụng để kiểm thử ứng dụng
targetSdkVersion(28)

// Chỉ định version cho ứng dụng
versionCode = 1

// Chỉ định version cho ứng dụng để người dùng có thê nhìn thấy
versionName = "1.0"
}

/**
* - Block này dùng để cấu hình các buile type
* - Mặc định, hệ thống tự định nghĩa 2 build types: debug và release
*/

buildTypes {

getByName("đebug") {

}

getByName("release") {
isMinifyEnabled = true // cho phép rút gọn code khi build.
proguardFile('proguard-rules.pro')
}
}

/**
* - Block này là 1 tùy chọn, dùng để tạo ra các product flavor
* - Ví dụ này tạo ra 2 product flavor: 1 bản free và 1 bản mất phí.
* - Tương ứng với mỗi bản sẽ có những cấu hình khác nhau. Các cấu hình này sẽ được ghi đè với các cấu hình trước nếu đã có.
* - Nếu bạn khai báo product flavors, thì phải chỉ định flavor dimensions cho nó
*/

flavorDimensions("tier")
productFlavors {
create(free) {
applicationId = 'com.example.myapp.free'
}

paid {
applicationId = 'com.example.myapp.paid'
}
}
}

/**
* - Block này chứa các dependencies từ local hoặc remote
*/

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

3.4. Source sets

  • Android Studio tổng hợp các mã nguồn và tài nguyên thành 1 nhóm gọi là source sets với tất cả các bản build

  • Source sets là 1 tùy chọn do vậy Android Studio không tự động sinh ra khi bạn cấu hình các bản build

  • Mặc định, Android Studio chỉ tạo ra sources sets ở đường dẫn

    src/main // được sử dụng cho tất cả các bản build

  • Ngoài ra, bạn có thể tạo ra các source sets với các đường dẫn tương ứng phụ thuộc vào build type và product flavor.

    src/buildType/
    src/productFlavor/
    src/productFlavorBuildType/

  • Nếu có nhiều source sets khác nhau trong project, thì thứ tự ưu tiên của các source sets được sử dụng cho việc build là:

    build variant > build type > product flavor > main source set > library dependencies

Okay, trên đây là những gì tổng quan nhất về việc cấu hình build cho 1 ứng dụng Android. Các bài viết sau mình sẽ đi chi tiết vào từng phần, hẹn gặp lại m.n ở những phần tiếp theo.

Tài liệu tham khảo: Config your build