1. Trước khi bắt đầu
Điều kiện tiên quyết
- Kiến thức về cách tạo ứng dụng bằng Jetpack Compose.
- Có kinh nghiệm sử dụng Kotlin.
- Có hiểu biết cơ bản về cú pháp Swift.
Những gì bạn cần
- Phiên bản ổn định mới nhất của Android Studio (Meerkat trở lên).
- Hệ thống macOS có Xcode 16.1 và trình mô phỏng iPhone chạy iOS 16.0 trở lên.
Kiến thức bạn sẽ học được
- Tìm hiểu thông tin cơ bản về Kotlin Multiplatform.
- Cách chia sẻ mã trên các nền tảng.
- Cách kết nối mã dùng chung trên Android và iOS.
2. Bắt đầu thiết lập
Để bắt đầu, hãy làm theo các bước sau:
- Sao chép kho lưu trữ GitHub:
$ git clone https://github.com/android/codelab-android-kmp.git
Ngoài ra, bạn có thể tải kho lưu trữ xuống dưới dạng tệp ZIP:
- Trong Android Studio, hãy mở dự án
get-started
chứa các nhánh sau:
main
: Chứa đoạn mã khởi đầu cho dự án này, nơi bạn thực hiện các thay đổi để hoàn tất lớp học lập trình.end
: Chứa đoạn mã giải pháp cho lớp học lập trình này.
Lớp học lập trình này bắt đầu bằng nhánh main
. Bạn có thể làm theo hướng dẫn từng bước trong lớp học lập trình theo tiến độ của riêng mình.
- Nếu bạn muốn thấy đoạn mã giải pháp, hãy chạy lệnh sau:
$ git clone -b end https://github.com/android/codelab-android-kmp.git
Ngoài ra, bạn có thể tải đoạn mã giải pháp xuống:
Cài đặt Xcode
Để tạo và chạy phần iOS của lớp học lập trình này, bạn cần có Xcode và một trình mô phỏng iOS:
- Cài đặt Xcode từ Mac App Store (để làm việc này, bạn cần có tài khoản Apple).
- Sau khi cài đặt, hãy chạy Xcode.
- Một hộp thoại sẽ xuất hiện cho biết những thành phần nào được tích hợp sẵn và những thành phần nào bạn cần tải xuống.
- Kiểm tra iOS 18.4 (trở lên).
- Nhấp vào Download & Install (Tải xuống và cài đặt).
- Chờ cho đến khi các thành phần được cài đặt.
Lớp học lập trình này được kiểm thử bằng Xcode 16.3. Nếu sử dụng bất kỳ phiên bản Xcode nào khác và gặp vấn đề, bạn nên tải đúng phiên bản được đề cập trong lớp học lập trình này xuống.
Ứng dụng mẫu
Cơ sở mã này chứa cả một ứng dụng Android được tạo bằng Jetpack Compose và một ứng dụng iOS được tạo bằng SwiftUI. Dự án Android nằm trong thư mục androidApp/
, trong khi dự án iOS nằm trong thư mục iosApp/
cũng chứa KMPGetStartedCodelab.xcodeproj
để chạy bằng Xcode.
3. Giới thiệu về Kotlin Multiplatform
Kotlin Multiplatform (KMP) cho phép bạn viết mã một lần và chia sẻ mã đó trên nhiều nền tảng mục tiêu, chẳng hạn như Android, iOS, Web và máy tính. Bằng cách tận dụng KMP, bạn có thể giảm thiểu tình trạng trùng lặp mã, duy trì tính nhất quán và giảm đáng kể thời gian cũng như công sức phát triển.
KMP không chỉ định lượng hoặc phần nào của cơ sở mã mà bạn cần chia sẻ. Bạn có toàn quyền quyết định muốn chia sẻ những phần mã nào.
Quyết định nội dung cần chia sẻ
Nhờ có mã dùng chung này, bạn có thể duy trì tính nhất quán và giảm tình trạng trùng lặp trên các nền tảng. Nhiều nhóm phát triển ứng dụng di động bắt đầu bằng cách chia sẻ một tập hợp logic nghiệp vụ riêng biệt (ví dụ: quyền truy cập vào cơ sở dữ liệu, quyền truy cập vào mạng, v.v.) và các chương trình kiểm thử liên quan, sau đó chia sẻ mã bổ sung theo thời gian.
Nhiều thư viện Android Jetpack hỗ trợ KMP. Các thư viện Jetpack được tạo đa nền tảng cung cấp nhiều cấp độ hỗ trợ tuỳ thuộc vào nền tảng mục tiêu. Để biết danh sách đầy đủ các thư viện và cấp độ hỗ trợ mà các thư viện đó cung cấp, hãy xem tài liệu.
Ví dụ: thư viện cơ sở dữ liệu Room – một trong những thư viện được hỗ trợ, hỗ trợ cả Android, iOS và máy tính. Điều này cho phép bạn chuyển tính năng tạo cơ sở dữ liệu và logic cơ sở dữ liệu liên quan sang một mô-đun dùng chung KMP phổ biến trong khi vẫn giữ lại mã gốc khác trên cả hai nền tảng.
Bước tiếp theo có thể thực hiện sau khi di chuyển cơ sở dữ liệu là chia sẻ logic miền khác. Sau đó, bạn cũng có thể cân nhắc sử dụng thư viện đa nền tảng ViewModel
trên Android Jetpack.
Cách viết mã dành riêng cho nền tảng
Kotlin Multiplatform giới thiệu các kỹ thuật mới để triển khai chức năng dành riêng cho nền tảng.
Nội dung khai báo dự kiến và thực tế
Tính năng ngôn ngữ Kotlin expect
actual
được dùng để hỗ trợ cơ sở mã Kotlin đa nền tảng với khả năng hỗ trợ IDE đầy đủ.
Phương pháp này lý tưởng khi có thể đóng gói hành vi dành riêng cho nền tảng trong một hàm hoặc lớp duy nhất. Đây là một cơ chế linh hoạt và mạnh mẽ. Ví dụ: một lớp expect
phổ biến có thể có các phiên bản actual
dành riêng cho nền tảng với các đối tượng sửa đổi chế độ hiển thị mở hơn, các loại siêu dữ liệu bổ sung hoặc các loại tham số hoặc đối tượng sửa đổi khác nhau. Bạn sẽ không thể tạo những loại biến thể này bằng một API giao diện nghiêm ngặt. Hơn nữa, expect
actual
được phân giải tĩnh, nghĩa là việc triển khai dành riêng cho nền tảng được thực thi tại thời điểm biên dịch.
Giao diện và cách triển khai trong Kotlin
Nếu cả hai nền tảng đều cần tuân theo các API tương tự nhưng có cách triển khai khác nhau, bạn có thể xác định một giao diện trong mã dùng chung thay cho các nội dung khai báo dự kiến và thực tế. Nhờ phương pháp này, bạn có thể sử dụng nhiều cách triển khai kiểm thử hoặc chuyển sang một cách triển khai khác trong thời gian chạy.
Ngoài ra, vì giao diện không yêu cầu kiến thức cụ thể về Kotlin nên các nhà phát triển quen thuộc với giao diện bằng ngôn ngữ khác có thể dễ dàng sử dụng lựa chọn này.
Giao diện trong mã dùng chung phổ biến, cách triển khai trong mã gốc (Android hoặc Swift).
Trong một số trường hợp, bạn cần viết mã không có trong mã KMP. Trong trường hợp này, bạn có thể xác định một giao diện trong mã dùng chung, triển khai giao diện đó cho Android trong Kotlin và cung cấp giao diện tương ứng cho iOS trong Swift. Thông thường, các cách triển khai gốc sẽ được chèn vào mã dùng chung, thông qua tính năng chèn phần phụ thuộc hoặc theo cách trực tiếp. Nhờ có chiến lược này, bạn có thể tạo ra trải nghiệm tuỳ chỉnh trên từng nền tảng mà vẫn duy trì một giao diện chung cho mã dùng chung.
4. Mở dự án Xcode trong Android Studio
Sau khi cài đặt Xcode, bạn cần đảm bảo rằng mình có thể chạy ứng dụng iOS.
Bạn có thể mở dự án iOS ngay trong Android Studio.
- Chuyển ngăn Project (Dự án) để sử dụng Project View (Khung hiển thị dự án)
- Tìm tệp KmpGetStartedCodelab.xcodeproj trong thư mục [root]/iosApp/
- Nhấp chuột phải vào tệp đó rồi chọn Open In (Mở trong) và Open in Associated Application (Mở trong ứng dụng liên kết). Thao tác này sẽ mở ứng dụng iOS trong Xcode.
- Chạy dự án trong Xcode bằng cách nhấp vào tổ hợp phím ⌘+R hoặc chuyển đến trình đơn Product (Sản phẩm) rồi chọn Run (Chạy)
.
5. Thêm một mô-đun KMP
Để thêm tính năng hỗ trợ KMP vào dự án, trước tiên, hãy tạo một mô-đun shared
cho mã sẽ được sử dụng lại trên các nền tảng (Android, iOS).
Với Android Studio, bạn có thể thêm mô-đun Kotlin Multiplatform bằng cách sử dụng mẫu mô-đun KMP dùng chung.
Cách tạo mô-đun KMP trong Android Studio:
- Chuyển đến File > New > New Module > Kotlin Multiplatform Shared Module (Tệp > Mới > Mô-đun mới > Mô-đun dùng chung Kotlin Multiplatform)
- Thay đổi gói thành
com.example.kmp.shared
- Nhấp vào Finish (Hoàn tất)
- Sau khi quá trình tạo mô-đun hoàn tất và Gradle đồng bộ hoá xong, một mô-đun
shared
mới sẽ xuất hiện trong dự án. Để xem khung hiển thị ở bên dưới, bạn có thể phải chuyển từ Khung hiển thị Android sang Khung hiển thị dự án.
Mô-đun dùng chung do mẫu Mô-đun dùng chung KMP tạo ra bao gồm một số hàm và phép kiểm thử phần giữ chỗ cơ bản. Các phần giữ chỗ này đảm bảo rằng mô-đun biên dịch và chạy thành công ngay từ đầu.
Quan trọng: Hãy lưu ý sự khác biệt giữa thư mục iosApp và thư mục iosMain. Thư mục iosApp chứa mã ứng dụng iOS độc lập, còn iosMain là một phần của mô-đun dùng chung KMP mà bạn vừa thêm. iosApp chứa mã Swift, còn iosMain chứa mã KMP dành riêng cho nền tảng iOS.
Liên kết mô-đun dùng chung với ứng dụng Android
Trước tiên, bạn cần liên kết mô-đun dùng chung mới dưới dạng một phần phụ thuộc trong mô-đun Gradle :androidApp
để cho phép ứng dụng dùng mã dùng chung:
- Mở tệp
androidApp/build.gradle.kts
- Thêm phần phụ thuộc mô-đun
shared
vào khối phần phụ thuộc như sau
dependencies {
...
implementation(projects.shared)
}
- Đồng bộ hoá dự án với các tệp Gradle của dự án đó
Xác minh quyền truy cập của mã vào mô-đun shared
Để xác minh rằng ứng dụng Android có thể truy cập vào mã từ mô-đun shared
, chúng ta sẽ tạo một bản cập nhật đơn giản cho ứng dụng.
- Trong dự án KMPGetStartedCodelab, hãy mở tệp
MainActivity
tạiandroidApp/src/main/java/com/example/kmp/getstarted/android/MainActivity.kt
- Sửa đổi thành phần kết hợp
Text
của nội dung để đưa thông tinplatform()
vào chuỗi được hiển thị.
Text(
"Hello ${platform()}",
)
- Nhấp vào
⌥(option)+return
trên bàn phím rồi chọnImport function 'platform'
- Tạo và chạy ứng dụng trên trình mô phỏng hoặc thiết bị Android.
Bản cập nhật này kiểm tra xem ứng dụng có thể gọi hàm platform()
từ mô-đun shared
hay không. Hàm này sẽ trả về "Android"
khi chạy trên nền tảng Android.
6. Thiết lập mô-đun dùng chung cho ứng dụng iOS
Swift không thể sử dụng trực tiếp mô-đun Kotlin như các ứng dụng Android, đồng thời yêu cầu tạo một khung nhị phân đã biên dịch (gói XCFramework). Gói XCFramework là một gói nhị phân bao gồm các khung và thư viện cần thiết để tạo ứng dụng cho nhiều nền tảng của Apple.
Cách phân phối thư viện dùng chung
Mẫu mô-đun mới trong Android Studio đã định cấu hình mô-đun dùng chung để tạo khung cho từng cấu trúc iOS. Bạn có thể tìm thấy mã sau trong tệp build.gradle.kts
của mô-đun shared
.
val xcfName = "sharedKit"
iosX64 {
binaries.framework {
baseName = xcfName
}
}
iosArm64 {
binaries.framework {
baseName = xcfName
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = xcfName
}
}
Liên kết thư viện dùng chung trong dự án iOS
Bước này bao gồm việc thiết lập Xcode để chạy một tập lệnh tạo khung Kotlin và gọi hàm platform()
trong ứng dụng iOS.
Để sử dụng thư viện dùng chung, bạn cần kết nối khung Kotlin với dự án iOS theo các bước sau:
- Mở dự án iOS (thư mục
iosApp
đã đề cập trước đó) trong Xcode và mở phần cài đặt dự án bằng cách nhấp đúp vào tên dự án trong trình điều hướng dự án - Trên thẻ Build Phases (Giai đoạn tạo) trong phần cài đặt dự án, hãy nhấp vào dấu + rồi chọn New Run Script Phase (Giai đoạn chạy tập lệnh mới). Thao tác này sẽ thêm một giai đoạn "Run script" (Chạy tập lệnh) mới sau tất cả các giai đoạn khác.
- Nhấp đúp vào tiêu đề Run Script (Chạy tập lệnh) để đổi tên tập lệnh. Thay đổi tên Run Script (Chạy tập lệnh) mặc định thành Compile Kotlin Framework (Biên dịch khung Kotlin) để dễ hiểu chức năng của giai đoạn này.
- Mở rộng giai đoạn tạo và trong trường văn bản bên dưới Shell (Màn hình shell), hãy nhập mã tập lệnh:
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode
- Kéo giai đoạn Compile Kotlin Framework (Biên dịch khung Kotlin) trước giai đoạn Compile Sources (Biên dịch nguồn).
- Tạo dự án trong Xcode bằng cách nhấp vào tổ hợp phím ⌘+B hoặc chuyển đến Product menu (Trình đơn sản phẩm) rồi chọn Build (Tạo). Lưu ý rằng tiến trình tạo sẽ hiển thị ở đầu Xcode.
Nếu bạn thiết lập đúng mọi thứ, dự án sẽ được tạo thành công.
Khi thiết lập giai đoạn chạy bản dựng tập lệnh theo cách này, bạn có thể biên dịch dự án iOS từ Xcode mà không cần chuyển sang một công cụ khác để biên dịch mô-đun dùng chung.
Xác minh quyền truy cập của mã vào mô-đun shared
Để xác minh rằng ứng dụng iOS có thể truy cập thành công vào mã từ mô-đun shared
, bạn sẽ tạo một bản cập nhật đơn giản cho ứng dụng giống như bạn đã thực hiện với ứng dụng Android.
- Trong dự án iOS, trong Xcode, hãy mở tệp
ContentView.swift
tại:Sources/View/ContentView.swift
- Thêm
import sharedKit
vào đầu tệp. - Sửa đổi khung hiển thị
Text
để đưa thông tinPlatform_iosKt.platform()
vào chuỗi được hiển thị bằng\(Platform_iosKt.platform())
.
Dưới đây là kết quả cuối cùng của tệp:
import SwiftUI
import sharedKit
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, \(Platform_iosKt.platform())!")
}
.padding()
}
}
- Chạy ứng dụng bằng cách nhấp vào tổ hợp phím ⌘+R hoặc chuyển đến trình đơn Product (Sản phẩm) rồi nhấp vào Run (Chạy).
Quá trình cập nhật này kiểm tra xem ứng dụng iOS có thể gọi hàm platform()
từ mô-đun dùng chung hay không. Hàm này sẽ trả về "iOS"
khi chạy trên nền tảng iOS.
7. Thêm Trình tăng cường giao diện Swift/Kotlin (SKIE)
Theo mặc định, giao diện gốc mà Kotlin tạo ra là tiêu đề Objective-C. Swift tương thích trực tiếp với Objective-C, nhưng Objective-C không bao gồm tất cả các tính năng hiện đại của Swift hoặc Kotlin.
Đây cũng là lý do tại sao trong ví dụ trước, bạn không thể sử dụng lệnh gọi platform()
ngay trong mã Swift – KMP không thể tạo hàm toàn cục, vì Objective-C không hỗ trợ hàm toàn cục, mà chỉ hỗ trợ các hàm tĩnh được đóng gói trong một lớp, đó là lý do bạn cần thêm Platform_iosKt
.
Để giao diện thân thiện hơn với Swift, bạn có thể sử dụng công cụ Trình tăng cường giao diện Swift/Kotlin (SKIE) để cải thiện giao diện Swift của mô-đun :shared
.
Các tính năng phổ biến của SKIE là:
- Hỗ trợ tốt hơn cho đối số mặc định
- Hỗ trợ tốt hơn cho hệ phân cấp kín (
sealed class
,sealed interface
) - Hỗ trợ tốt hơn cho
enum class
bằng cách xử lý đầy đủ trong câu lệnhswitch
- Khả năng tương tác giữa
Flow
vớiAsyncSequence
- Khả năng tương tác giữa
suspend fun
vàasync func
- Thêm trình bổ trợ Gradle
co.touchlab.skie
vào tệplibs.versions.toml
:
[versions]
skie = "0.10.1"
[plugins]
skie = { id = "co.touchlab.skie", version.ref = "skie" }
- Thêm trình bổ trợ vào tệp
build.gradle.kts
gốc
plugins {
...
alias(libs.plugins.skie) apply false
}
- Thêm trình bổ trợ vào tệp
build.gradle.kts
của mô-đun:shared
:
plugins {
...
alias(libs.plugins.skie)
}
- Gradle đồng bộ hoá dự án
Xoá lệnh gọi hàm tĩnh
Bây giờ, khi tạo lại ứng dụng iOS, bạn có thể không nhận thấy điều gì ngay lập tức, nhưng bạn có thể xoá tiền tố Platform_iosKt
và để hàm platform()
hoạt động như một hàm toàn cục.
Text("Hello, KMP! \(platform())")
Điều này có hiệu quả vì SKIE (cùng với các tính năng khác) tận dụng Ghi chú API của Swift. Ghi chú này sẽ thêm thông tin về các API để sử dụng API hiệu quả hơn từ mã Swift.
8. Xin chúc mừng
Xin chúc mừng! Bạn đã thêm mã Kotlin Multiplatform dùng chung đầu tiên vào các dự án Android và iOS. Mặc dù đây chỉ là bước khởi đầu cơ bản, nhưng giờ đây, bạn có thể bắt đầu khám phá các tính năng nâng cao cũng như các trường hợp sử dụng khác để chia sẻ mã với KMP.
Tiếp theo là gì?
Tìm hiểu cách sử dụng Jetpack Room để chia sẻ lớp dữ liệu giữa Android và iOS trong lớp học lập trình tiếp theo.
Tìm hiểu thêm
- Tìm hiểu những thư viện Jetpack hỗ trợ KMP
- Xem tài liệu chính thức về Kotlin Multiplatform