Hướng dẫn này giải thích cách phát hiện, tương tác và định cấu hình mục tiêu Android trong dự án Kotlin Multiplatform (KMP) từ một trình bổ trợ Gradle tuỳ chỉnh. Hãy sử dụng các API này khi viết trình bổ trợ quy ước cho bản dựng hoặc xuất bản trình bổ trợ Gradle cho các dự án KMP.
Kiểm tra xem dự án có sử dụng trình bổ trợ Kotlin Multiplatform hay không
Để tránh lỗi và đảm bảo rằng trình bổ trợ của bạn chỉ chạy khi có KMP,
bạn phải kiểm tra xem dự án có sử dụng trình bổ trợ KMP hay không. Tốt nhất là bạn nên sử dụng plugins.withId() để phản ứng với trình bổ trợ KMP đang được áp dụng, thay vì kiểm tra trình bổ trợ đó ngay lập tức. Phương pháp phản ứng này giúp trình bổ trợ của bạn không bị ảnh hưởng bởi thứ tự áp dụng trình bổ trợ trong tập lệnh bản dựng của người dùng.
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
// The KMP plugin is applied, you can now configure your KMP integration.
}
}
}
Sử dụng mô hình
Điểm truy cập cho tất cả cấu hình Kotlin Multiplatform là tiện ích KotlinMultiplatformExtension.
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
}
}
}
Phản ứng với các mục tiêu Kotlin Multiplatform
Sử dụng vùng chứa targets để định cấu hình trình bổ trợ một cách linh hoạt cho từng mục tiêu mà người dùng thêm vào.
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
// 'target' is an instance of KotlinTarget
val targetName = target.name // for example, "android", "iosX64", "jvm"
val platformType = target.platformType // for example, androidJvm, jvm, native, js
}
}
}
}
Áp dụng logic theo mục tiêu cụ thể
Nếu trình bổ trợ của bạn chỉ cần áp dụng logic cho một số loại nền tảng nhất định, thì cách phổ biến là kiểm tra thuộc tính platformType. Đây là một enum phân loại rộng rãi mục tiêu.
Ví dụ: hãy sử dụng thuộc tính này nếu trình bổ trợ của bạn chỉ cần phân biệt một cách khái quát (chẳng hạn như chỉ chạy trên các mục tiêu giống JVM):
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
when (target.platformType) {
KotlinPlatformType.jvm -> { /* Standard JVM */ }
KotlinPlatformType.androidJvm -> { /* Android */ }
KotlinPlatformType.js -> { /* JavaScript */ }
KotlinPlatformType.native -> { /* Any Native (iOS, Linux, Windows, etc.) */ }
KotlinPlatformType.wasm -> { /* WebAssembly */ }
KotlinPlatformType.common -> { /* Metadata target (rarely needs direct plugin interaction) */ }
}
}
}
}
}
Thông tin chi tiết dành riêng cho Android
Mặc dù tất cả mục tiêu Android đều có chỉ báo platformType.androidJvm, nhưng KMP có hai điểm tích hợp riêng biệt tuỳ thuộc vào trình bổ trợ Android cho Gradle được sử dụng: KotlinAndroidTarget cho các dự án sử dụng com.android.library hoặc com.android.application và KotlinMultiplatformAndroidLibraryTarget cho các dự án sử dụng com.android.kotlin.multiplatform.library.
API KotlinMultiplatformAndroidLibraryTarget được thêm vào AGP 8.8.0, vì vậy, nếu người dùng trình bổ trợ của bạn đang chạy trên phiên bản AGP thấp hơn, thì việc kiểm tra target is KotlinMultiplatformAndroidLibraryTarget có thể dẫn đến ClassNotFoundException. Để đảm bảo an toàn, hãy kiểm tra AndroidPluginVersion.getCurrent() trước khi kiểm tra loại tiêu chí nhắm mục tiêu.
AndroidPluginVersion.getCurrent() yêu cầu AGP 8.3.1 trở lên.
import com.android.build.api.AndroidPluginVersion
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
if (target is KotlinAndroidTarget) {
// Old kmp android integration using com.android.library or com.android.application
} else if (
// Check platformType first, so AGP classes load only for Android targets
target.platformType == KotlinPlatformType.androidJvm &&
AndroidPluginVersion.getCurrent() >= AndroidPluginVersion(8, 8) &&
target is KotlinMultiplatformAndroidLibraryTarget
) {
// New kmp android integration using com.android.kotlin.multiplatform.library
}
}
}
}
}
Truy cập vào tiện ích KMP của Android và các thuộc tính của tiện ích này
Trình bổ trợ của bạn chủ yếu tương tác với tiện ích Kotlin do trình bổ trợ Kotlin Multiplatform cung cấp và tiện ích Android do AGP cung cấp cho mục tiêu Android KMP. Khối android {} trong tiện ích Kotlin trong dự án KMP được biểu thị bằng giao diện KotlinMultiplatformAndroidLibraryTarget, giao diện này cũng mở rộng KotlinMultiplatformAndroidLibraryExtension.
Điều này có nghĩa là bạn có thể truy cập vào cả thuộc tính DSL dành riêng cho mục tiêu và dành riêng cho Android thông qua đối tượng duy nhất này.
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
// Access the Android target, which also serves as the Android-specific DSL extension
kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java).configureEach { androidTarget ->
// You can now access properties and methods from both
// KotlinMultiplatformAndroidLibraryTarget and KotlinMultiplatformAndroidLibraryExtension
androidTarget.compileSdk = 34
androidTarget.namespace = "com.example.myplugin.library"
androidTarget.withJava() // enable Java sources
}
}
}
}
Không giống như các trình bổ trợ Android khác (chẳng hạn như com.android.library hoặc com.android.application), trình bổ trợ KMP Android không đăng ký tiện ích DSL chính ở cấp dự án. Cấu hình này nằm trong hệ phân cấp mục tiêu KMP để đảm bảo chỉ áp dụng cho mục tiêu Android cụ thể được xác định trong chế độ thiết lập đa nền tảng.
Xử lý các bản biên dịch và nhóm tài nguyên
Thông thường, các trình bổ trợ cần hoạt động ở cấp độ chi tiết hơn so với mục tiêu, cụ thể là ở cấp độ biên dịch. KotlinMultiplatformAndroidLibraryTarget chứa các thực thể KotlinMultiplatformAndroidCompilation (ví dụ: main, hostTest, deviceTest). Mỗi bản biên dịch được liên kết với các nhóm tài nguyên Kotlin. Trình bổ trợ có thể tương tác với các trình bổ trợ này để thêm nguồn, phần phụ thuộc hoặc định cấu hình các tác vụ biên dịch.
import com.android.build.api.dsl.KotlinMultiplatformAndroidCompilation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
target.compilations.configureEach { compilation ->
// standard compilations are usually 'main' and 'test'
// android target has 'main', 'hostTest', 'deviceTest'
val compilationName = compilation.name
// Access the default source set for this compilation
val defaultSourceSet = compilation.defaultSourceSet
// Access the Android-specific compilation DSL
if (compilation is KotlinMultiplatformAndroidCompilation) {
}
// Access and configure the Kotlin compilation task
compilation.compileTaskProvider.configure { compileTask ->
}
}
}
}
}
}
Định cấu hình bản biên dịch kiểm thử trong trình bổ trợ quy ước
Khi định cấu hình giá trị mặc định cho các bản biên dịch kiểm thử (chẳng hạn như targetSdk cho kiểm thử đo lường) trong một trình bổ trợ quy ước, hãy tránh sử dụng các phương thức hỗ trợ như withDeviceTest { } hoặc withHostTest { }. Việc gọi các phương thức này sẽ kích hoạt ngay việc tạo các biến thể kiểm thử Android tương ứng và biên dịch cho mọi mô-đun áp dụng trình bổ trợ quy ước, điều này có thể không phù hợp. Bạn cũng không thể gọi các phương thức này lần thứ hai trong một mô-đun cụ thể để tinh chỉnh chế độ cài đặt, vì làm như vậy sẽ gửi trạng thái lỗi cho biết quá trình biên dịch đã được tạo.
Thay vào đó, hãy sử dụng khối configureEach phản ứng trên vùng chứa bản biên dịch.
Điều này cho phép bạn cung cấp các cấu hình mặc định chỉ áp dụng nếu và khi một mô-đun bật rõ ràng quá trình biên dịch kiểm thử:
import com.android.build.api.dsl.KotlinMultiplatformAndroidDeviceTestCompilation
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension =
project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java)
.configureEach { androidTarget ->
androidTarget.compilations.withType(
KotlinMultiplatformAndroidDeviceTestCompilation::class.java
).configureEach {
it.targetSdk { version = release(34) }
}
}
}
}
}
Mẫu này đảm bảo rằng trình bổ trợ quy ước của bạn vẫn lười và cho phép
các mô-đun riêng lẻ gọi withDeviceTest { } để bật và tuỳ chỉnh thêm
các kiểm thử mà không xung đột với các giá trị mặc định.
Tương tác với Variant API
Đối với các tác vụ yêu cầu cấu hình giai đoạn muộn, quyền truy cập cấu phần phần mềm (như tệp kê khai hoặc mã byte) hoặc khả năng bật/tắt các thành phần cụ thể, bạn phải sử dụng Android Variant API. Trong các dự án KMP, tiện ích này thuộc loại KotlinMultiplatformAndroidComponentsExtension.
Phần mở rộng được đăng ký ở cấp dự án khi Plugin Android KMP được áp dụng.
Sử dụng beforeVariants để kiểm soát việc tạo biến thể hoặc các thành phần kiểm thử lồng nhau (hostTests và deviceTests). Đây là nơi thích hợp để lập trình tắt kiểm thử hoặc thay đổi giá trị thuộc tính DSL.
import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
androidComponents?.beforeVariants { variantBuilder ->
// Disable all tests for this module
variantBuilder.hostTests.values.forEach { it.enable = false }
variantBuilder.deviceTests.values.forEach { it.enable = false }
}
}
}
}
Sử dụng onVariants để truy cập vào đối tượng biến thể cuối cùng (KotlinMultiplatformAndroidVariant). Đây là nơi bạn có thể kiểm tra các thuộc tính đã phân giải hoặc đăng ký các phép biến đổi trên cấu phần phần mềm như tệp kê khai sáp nhập hoặc các lớp thư viện.
import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
androidComponents?.onVariants { variant ->
// 'variant' is a KotlinMultiplatformAndroidVariant
val variantName = variant.name
// Access the artifacts API
val manifest = variant.artifacts.get(com.android.build.api.artifact.SingleArtifact.MERGED_MANIFEST)
}
}
}
}
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Thiết lập môi trường
- Thêm mô-đun KMP vào dự án
- Thiết lập Trình bổ trợ thư viện Android cho Gradle cho KMP