Home About Contact
Kotlin , Kotlin Multiplatform , Gradle

Kotlin Multiplatform プロジェクト用のライブラリの作成と利用

以前のポスト Gradle を使ってライブラリプロジェクトを作成して local maven に publish、それをアプリケーションプロジェクトで使う(覚え書き) でつくった names というライブラリを Kotlin Multiplatform 用にする(覚え書き)。

以前に書いたポスト Kotlin Multiplatform 2.0.0 Kotlin/JS でテストを書く、生成したライブラリをHTMLから使用する覚え書き で、Kotlin Multiplatform のテストは書いていた。(完全に忘れいている。) ただ、このポストでは jsTest ではなく jvmTest を書いている、という点はそちらとは異なる。

環境

$ gradle -version

------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------

Build time:   2023-10-04 20:52:13 UTC
Revision:     e9251e572c9bd1d01e503a0dfdf43aedaeecdc3f

Kotlin:       1.9.10
Groovy:       3.0.17
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM:          17.0.12 (Ubuntu 17.0.12+7-Ubuntu-1ubuntu222.04)
OS:           Linux 6.8.0-47-generic amd64

ライブラリを作成

names というポケモン名のリストを返すだけのライブラリをつくります。

$ mkdir names
$ cd names
$ touch build.gradle.kts

build.gradle.kts を記述:

plugins {
    kotlin("multiplatform") version "2.0.0"
    `maven-publish`
}

repositories {
    mavenCentral()
}

publishing {
    publications {
        create<MavenPublication>("maven"){
            group = "org.example"
            version = "0.0.1-SNAPSHOT"
            from(components["kotlin"])
        }
    }
}

kotlin {
    js {
        nodejs()
    }

    jvm {
        withJava()
    }

    sourceSets {
        jvmTest.dependencies {
            implementation(kotlin("test"))
        }
    }
}

ここでは Kotlin/JS のプロジェクトからこの names ライブラリを使うことを想定しています。 一方で、このライブラリプロジェクトでは JavaVM 用のテストを実行するつもりなので、 次のように kotlin セクションに記述しています。

jvm {
    withJava()
}

よくわからないのだが、これを記述しないと

$ ./gradlew test

FAILURE: Build failed with an exception.

* What went wrong:
Task 'test' not found in root project 'names'. Some candidates are: 'jsTest'.

と怒られることになる。

./src/commonMain/kotlin/org/example/Library.kt にコードを書きます。

package org.example

class Library {
    val toNames: ()->List<String> = {
        "pikachu,squirtle,charmander,golduck".split(",")
    }
}

ここでプロジェクトのルートで gradle assemble を実行。 問題なければ、 gradle wrapper しておきましょう。 今後は、 ./gradlew コマンドを使っていきます。

次に、テストを ./src/jvmTest/kotlin/org/example/LibraryTest.kt を書きます。

package org.example

import kotlin.test.Test
import kotlin.test.assertEquals

class LibraryTest {
    @Test fun pokemonNamesTest() {
        val firstPokemonName =  Library().toNames()[0]
        assertEquals("pikachu", firstPokemonName)
    }
}

assertEaulas: https://kotlinlang.org/api/latest/kotlin.test/kotlin.test/assert-equals.html

jvmTest タスクを実行します。

$ ./gradlew jvmTest

src/jvmTest/... 以下に配置したテストを実行するには test タスクではなく jvmTest タスクを実行する必要があります。

固定のポケモン名のリストを返すだけのライブラリですが、これでライブラリはできました。 これを local maven へ publish します。

$ ./gradlew publishToMavenLocal

その後、~/.m2/repository/org/example/ を見ると

$ ls
names  names-js  names-jvm

となっています。(js と jvm のライブラリができている。)

別の Kotlin/Multiplatform プロジェクト からこのライブラリを使う

$ mkdir hello
$ cd hello
$ touch build.gradle.kts

build.gradle.kts を次のように記述します。

plugins {
    kotlin("multiplatform") version "2.0.0"
}

repositories {
    mavenCentral()
    mavenLocal()
}

kotlin {
    js {
        nodejs()
        binaries.library()
    }

    sourceSets {
        commonMain.dependencies {
            implementation("org.example:names:0.0.1-SNAPSHOT")
        }
    }
}

先に作成しておいた names ライブラリを dependencies に記述しておきます。

このライブラリを使うコードを src/jsMain/kotlin/Main.kt に記述。

import org.example.Library

@ExperimentalJsExport
@JsExport
fun sayHelloTo(name: String): String {
    return Library().toNames().filter { it==name }.map { "Hello, ${it}!" }.joinToString("")
}

gradlew コマンドを作成して、ビルドします。

$ gradle wrapper
$ ./gradlew build

Node.js のプロジェクトが ./build/js/ にできているので、そこへ移動して、 main.js を作成。

$ cd build/js
$ touch main.js

main.js は次のように記述します。

// main.js

const hello = require('hello')
console.log(hello)
const greeting = hello.sayHelloTo('pikachu')
console.log(greeting)

実行:

$ node main.js
{ sayHelloTo: [Function: sayHelloTo] }
Hello, pikachu!

できました。