Skip to content

Instantly share code, notes, and snippets.

@Ribesg
Last active June 20, 2022 15:00
Show Gist options
  • Save Ribesg/95a172ceb2177d74cf5b15993d40092e to your computer and use it in GitHub Desktop.
Save Ribesg/95a172ceb2177d74cf5b15993d40092e to your computer and use it in GitHub Desktop.
How to use an iOS Framework in a Kotlin MPP library published to Maven

This gist demonstrates how to build a Kotlin MPP library so that the iOS sourceSet depends on and uses an iOS Framework as a dependency.

Key ideas:

  • We use Carthage to retrieve/build the iOS Framework.
  • We use cinterop to create bindings allowing us to use the iOS Framework from Kotlin
  • We build and publish the library using ./gradlew publishToMavenLocal
  • We build and publish klib artifacts for both the arm64 and x86_64 architectures, you can easily add arm32 if you need.
  • Note that the publish process also publishes a cinterop klib artifact, allowing dependents to also know about the iOS Framework headers.

You can find a gist explaining how to use such library in an iOS app here.

More notes:

  • The .def file's name for this gist contains its path with / replaced with -. You can't have /s in a gist file name!
  • I have no idea what I'm doing in this .def file, but it works. Half the entries are probably useless.
  • src/iosSimMain is a symbolic link to src/iosMain
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
group = "com.example.lib"
version = "1.2.3"
repositories {
google()
jcenter()
}
plugins {
id("maven-publish")
id("com.android.library") version "3.2.1"
id("org.jetbrains.kotlin.multiplatform") version "1.3.21"
}
android {
compileSdkVersion(28)
defaultConfig {
minSdkVersion(16)
targetSdkVersion(28)
}
sourceSets {
getByName("main") {
setRoot("src/androidMain")
}
getByName("test") {
setRoot("src/androidTest")
}
}
lintOptions {
isAbortOnError = false
}
}
kotlin {
data class IosTarget(val name: String, val preset: String, val id: String)
val iosTargets = listOf(
IosTarget("ios", "iosArm64", "ios-arm64"),
IosTarget("iosSim", "iosX64", "ios-x64")
)
android {
publishAllLibraryVariants()
}
for ((targetName, presetName, id) in iosTargets) {
targetFromPreset(presets.getByName<KotlinNativeTargetPreset>(presetName), targetName) {
compilations {
getByName("main") {
val carthageBuildDir = "$projectDir/Carthage/Build/iOS"
cinterops(Action {
val bugsnag by creating {
defFile("src/iosMain/cinterop/bugsnag.def")
includeDirs.allHeaders("$carthageBuildDir/Bugsnag.framework/Headers")
}
})
}
}
mavenPublication {
artifactId = "${project.name}-$id"
}
}
}
sourceSets {
getByName("commonMain") {
dependencies {
implementation(kotlin("stdlib-common"))
}
}
getByName("androidMain") {
dependencies {
implementation(kotlin("stdlib"))
implementation(kotlin("reflect"))
implementation("com.bugsnag:bugsnag-android:4.11.0")
}
}
}
}
// Create Carthage tasks
listOf("bootstrap", "update").forEach { type ->
task<Exec>("carthage${type.capitalize()}") {
group = "carthage"
executable = "carthage"
args(
type,
"--platform", "iOS",
"--no-use-binaries", // Provided binaries are sometimes problematic, remove this to speedup process
"--cache-builds"
)
}
}
// Make CInterop tasks depend on Carthage
tasks.withType<CInteropProcess> {
dependsOn("carthageBootstrap")
}
// Delete build directory on clean
tasks.named<Delete>("clean") {
delete(buildDir)
}
// Temporary workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations.create("compileClasspath")
github "bugsnag/bugsnag-cocoa" ~> 5.0
rootProject.name = "my-mpp-library"
enableFeaturePreview("GRADLE_METADATA")
pluginManagement {
repositories {
google()
gradlePluginPortal()
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.android.library") {
useModule("com.android.tools.build:gradle:${requested.version}")
}
}
}
}
depends = Foundation
package = framework.Bugsnag
language = Objective-C
headers = Bugsnag.h
headersFilter = **
compilerOpts = -framework Bugsnag -fmodules
linkerOpts = -framework Bugsnag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment