I'm building a multiplatform library for Android and iOS. My gradle file looks like this:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.4.0'
}
repositories {
mavenCentral()
}
group 'com.example'
version '0.0.1'
apply plugin: 'maven-publish'
kotlin {
jvm()
// This is for iPhone simulator
// Switch here to iosArm64 (or iosArm32) to build library for iPhone device
ios {
binaries {
framework()
}
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib-common')
implementation("com.ionspin.kotlin:bignum:0.2.2")
}
}
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
jvmMain {
dependencies {
implementation("com.ionspin.kotlin:bignum:0.2.2")
}
}
jvmTest {
dependencies {
implementation kotlin('test')
implementation kotlin('test-junit')
}
}
iosMain {
}
iosTest {
}
}
}
configurations {
compileClasspath
}
Im using a third party library and I'm using it like this:
fun test(value: String): Int {
return BigDecimal.parseString(value).toBigInteger().intValue()
}
The problem is when I build the .jar the bignum library isn't included, and when I use the lib in an Android project I get an exception ClassNotFoundException: Didn't find class "com.ionspin.kotlin.bignum.decimal.BigDecimal".
Is there a way to include third party libs in the .jar for Android and .framework for iOS?
JVM
So, the only way I've found to generate a Fat JAR that works like you expect is by adding two custom gradle tasks in project:build.gradle.kts
of your KMP library after applying the java plugin.
plugins {
[...]
id("java")
}
[...]
kotlin {
jvm {
[...]
compilations {
val main = getByName("main")
tasks {
register<Copy>("unzip") {
group = "library"
val targetDir = File(buildDir, "3rd-libs")
project.delete(files(targetDir))
main.compileDependencyFiles.forEach {
println(it)
if (it.path.contains("com.")) {
from(zipTree(it))
into(targetDir)
}
}
}
register<Jar>("fatJar") {
group = "library"
manifest {
attributes["Implementation-Title"] = "Fat Jar"
attributes["Implementation-Version"] = archiveVersion
}
archiveBaseName.set("${project.name}-fat")
val thirdLibsDir = File(buildDir, "3rd-libs")
from(main.output.classesDirs, thirdLibsDir)
with(jar.get() as CopySpec)
}
}
tasks.getByName("fatJar").dependsOn("unzip")
}
}
[...]
}
You then must launch the fatJar
gradle task that generate a .jar file with the 3rd libraries classes extracted from their corresponding jar archives.
You can customize the two custom gradle scripts even more in order to better fit your needs (here I only included dependencies in com.* package).
Then in your Android app app:build.gradle
file you can use it as you did or simply
implementation files('libs/KMLibraryTest001-fat-1.0-SNAPSHOT.jar')
iOS
As you ask also for the iOS part in your title (even if it's a second citizen in the main topic of your question) you need only to use api
instead of implementation
for your 3rd party library along with the export option of the framework.
ios() {
binaries {
framework() {
transitiveExport = true // all libraries
//export(project(":LibA")) // this library project in a transitive way
//export("your 3rd party lib") // this 3rd party lib in a transitive way
}
}
}
And you can find a full reference here.