建置最終原生二進位檔
依預設,Kotlin/Native 目標會編譯為 *.klib 函式庫產物,此產物可被 Kotlin/Native 本身作為依賴項使用,但無法被執行或作為原生函式庫使用。
若要宣告最終原生二進位檔(例如可執行檔或共享函式庫),請使用原生目標的 binaries 屬性。此屬性代表為此目標建置的原生二進位檔集合,除了預設的 *.klib 產物外,還提供一組用於宣告和配置它們的方法。
kotlin-multiplatform外掛程式預設不會建立任何生產環境二進位檔。預設唯一可用的二進位檔是偵錯測試可執行檔,可讓您從test編譯執行單元測試。
Kotlin/Native 編譯器產生的二進位檔可包含第三方程式碼、資料或衍生作品。這表示如果您分發 Kotlin/Native 編譯的最終二進位檔,您應始終將必要的授權檔案包含在您的二進位發布中。
宣告二進位檔
使用以下工廠方法宣告 binaries 集合的元素。
| 工廠方法 | 二進位種類 | 適用於 |
|---|---|---|
executable | 產品可執行檔 | 所有原生目標 |
test | 測試可執行檔 | 所有原生目標 |
sharedLib | 共享原生函式庫 | 所有原生目標 |
staticLib | 靜態原生函式庫 | 所有原生目標 |
framework | Objective-C 框架 | 僅限 macOS、iOS、watchOS 和 tvOS 目標 |
最簡單的版本不需要任何額外參數,並為每個建置類型建立一個二進位檔。目前,有兩種建置類型可用:
DEBUG– 產生一個未最佳化的二進位檔,帶有在處理偵錯工具時有幫助的額外中繼資料RELEASE– 產生一個不含偵錯資訊的最佳化二進位檔
以下程式碼片段建立兩個可執行二進位檔,分別是偵錯和釋出版本:
kotlin {
linuxX64 { // 請改為定義您的目標。
binaries {
executable {
// 二進位配置。
}
}
}
}如果不需要額外配置,您可以省略 lambda:
binaries {
executable()
}您可以指定為哪些建置類型建立二進位檔。在以下範例中,僅建立 debug 可執行檔:
binaries {
executable(listOf(DEBUG)) {
// 二進位配置。
}
}binaries {
executable([DEBUG]) {
// 二進位配置。
}
}您也可以宣告具有自訂名稱的二進位檔:
binaries {
executable("foo", listOf(DEBUG)) {
// 二進位配置。
}
// 可以省略建置類型列表
// (在這種情況下,將使用所有可用的建置類型)。
executable("bar") {
// 二進位配置。
}
}binaries {
executable('foo', [DEBUG]) {
// 二進位配置。
}
// 可以省略建置類型列表
// (在這種情況下,將使用所有可用的建置類型)。
executable('bar') {
// 二進位配置。
}
}第一個參數設定一個名稱前綴,這是二進位檔案的預設名稱。例如,對於 Windows,此程式碼會產生 foo.exe 和 bar.exe 檔案。您也可以使用名稱前綴來在建置腳本中存取二進位檔。
存取二進位檔
您可以透過其唯一名稱來存取二進位檔以配置它們或取得其屬性(例如,輸出檔案的路徑)。
此名稱基於名稱前綴(如果已指定)、建置類型和二進位種類,遵循以下模式:<optional-name-prefix><build-type><binary-kind>,例如 releaseFramework 或 testDebugExecutable。
靜態和共享函式庫分別帶有
static和shared字尾,例如fooDebugStatic或barReleaseShared。
// 如果沒有此二進位檔,則失敗。
binaries["fooDebugExecutable"]
binaries.getByName("fooDebugExecutable")
// 如果沒有此二進位檔,則返回 null。
binaries.findByName("fooDebugExecutable")// 如果沒有此二進位檔,則失敗。
binaries['fooDebugExecutable']
binaries.fooDebugExecutable
binaries.getByName('fooDebugExecutable')
// 如果沒有此二進位檔,則返回 null。
binaries.findByName('fooDebugExecutable')或者,您可以使用型別化 getter 透過名稱前綴和建置類型存取二進位檔。
// 如果沒有此二進位檔,則失敗。
binaries.getExecutable("foo", DEBUG)
binaries.getExecutable(DEBUG) // 如果未設定名稱前綴,則省略第一個參數。
binaries.getExecutable("bar", "DEBUG") // 您也可以為建置類型使用字串。
// 其他二進位種類也有類似的 getter:
// getFramework、getStaticLib 和 getSharedLib。
// 如果沒有此二進位檔,則返回 null。
binaries.findExecutable("foo", DEBUG)
// 其他二進位種類也有類似的 getter:
// findFramework、findStaticLib 和 findSharedLib。// 如果沒有此二進位檔,則失敗。
binaries.getExecutable('foo', DEBUG)
binaries.getExecutable(DEBUG) // 如果未設定名稱前綴,則省略第一個參數。
binaries.getExecutable('bar', 'DEBUG') // 您也可以為建置類型使用字串。
// 其他二進位種類也有類似的 getter:
// getFramework、getStaticLib 和 getSharedLib。
// 如果沒有此二進位檔,則返回 null。
binaries.findExecutable('foo', DEBUG)
// 其他二進位種類也有類似的 getter:
// findFramework、findStaticLib 和 findSharedLib。將依賴項匯出到二進位檔
建置 Objective-C 框架或原生函式庫(共享或靜態)時,您可能需要不僅封裝當前專案的類別,還需封裝其依賴項的類別。使用 export 方法指定要將哪些依賴項匯出到二進位檔。
kotlin {
//...
sourceSets {
macosMain.dependencies {
// 將被匯出。
api(project(":dependency"))
api("org.example:exported-library:1.0")
// 將不被匯出。
api("org.example:not-exported-library:1.0")
}
}
macosX64("macos").binaries {
framework {
export(project(":dependency"))
export("org.example:exported-library:1.0")
}
sharedLib {
// 可以將不同組的依賴項匯出到不同的二進位檔。
export(project(':dependency'))
}
}
}kotlin {
//...
sourceSets {
macosMain.dependencies {
// 將被匯出。
api project(':dependency')
api 'org.example:exported-library:1.0'
// 將不被匯出。
api 'org.example:not-exported-library:1.0'
}
}
macosX64("macos").binaries {
framework {
export project(':dependency')
export 'org.example:exported-library:1.0'
}
sharedLib {
// 可以將不同組的依賴項匯出到不同的二進位檔。
export project(':dependency')
}
}
}例如,您在 Kotlin 中實作了多個模組並希望從 Swift 存取它們。在 Swift 應用程式中使用多個 Kotlin/Native 框架受到限制,但您可以建立一個傘狀框架並將所有這些模組匯出到其中。
您只能匯出相應原始碼集的
api依賴項。
當您匯出依賴項時,它會將其所有 API 包含到框架 API 中。編譯器會將此依賴項中的程式碼新增到框架中,即使您只使用了其中的一小部分。這會停用對匯出依賴項(以及在某種程度上,其依賴項)的無用程式碼消除。
預設情況下,匯出是非遞移的。這意味著如果您匯出依賴於函式庫 bar 的函式庫 foo,則只有 foo 的方法會新增到輸出框架中。
您可以使用 transitiveExport 選項更改此行為。如果設定為 true,則函式庫 bar 的宣告也會被匯出。
不建議使用
transitiveExport:它會將匯出依賴項的所有遞移依賴項新增到框架中。這可能會增加編譯時間和二進位檔大小。在大多數情況下,您不需要將所有這些依賴項新增到框架 API 中。 對於您需要直接從 Swift 或 Objective-C 程式碼存取的依賴項,請明確使用
export。
binaries {
framework {
export(project(":dependency"))
// 遞移匯出。
transitiveExport = true
}
}binaries {
framework {
export project(':dependency')
// 遞移匯出。
transitiveExport = true
}
}建置通用框架
預設情況下,Kotlin/Native 產生的 Objective-C 框架僅支援一個平台。然而,您可以使用 lipo 工具將此類框架合併為單一的通用(fat)二進位檔。此操作對於 32 位元和 64 位元 iOS 框架尤其有意義。在這種情況下,您可以在 32 位元和 64 位元裝置上使用生成的通用框架。
Fat 框架必須與初始框架具有相同的基本名稱。否則,您將會收到錯誤。
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// 建立並配置目標。
val watchos32 = watchosArm32("watchos32")
val watchos64 = watchosArm64("watchos64")
configure(listOf(watchos32, watchos64)) {
binaries.framework {
baseName = "MyFramework"
}
}
// 建立一個建置 fat 框架的任務。
tasks.register<FatFrameworkTask>("debugFatFramework") {
// Fat 框架必須與初始框架具有相同的基本名稱。
baseName = "MyFramework"
// 預設目標目錄是 "<build directory>/fat-framework"。
destinationDirProperty.set(layout.buildDirectory.dir("fat-framework/debug"))
// 指定要合併的框架。
from(
watchos32.binaries.getFramework("DEBUG"),
watchos64.binaries.getFramework("DEBUG")
)
}
}import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
kotlin {
// 建立並配置目標。
targets {
watchosArm32("watchos32")
watchosArm64("watchos64")
configure([watchos32, watchos64]) {
binaries.framework {
baseName = "MyFramework"
}
}
}
// 建立一個建置 fat 框架的任務。
tasks.register("debugFatFramework", FatFrameworkTask) {
// Fat 框架必須與初始框架具有相同的基本名稱。
baseName = "MyFramework"
// 預設目標目錄是 "<build directory>/fat-framework"。
destinationDirProperty.set(layout.buildDirectory.dir("fat-framework/debug"))
// 指定要合併的框架。
from(
targets.watchos32.binaries.getFramework("DEBUG"),
targets.watchos64.binaries.getFramework("DEBUG")
)
}
}建置 XCFramework
所有 Kotlin Multiplatform 專案都可以使用 XCFramework 作為輸出,將所有目標平台和架構的邏輯收集到單一捆綁包中。與通用(fat)框架不同,您無需在將應用程式發布到 App Store 之前移除所有不必要的架構。
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
kotlin("multiplatform") version "2.2.21"
}
kotlin {
val xcf = XCFramework()
val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())
iosTargets.forEach {
it.binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
}import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '2.2.21'
}
kotlin {
def xcf = new XCFrameworkConfig(project)
def iosTargets = [iosX64(), iosArm64(), iosSimulatorArm64()]
iosTargets.forEach {
it.binaries.framework {
baseName = 'shared'
xcf.add(it)
}
}
}當您宣告 XCFrameworks 時,Kotlin Gradle 外掛程式將會註冊多個 Gradle 任務:
assembleXCFrameworkassemble<Framework name>DebugXCFrameworkassemble<Framework name>ReleaseXCFramework
undefined
如果您在專案中使用 CocoaPods 整合,您可以透過 Kotlin CocoaPods Gradle 外掛程式建置 XCFramework。它包含以下任務,這些任務會建置包含所有註冊目標的 XCFramework,並生成 podspec 檔案:
podPublishReleaseXCFramework,它生成一個釋出 XCFramework 以及一個 podspec 檔案。podPublishDebugXCFramework,它生成一個偵錯 XCFramework 以及一個 podspec 檔案。podPublishXCFramework,它生成偵錯和釋出 XCFrameworks 以及一個 podspec 檔案。
這可以幫助您透過 CocoaPods 將專案的共享部分與行動應用程式分開分發。您也可以使用 XCFrameworks 發布到私有或公共 podspec 儲存庫。
如果 Kotlin 框架是針對不同版本的 Kotlin 建置的,則不建議將其發布到公共儲存庫。這樣做可能會導致終端使用者專案中出現衝突。
自訂 Info.plist 檔案
當產生框架時,Kotlin/Native 編譯器會生成資訊屬性列表檔案 Info.plist。您可以使用相應的二進位選項自訂其屬性:
| 屬性 | 二進位選項 |
|---|---|
CFBundleIdentifier | bundleId |
CFBundleShortVersionString | bundleShortVersionString |
CFBundleVersion | bundleVersion |
若要啟用此功能,請傳遞 -Xbinary=$option=$value 編譯器旗標,或為特定框架設定 binaryOption("option", "value") Gradle DSL:
binaries {
framework {
binaryOption("bundleId", "com.example.app")
binaryOption("bundleVersion", "2")
}
}