1. 事前準備
必要條件
- 瞭解如何建構 Jetpack Compose 應用程式。
- 具備 Kotlin 使用經驗。
- 對 Swift 語法有基本瞭解。
軟硬體需求
- 最新的 Android Studio 穩定版 (Meerkat 以上版本)。
- macOS 系統,搭載 Xcode 16.1 和 iPhone 模擬器,且模擬器搭載 iOS 16.0 以上版本。
學習目標
- 瞭解 Kotlin Multiplatform 的基本概念。
- 如何跨平台共用程式碼。
- 如何在 Android 和 iOS 上連結共用程式碼。
2. 做好準備
首先,請按照下列步驟操作:
- 複製 GitHub 存放區:
$ git clone https://github.com/android/codelab-android-kmp.git
您也可以透過 ZIP 檔案下載存放區:
- 在 Android Studio 中開啟
get-started
專案,該專案含有下列分支版本:
main
:包含此專案的範例程式碼,您將修改這些程式碼來完成本程式碼研究室。end
:含有本程式碼研究室的解決方案程式碼。
這個程式碼實驗室會從 main
分支版本開始。您可以按照自己的步調,逐步完成本程式碼實驗室。
- 如要查看解決方案程式碼,請執行以下指令:
$ git clone -b end https://github.com/android/codelab-android-kmp.git
或者,您也可以下載解決方案程式碼:
安裝 XCode
如要建構及執行本程式碼實驗室的 iOS 部分,您需要 Xcode 和 iOS 模擬器:
- 從 Mac App Store 安裝 Xcode (您需要 Apple 帳戶才能安裝)。
- 安裝完成後,請啟動 Xcode。
- 系統會顯示對話方塊,指出哪些元件是內建的,以及哪些元件需要下載。
- 確認 iOS 18.4 (或更新版本)。
- 點選「Download & Install」。
- 等待元件安裝完成。
本程式碼實驗室搭配 Xcode 16.3 進行測試。如果您使用任何其他 Xcode 版本,且遇到問題,建議您下載本程式碼實驗室中所述的確切版本。
範例應用程式
這個程式碼集包含以 Jetpack Compose 建構的 Android 應用程式,以及以 SwiftUI 建構的 iOS 應用程式。Android 專案位於 androidApp/
資料夾中,而 iOS 專案位於 iosApp/
資料夾中,其中也包含可透過 Xcode 執行的 KMPGetStartedCodelab.xcodeproj
。
3. Kotlin Multiplatform 簡介
使用 Kotlin Multiplatform (KMP),您只需編寫一次程式碼,即可跨多個目標平台 (例如 Android、iOS、網頁和電腦) 共用程式碼。透過 KMP,您可以盡量減少程式碼重複情形、維持一致性,並大幅減少開發時間和工作量。
KMP 不會規定您需要共用程式碼的哪些部分或多少部分。您可以自行決定要共用程式碼的哪些部分。
決定要共用的內容
這個共用程式碼可讓您維持一致性,並減少跨平台的重複作業。許多行動團隊一開始會共用一組獨立的商業邏輯 (例如資料庫存取、網路存取等) 和相關測試,然後隨著時間進展共用其他程式碼。
許多 Android Jetpack 程式庫都支援 KMP。已製作成多平台的 Jetpack 程式庫,可根據目標平台提供多層級支援。如需完整的程式庫清單及其支援等級,請參閱說明文件。
舉例來說,其中一個支援的程式庫 (Room 資料庫程式庫) 同時支援 Android、iOS 和電腦。這樣一來,您就能將資料庫建立作業和相關資料庫邏輯移植至通用 KMP 共用模組,同時保留兩個平台上的其他原生程式碼。
遷移資料庫後,您可能會想共用其他網域邏輯。接著,您也可以考慮使用 Android Jetpack 的 ViewModel
多平台程式庫。
如何編寫平台專屬程式碼
Kotlin Multiplatform 推出了實作平台專屬功能的新技術。
預期和實際宣告
expect
actual
Kotlin 語言功能旨在支援 Kotlin 多平台程式碼集,並提供完整的 IDE 支援。
如果平台專屬行為可封裝在單一函式或類別中,這麼做就很理想。這是一種靈活且強大的機制。舉例來說,常見的 expect
類別可以有平台專屬的 actual
對應項目,其中包含更開放的可見度修飾符、額外的超級類型,或不同的參數類型或修飾符。嚴格的介面 API 無法提供這些變化版本。此外,expect
actual
會以靜態方式解析,這表示系統會在編譯期間強制執行平台專屬的實作項目。
Kotlin 中的介面和實作
如果兩個平台都需要遵循類似的 API,但實作方式不同,您可以在共用程式碼中定義介面,做為預期和實際宣告的替代方案。這種做法可讓您使用不同的測試實作方式,或在執行階段切換至其他實作方式。
此外,介面不需要 Kotlin 專屬知識,因此熟悉其他語言介面的開發人員也能輕鬆使用這個選項。
在通用共用程式碼中建立介面,在原生程式碼 (Android 或 Swift) 中實作。
在某些情況下,您需要編寫無法從 KMP 程式碼取得的程式碼。遇到這種情況,您可以在共用程式碼中定義介面,並在 Kotlin 中為 Android 實作該介面,並在 Swift 中提供 iOS 對應項目。一般來說,原生實作項目會透過依附元件插入或直接插入方式,注入至共用程式碼。這項策略可讓您在各個平台上提供自訂體驗,同時保留共用程式碼的通用介面。
4. 透過 Android Studio 開啟 Xcode 專案
安裝 Xcode 後,請確認您可以執行 iOS 應用程式。
您可以直接透過 Android Studio 開啟 iOS 專案。
- 將「Project」窗格切換為使用「Project」檢視畫面
- 在「[root]/iosApp/」資料夾中找出「KmpGetStartedCodelab.xcodeproj」檔案
- 在檔案上按一下滑鼠右鍵,然後選取「Open In」和「Open in Associated Application」。這樣做會在 Xcode 中開啟 iOS 應用程式。
- 按一下 ⌘+R 或前往「Product」選單並選取「Run」,即可在 Xcode 中執行專案
。
5. 新增 KMP 模組
如要在專案中新增 KMP 支援功能,請先為跨平台 (Android、iOS) 重複使用的程式碼建立 shared
模組。
Android Studio 提供一種方法,可使用 KMP 共用模組範本新增 Kotlin Multiplatform 模組。
如要建立 KMP 模組,請在 Android Studio 中執行下列操作:
- 依序前往「File」>「New」>「New Module」>「Kotlin Multiplatform Shared Module」
- 將套件變更為
com.example.kmp.shared
- 按一下「Finish」
- 模組建立完成且 Gradle 同步處理完成後,專案中就會顯示新的
shared
模組。要看到下方顯示的檢視畫面,您可能需要從 Android 檢視畫面切換至專案檢視畫面。
KMP 共用模組範本產生的共用模組包含一些基本預留位置函式和測試。這些預留位置可確保模組從一開始就能順利編譯及執行。
重要事項:請注意 iosApp 資料夾和 iosMain 資料夾的差異。iosApp 資料夾包含獨立的 iOS 應用程式程式碼,而 iosMain 則是您剛新增的 KMP 共用模組的一部分。iosApp 包含 Swift 程式碼,而 iosMain 則包含 iOS 平台專屬的 KMP 程式碼。
將共用模組連結至 Android 應用程式
首先,您必須將新的共用模組連結為 :androidApp
Gradle 模組中的依附元件,讓應用程式能夠使用共用程式碼:
- 開啟
androidApp/build.gradle.kts
檔案。 - 在依附元件區塊中新增
shared
模組依附元件,如下所示
dependencies {
...
implementation(projects.shared)
}
- 同步處理專案與 Gradle 檔案
驗證程式碼對 shared
模組的存取權
為了確認 Android 應用程式可以存取 shared
模組中的程式碼,我們會對應用程式進行簡單更新。
- 在 KMPGetStartedCodelab 專案中,開啟
androidApp/src/main/java/com/example/kmp/getstarted/android/MainActivity.kt
中的MainActivity
檔案 - 修改內容
Text
可組合函式,在顯示的字串中加入platform()
資訊。
Text(
"Hello ${platform()}",
)
- 按一下鍵盤上的
⌥(option)+return
,然後選取Import function 'platform'
- 在 Android 裝置或模擬器上建構並執行應用程式。
這項更新會檢查應用程式是否可從 shared
模組呼叫 platform()
函式,該函式應在 Android 平台上執行時傳回 "Android"
。
6. 將共用模組設定至 iOS 應用程式
Swift 無法像 Android 應用程式一樣直接使用 Kotlin 模組,因此必須產生已編譯的二進位架構 (XCFramework 套件)。XCFramework 套件是二進位檔套件,其中包含為多個 Apple 平台建構所需的架構和程式庫。
共用程式庫的發布方式
Android Studio 中的新模組範本已設定共用模組,可為每個 iOS 架構產生框架。您可以在 shared
模組的 build.gradle.kts
檔案中找到下列程式碼。
val xcfName = "sharedKit"
iosX64 {
binaries.framework {
baseName = xcfName
}
}
iosArm64 {
binaries.framework {
baseName = xcfName
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = xcfName
}
}
在 iOS 專案中連結共用程式庫
這個步驟包括設定 Xcode 以執行指令碼來產生 Kotlin 框架,以及在 iOS 應用程式中呼叫 platform()
函式。
如要使用共用程式庫,您必須按照下列步驟將 Kotlin 框架連結至 iOS 專案:
- 在 Xcode 中開啟 iOS 專案 (先前提到的
iosApp
目錄),然後在專案導覽器中按兩下專案名稱,開啟專案設定。 - 在專案設定的「Build Phases」分頁標籤中,按一下「+」並選取「New Run Script Phase」。這會在所有其他階段後新增「執行指令碼」階段。
- 按兩下「執行指令碼」標題即可重新命名。將預設的「Run Script」名稱變更為「Compile Kotlin Framework」,讓這個階段所執行的事項一目瞭然。
- 展開建構階段,然後在「Shell」下方的文字欄位中輸入指令碼:
cd "$SRCROOT/.."
./gradlew :shared:embedAndSignAppleFrameworkForXcode
- 將「Compile Kotlin Framework」階段拖曳至「Compile Sources」階段之前。
- 按一下 ⌘+B 或前往「Product」選單,然後選取「Build」,即可在 Xcode 中建構專案。請注意,建構進度會顯示在 Xcode 頂端。
如果一切都設定正確,專案就會順利建構。
以這種方式設定執行指令碼建構階段,您就能透過 Xcode 編譯 iOS 專案,而不需要切換至其他工具來編譯共用模組。
驗證程式碼對 shared
模組的存取權
如要確認 iOS 應用程式能成功存取 shared
模組的程式碼,請對應用程式進行與 Android 應用程式相同的簡單更新。
- 在 iOS 專案的 Xcode 中,開啟
ContentView.swift
檔案:Sources/View/ContentView.swift
- 在檔案頂端新增
import sharedKit
。 - 使用
\(Platform_iosKt.platform())
修改Text
檢視畫面,在顯示的字串中加入Platform_iosKt.platform()
資訊。
以下是檔案的最終結果:
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()
}
}
- 按一下 ⌘+R 鍵執行應用程式,或前往「Product」選單,然後點選「Run」。
這項更新會檢查 iOS 應用程式是否能從共用模組呼叫 platform()
函式,該函式應在 iOS 平台上執行時傳回 "iOS"
。
7. 新增 Swift/Kotlin 介面強化工具 (SKIE)
根據預設,Kotlin 產生的原生介面是 Objective-C 標頭。Swift 可直接與 Objective-C 相容,但 Objective-C 不包含 Swift 或 Kotlin 的所有新功能。
這也是在先前範例中,您無法在 Swift 程式碼中直接使用 platform()
呼叫的原因。KMP 無法產生全域函式,因為 Objective-C 只支援類別中封裝的靜態函式,而非全域函式,因此您需要新增 Platform_iosKt
。
如要讓介面更符合 Swift 的使用需求,您可以使用 Swift/Kotlin Interface Enhancer (SKIE) 工具改善 :shared
模組的 Swift 介面。
SKIE 的常見功能如下:
- 更妥善支援預設引數
- 進一步支援密封階層 (
sealed class
、sealed interface
) - 提升對
enum class
的支援,使其在switch
陳述式中具有完整的處理機制 Flow
到AsyncSequence
之間的互通性suspend fun
和async func
之間的互通性
- 將
co.touchlab.skie
Gradle 外掛程式新增至libs.versions.toml
檔案:
[versions]
skie = "0.10.1"
[plugins]
skie = { id = "co.touchlab.skie", version.ref = "skie" }
- 將外掛程式新增至根層級
build.gradle.kts
檔案
plugins {
...
alias(libs.plugins.skie) apply false
}
- 將外掛程式新增至
:shared
模組build.gradle.kts
檔案:
plugins {
...
alias(libs.plugins.skie)
}
- Gradle 同步處理專案
移除靜態函式呼叫
重新建構 iOS 應用程式後,您可能不會立即發現任何變化,但可以移除 Platform_iosKt
前置字串,讓 platform()
函式充當全域函式。
Text("Hello, KMP! \(platform())")
這是因為 SKIE (以及其他功能) 會利用 Swift API 附註,為 API 新增資訊,以便在 Swift 程式碼中更妥善地使用 API。
8. 恭喜
恭喜!您已將第一個共用 Kotlin Multiplatform 程式碼新增至 Android 和 iOS 專案。雖然這只是最基本的起點,但您現在可以開始探索更進階的功能和用途,以便透過 KMP 共用程式碼。
後續步驟
在下一個程式碼實驗室中,瞭解如何使用 Jetpack Room 在 Android 和 iOS 之間共用資料層。
瞭解詳情
- 瞭解哪些 Jetpack 程式庫支援 KMP
- 查看官方的 Kotlin Multiplatform 說明文件