如何为Kotlin多平台iOS模块添加Swift库依赖?求示例项目
I get it—adding Java dependencies for Android in KMP is straightforward, but figuring out Swift library integration for iOS can be tricky. The key here is to use CocoaPods as the bridge between your Kotlin Multiplatform project and Swift libraries like SwiftSoup. Below is a complete, runnable configuration and step-by-step breakdown to solve your problem.
Step 1: Update Plugins to Include CocoaPods
First, you need to add the Kotlin CocoaPods plugin to your project. This lets Gradle manage CocoaPods dependencies for your iOS target seamlessly.
Step 2: Configure iOS Target with CocoaPods
Modify your iOS target setup to enable CocoaPods, and declare the SwiftSoup dependency directly in the configuration.
Step 3: Add Expect/Actual Wrappers (Critical!)
Kotlin Native can't directly call Swift code without a bridge. You'll need to define an expect interface in your common source set, then implement it with actual in the iOS source set to wrap SwiftSoup calls (and do the same for Android with Jsoup).
Full Modified build.gradle.kts
Here's your updated build script with all necessary changes:
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget val serializationVersion = "0.20.0" val kotlinVersion = "1.3.72" plugins { kotlin("multiplatform") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion // Add CocoaPods plugin to handle Swift dependencies kotlin("native.cocoapods") version kotlinVersion } buildscript { dependencies { classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion") } } repositories { jcenter() mavenCentral() } kotlin { // Configure CocoaPods for iOS cocoapods { summary = "Shared KMP library with HTML parsing capabilities" homepage = "https://github.com/your-repo-url" ios.deploymentTarget = "13.0" // Declare SwiftSoup dependency here pod("SwiftSoup") { version = "2.6.0" // Use the latest stable version available } } // iOS target configuration (adjusted for CocoaPods integration) val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget = if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true) ::iosArm64 else ::iosX64 iOSTarget("ios") { binaries { framework { baseName = "SharedCode" } } } jvm("android") sourceSets["commonMain"].dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-common") implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion") } sourceSets["androidMain"].dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("org.jsoup:jsoup:1.13.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion") } sourceSets["iosMain"].dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serializationVersion") } } val packForXcode by tasks.creating(Sync::class) { group = "build" val mode = System.getenv("CONFIGURATION") ?: "DEBUG" val framework = kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode) inputs.property("mode", mode) dependsOn(framework.linkTask) val targetDir = File(buildDir, "xcode-frameworks") from({ framework.outputDirectory }) into(targetDir) doLast { val gradlew = File(targetDir, "gradlew") gradlew.writeText("#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty(\"java.home\")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n") gradlew.setExecutable(true) } } tasks.getByName("build").dependsOn(packForXcode)
Step 4: Implement Expect/Actual Wrappers
- Common Source Set (
commonMain):
Create anHtmlParser.ktfile with the platform-agnostic declaration:
expect class HtmlParser { fun getDocumentTitle(html: String): String }
- iOS Source Set (
iosMain):
Create the actual implementation that calls SwiftSoup via Kotlin-Swift interop:
import SwiftSoup actual class HtmlParser { actual fun getDocumentTitle(html: String): String { return try { val doc = SwiftSoup.parse(html) doc.title() } catch (e: Exception) { "Failed to parse title: ${e.localizedDescription}" } } }
- Android Source Set (
androidMain):
Implement the same interface using Jsoup:
import org.jsoup.Jsoup actual class HtmlParser { actual fun getDocumentTitle(html: String): String { val doc = Jsoup.parse(html) return doc.title() } }
How to Verify
- Sync your Gradle project. The CocoaPods plugin will generate a
Podfileand fetch SwiftSoup automatically. - For iOS: Open your Xcode project, and you'll see SwiftSoup listed in the Pods. You can call the
HtmlParserfrom your shared Kotlin code in both Android and iOS targets. - Test the parsing functionality in both platforms to confirm the libraries are working as expected.
内容的提问来源于stack exchange,提问作者Goran Horia Mihail

