程式界有句名言叫做 “Don’t reinventing the wheel”,當有個很成熟完美的 library 可以使用時,如果硬要自己刻一套使用就有點沒效率了,而我們的 shared module 身為整體商業邏輯的核心,一定有很多地方需要使用第三方的 library 讓我們開發更輕鬆。但具體要怎麼做呢?如果我們今天要依賴的 library 是 platform dependent,或是 language dependent 的時候,支援度又是如何?
讓我們從最簡單的例子開始,如果我們今天想要使用的功能是 platform independent 而且也是 pure Kotlin,那其實我們就直接在 commonMain 這個區塊宣告 dependency 就可以了,小範例如下:
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.example:my-library:1.0") // library shared for all source sets
}
}
}
}
一切聽起來都很合理,但為什麼寫在 commonMain 的 dependency 其他 module 也能使用呢,我們其實可以從昨天介紹的 build.gradle.kts 中看出端倪,底下是 iosMain 的定義:
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
}
我們可以看到 iosMain 直接依賴於 commonMain,而且又被 iosArm64Main 以及 iosSimulatorArm64Main 依賴,所以寫在 commonMain 的自然就所有人都可以用囉。
而 android 的寫法稍微有不同,大家也可以想想差別是什麼。
再來差不多一樣直覺的是 android 自己的 dependency,這邊跟 commonMain 稍微不一樣的是 androidMain 是可以使用 Java 的 library 的,所以你如果有什麼非用 Java library 的原因的話,可以直接在這一層宣告就可以了(雖然並不怎麼建議),小範例如下:
val androidMain by getting {
dependencies {
implementation("com.squareup.retrofit2:retrofit:2.9.0")
}
}
好,有了 android 的範例,我們可以猜測 iosMain 也可以一般 ios 開發會使用的 library 囉?
概念上類似,因為 iosMain 也是會 compile 成 native 的 binary。但實際上還稍微有點差距的,以目前來說,如果你想使用的 library 是 pure Objective-C 、或是 Swift 但有使用 @objc
來的話就可以正常使用,pure Swift 的 library 目前是還不支援的。
以下以 Cocoapods + AFNetworking 為例說明,首先先在 shared 的 build.gradle.kt 裡的 cocoapods 新增 AFNetworking 如下:
kotlin {
cocoapods {
//..
pod("AFNetworking") {
version = "~> 4.0.1"
}
}
}
接下來 compile 過後,你就可以在 iosMain 使用 AFNetworking 的功能囉!
import cocoapods.AFNetworking.*
我們今天探討了如何在 KMM 的 module 加上 dependency,甚至是 platform/language dependent 的 library,但如果每個 dependency 都是加在 platform dependent 的 module 裡,似乎把多個專案合在一起的意義就不大了,我們還有什麼方法可以讓這件事情更有結構性嗎?記得不要錯過明天的 expect/actual 介紹~~