diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 23ee9808e2..005901c549 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -114,6 +114,15 @@ jobs: - build-jvm-linux uses: ./.github/workflows/docs-jvm.yml + ################# + # KMP + + test-kmp: + needs: + - build-jvm-linux + - build-jvm-darwin + uses: ./.github/workflows/test-kmp.yml + ################# # iOS/Swift diff --git a/.github/workflows/test-kmp.yml b/.github/workflows/test-kmp.yml new file mode 100644 index 0000000000..21bae55a80 --- /dev/null +++ b/.github/workflows/test-kmp.yml @@ -0,0 +1,49 @@ +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}-test-kmp-jvm" + cancel-in-progress: true + +on: + workflow_call: + workflow_dispatch: + +env: + RELEASE: 1 + +jobs: + test-jvm: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + - name: set up jdk 17 + uses: actions/setup-java@v5 + with: + java-version: "17" + distribution: "adopt" + - name: gradle setup + uses: gradle/actions/setup-gradle@v5 + - name: validate gradle wrapper + uses: gradle/actions/wrapper-validation@v5 + + - name: download linux library + uses: ./.github/actions/make/jvm + with: + gh-token: ${{ secrets.GITHUB_TOKEN }} + + # The specific jvm action uses `uname -s` to determine which `jvm` make rule to call. + # Because this workflow runs on ubuntu, we're using the generic action + - name: download aarch64 apple darwin artifact + uses: ./.github/actions/make + with: + key: jvm-darwin + make-rule: jvm-darwin + target-path: target/aarch64-apple-darwin/release/libcore_crypto_ffi.dylib + gh-token: ${{ secrets.GITHUB_TOKEN }} + + - name: build and test kmp package + uses: ./.github/actions/make + with: + key: kmp-jvm-test + make-rule: kmp-jvm-test + always-run: ${{ github.event_name == 'workflow_dispatch' || github.ref_name == 'main' }} + gh-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index 51017638b1..0e4cd32605 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,15 @@ RUST_SOURCES := $(WORKSPACE_CARGO_FILES) $(CRATE_MANIFESTS) $(RUST_RS_FILES) hash=$$(sha256sum $($*-deps) | sha256sum | awk '{print $$1}'); \ echo "$$hash" +#------------------------------------------------------------------------------- +# Kotlin file-based heuristics +#------------------------------------------------------------------------------- + +KT_WRAPPER = ./crypto-ffi/bindings/shared/src/commonMain/kotlin +KT_TESTS = ./crypto-ffi/bindings/shared/src/commonTest +KT_INTEROP = ./interop/src/clients/android-interop/src/main/java +KT_FILES := $(shell find $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP) -type f -name '*.kt') + #------------------------------------------------------------------------------- # Build FFI artifacts #------------------------------------------------------------------------------- @@ -436,6 +445,17 @@ $(STAMPS)/jvm-test: $(jvm-test-deps) ./gradlew jvm:test --rerun $(TOUCH_STAMP) +#------------------------------------------------------------------------------- +# KMP (Kotlin Multiplatform) builds +#------------------------------------------------------------------------------- + +kmp-jvm-test-deps := $(KT_FILES) + +$(STAMPS)/kmp-jvm-test: $(kmp-jvm-test-deps) + cd crypto-ffi/bindings && \ + ./gradlew kmp:jvmTest --rerun + $(TOUCH_STAMP) + #------------------------------------------------------------------------------- # TypeScript / JS tasks #------------------------------------------------------------------------------- @@ -592,7 +612,7 @@ $(STAMPS)/docs-rust-wasm: $(RUST_SOURCES) docs-rust-wasm: $(STAMPS)/docs-rust-wasm ## Generate Rust docs for wasm32-unknown-unknown # Kotlin docs -KOTLIN_SOURCES := $(shell find crypto-ffi/bindings/jvm/src/main/kotlin \ +KOTLIN_SOURCES := $(shell find crypto-ffi/bindings/shared/src/commonMain/kotlin \ -type f -name '*.kt' 2>/dev/null | LC_ALL=C sort) DOCS_KOTLIN := target/kotlin/doc/html/index.html $(DOCS_KOTLIN): $(JVM_LIB) $(KOTLIN_SOURCES) @@ -699,11 +719,6 @@ swift-check: $(STAMPS)/swift-check ## Lint Swift files via swift-format and swif # Kotlin -KT_WRAPPER = ./crypto-ffi/bindings/jvm/src/main/kotlin -KT_TESTS = ./crypto-ffi/bindings/jvm/src/test -KT_INTEROP = ./interop/src/clients/android-interop/src/main/java -KT_FILES := $(shell find $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP) -type f -name '*.kt') - $(STAMPS)/kotlin-fmt: $(KT_FILES) ktlint --format $(KT_WRAPPER) $(KT_TESTS) $(KT_INTEROP) $(TOUCH_STAMP) @@ -746,9 +761,10 @@ check: rust-check swift-check kotlin-check ts-check ## Run all linters # Lazy targets #------------------------------------------------------------------------------- -LAZY_TARGETS := jvm-test ts-test android-test ios-test interop-test +LAZY_TARGETS := jvm-test kmp-jvm-test ts-test android-test ios-test interop-test ts-test: ## Run TypeScript wrapper tests via wdio and bun. Optionally pass TEST= to filter by test name. +kmp-jvm-test: ## Run Kotlin multi-platform tests on JVM jvm-test: ## Run Kotlin tests on JVM android-test: ## Run Kotlin tests on Android ios-test: ## Run Swift tests on iOS (macOS only) diff --git a/crypto-ffi/bindings/android/build.gradle.kts b/crypto-ffi/bindings/android/build.gradle.kts index f359a2d125..a19cdcf155 100644 --- a/crypto-ffi/bindings/android/build.gradle.kts +++ b/crypto-ffi/bindings/android/build.gradle.kts @@ -6,7 +6,8 @@ plugins { id("com.vanniktech.maven.publish.base") } -val jvmSources = projectDir.resolve("../jvm/src") +val sharedSources = projectDir.resolve("../shared/src/commonMain") +val sharedTestSources = projectDir.resolve("../shared/src/commonTest") val dokkaHtmlJar = tasks.register("dokkaHtmlJar") { dependsOn(tasks.dokkaGeneratePublicationHtml) @@ -87,12 +88,12 @@ android { main { kotlin { srcDir(projectDir.resolve("src/main/uniffi")) - srcDir(jvmSources.resolve("main/kotlin")) + srcDir(sharedSources.resolve("kotlin")) } } androidTest { kotlin { - srcDir(jvmSources.resolve("test")) + srcDir(sharedTestSources.resolve("kotlin")) } } } diff --git a/crypto-ffi/bindings/gradle/libs.versions.toml b/crypto-ffi/bindings/gradle/libs.versions.toml index 4e34270a17..76995cb819 100644 --- a/crypto-ffi/bindings/gradle/libs.versions.toml +++ b/crypto-ffi/bindings/gradle/libs.versions.toml @@ -15,12 +15,17 @@ kotlin-gradle = "1.9.21" dokka = "2.0.0" detekt = "1.23.8" agp = "8.12.3" +gobley = "0.3.7" [plugins] android-library = { id = "com.android.library", version.ref = "agp" } vanniktech-publish = { id = "com.vanniktech.maven.publish", version.ref = "vanniktech-publish" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +gobley-cargo = { id = "dev.gobley.cargo", version.ref = "gobley" } +gobley-uniffi = { id = "dev.gobley.uniffi", version.ref = "gobley" } +gobley-rust = { id = "dev.gobley.rust", version.ref = "gobley" } +kotlin-atomicfu = { id = "org.jetbrains.kotlin.plugin.atomicfu", version.ref = "kotlin" } [libraries] coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version.ref = "coroutines" } diff --git a/crypto-ffi/bindings/jvm/build.gradle.kts b/crypto-ffi/bindings/jvm/build.gradle.kts index 181b1d56e3..cb2f2a5759 100644 --- a/crypto-ffi/bindings/jvm/build.gradle.kts +++ b/crypto-ffi/bindings/jvm/build.gradle.kts @@ -14,6 +14,9 @@ kotlin { jvmToolchain(17) } +val sharedSources = projectDir.resolve("../shared/src/commonMain") +val sharedTestSources = projectDir.resolve("../shared/src/commonTest") + dependencies { implementation(platform(kotlin("bom"))) implementation(platform(libs.coroutines.bom)) @@ -61,13 +64,18 @@ tasks.named("compileKotlin") { sourceSets { main { kotlin { - srcDir(projectDir.resolve("src/main/kotlin")) + srcDir(sharedSources.resolve("kotlin")) srcDir(projectDir.resolve("src/main/uniffi")) } resources { srcDirs(ffiLibsBase.resolve(buildType)) } } + test { + kotlin { + srcDir(sharedTestSources.resolve("kotlin")) + } + } } // Allows skipping signing jars published to 'MavenLocal' repository diff --git a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/ByteUtils.kt b/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/ByteUtils.kt deleted file mode 100644 index 8f072e6fdf..0000000000 --- a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/ByteUtils.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.wire.crypto - -internal fun String.toByteArray() = encodeToByteArray() - -internal fun ByteArray.toHex(): String = joinToString(separator = "") { b -> "%02x".format(b) } diff --git a/crypto-ffi/bindings/kmp/build.gradle.kts b/crypto-ffi/bindings/kmp/build.gradle.kts new file mode 100644 index 0000000000..9e61debce0 --- /dev/null +++ b/crypto-ffi/bindings/kmp/build.gradle.kts @@ -0,0 +1,183 @@ +import gobley.gradle.GobleyHost +import gobley.gradle.cargo.dsl.* +import org.gradle.api.tasks.bundling.Jar + +plugins { + kotlin("multiplatform") + id("com.android.library") + alias(libs.plugins.gobley.cargo) + alias(libs.plugins.gobley.uniffi) + id("com.vanniktech.maven.publish.base") + alias(libs.plugins.kotlin.atomicfu) +} + +val dokkaHtmlJar = tasks.register("dokkaHtmlJar") { + dependsOn(tasks.dokkaGeneratePublicationHtml) + from(tasks.dokkaGeneratePublicationHtml.flatMap { it.outputDirectory }) + archiveClassifier.set("html-docs") +} + +kotlin { + jvmToolchain(17) + + // Android target + androidTarget { + publishLibraryVariants("release") + } + + // JVM target + jvm() + + // iOS targets + iosArm64() + iosSimulatorArm64() + + // macOS ARM64 target + macosArm64() + + sourceSets { + val commonMain by getting { + sourceSets { + kotlin.srcDir("../shared/src/commonMain/kotlin") + } + dependencies { + implementation(libs.coroutines.core) + } + } + + val commonTest by getting { + sourceSets { + kotlin.srcDir("../shared/src/commonTest/kotlin") + } + dependencies { + implementation(kotlin("test")) + implementation(libs.coroutines.test) + } + } + + val jvmMain by getting { + dependencies { + implementation(libs.jna) + } + } + + val jvmTest by getting { + dependencies { + implementation(libs.assertj.core) + } + } + + val androidMain by getting { + dependencies { + implementation("${libs.jna.get()}@aar") + implementation("androidx.annotation:annotation:1.9.1") + } + } + + val androidInstrumentedTest by getting { + dependencies { + implementation(libs.android.junit) + implementation(libs.espresso) + implementation(libs.assertj.core) + } + } + + // Native targets share sources + val nativeMain by creating { + dependsOn(commonMain) + } + + val nativeTest by creating { + dependsOn(commonTest) + } + + val iosArm64Main by getting { + dependsOn(nativeMain) + } + + val iosArm64Test by getting { + dependsOn(nativeTest) + } + + val iosSimulatorArm64Main by getting { + dependsOn(nativeMain) + } + + val iosSimulatorArm64Test by getting { + dependsOn(nativeTest) + } + + val macosArm64Main by getting { + dependsOn(nativeMain) + } + + val macosArm64Test by getting { + dependsOn(nativeTest) + } + } +} + +android { + namespace = "com.wire.crypto" + compileSdk = libs.versions.sdk.compile.get().toInt() + + defaultConfig { + minSdk = libs.versions.sdk.min.get().toInt() + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + ndk { + abiFilters += setOf("arm64-v8a", "armeabi-v7a", "x86_64") + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +cargo { + // Point to the crypto-ffi crate directory + packageDirectory = layout.projectDirectory.dir("../..") + + // Only build JVM native libraries for the current host platform + // This disables cross-compilation for other JVM targets (e.g., Linux ARM64 on macOS) + builds.jvm { + embedRustLibrary = (rustTarget == GobleyHost.current.rustTarget) + } +} + +// Configure iOS build tasks with the required environment +afterEvaluate { + tasks.matching { it.name.contains("cargoBuildIos") }.configureEach { + // Set environment via the task's additionalEnvironment if available + if (this is gobley.gradle.cargo.tasks.CargoBuildTask) { + val target = if (name.contains("Simulator")) { + "IPHONESIMULATOR_DEPLOYMENT_TARGET" + } else { + "IPHONEOS_DEPLOYMENT_TARGET" + } + additionalEnvironment.put(target, "16.0") + } + } +} + +uniffi { + generateFromLibrary { + namespace = "core_crypto_ffi" + packageName = "com.wire.crypto" + } +} + +mavenPublishing { + publishToMavenCentral(automaticRelease = true) + pomFromGradleProperties() + signAllPublications() +} + +// Allows skipping signing jars published to 'MavenLocal' repository +tasks.withType().configureEach { + if (System.getenv("CI") == null) { + enabled = false + } +} diff --git a/crypto-ffi/bindings/kmp/src/jvmTest/resources/db-v10002003.sqlite b/crypto-ffi/bindings/kmp/src/jvmTest/resources/db-v10002003.sqlite new file mode 100644 index 0000000000..bd031d5d0f Binary files /dev/null and b/crypto-ffi/bindings/kmp/src/jvmTest/resources/db-v10002003.sqlite differ diff --git a/crypto-ffi/bindings/settings.gradle.kts b/crypto-ffi/bindings/settings.gradle.kts index 45d9cfc660..b802589e8d 100644 --- a/crypto-ffi/bindings/settings.gradle.kts +++ b/crypto-ffi/bindings/settings.gradle.kts @@ -7,4 +7,4 @@ pluginManagement { } } -include(":jvm", ":android") +include(":shared", ":jvm", ":android", ":kmp") diff --git a/crypto-ffi/bindings/shared/build.gradle.kts b/crypto-ffi/bindings/shared/build.gradle.kts new file mode 100644 index 0000000000..6932f5217d --- /dev/null +++ b/crypto-ffi/bindings/shared/build.gradle.kts @@ -0,0 +1,26 @@ +// This module holds shared Kotlin source files used by both JVM and Android modules. +// The sources are included directly by those modules rather than compiled as a separate library, +// because they depend on Uniffi-generated types that are platform-specific. + +plugins { + kotlin("multiplatform") +} + +kotlin { + jvmToolchain(17) + + jvm() + + sourceSets { + commonMain { + dependencies { + implementation(kotlin("stdlib")) + } + } + commonTest { + dependencies { + implementation(kotlin("stdlib")) + } + } + } +} diff --git a/crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/ByteUtils.kt b/crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/ByteUtils.kt new file mode 100644 index 0000000000..7010ef599f --- /dev/null +++ b/crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/ByteUtils.kt @@ -0,0 +1,7 @@ +package com.wire.crypto + +internal fun String.toByteArray() = encodeToByteArray() + +// this opt-in can be removed once the project updates to Kotlin 2.2 or higher +@OptIn(ExperimentalStdlibApi::class) +internal fun ByteArray.toHex(): String = toHexString() diff --git a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt b/crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/CoreCrypto.kt similarity index 100% rename from crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/CoreCrypto.kt rename to crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/CoreCrypto.kt diff --git a/crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/MlsModel.kt b/crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/MlsModel.kt similarity index 100% rename from crypto-ffi/bindings/jvm/src/main/kotlin/com/wire/crypto/MlsModel.kt rename to crypto-ffi/bindings/shared/src/commonMain/kotlin/com/wire/crypto/MlsModel.kt diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/E2EITest.kt b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/E2EITest.kt similarity index 99% rename from crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/E2EITest.kt rename to crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/E2EITest.kt index 5993ab51d8..317125fce3 100644 --- a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/E2EITest.kt +++ b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/E2EITest.kt @@ -239,7 +239,7 @@ internal class E2EITest : HasMockDeliveryService() { val aliceKp = alice.transaction { ctx -> ctx.clientKeypackagesShort(1u).first() } bob.transaction { ctx -> ctx.addClientsToConversation(id, listOf(aliceKp)) } - val welcome = HasMockDeliveryService.mockDeliveryService.getLatestWelcome() + val welcome = mockDeliveryService.getLatestWelcome() val groupId = alice.transaction { ctx -> ctx.processWelcomeMessage(welcome).id } assertThat(alice.transaction { ctx -> ctx.e2eiConversationState(groupId) }).isEqualTo(E2eiConversationState.NOT_ENABLED) diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/GeneralTest.kt b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/GeneralTest.kt similarity index 99% rename from crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/GeneralTest.kt rename to crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/GeneralTest.kt index 12a4ec6d74..f395bac9f5 100644 --- a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/GeneralTest.kt +++ b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/GeneralTest.kt @@ -6,7 +6,6 @@ import kotlinx.coroutines.test.runTest import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import testutils.MockMlsTransportSuccessProvider import testutils.genDatabaseKey -import java.nio.file.Files import java.nio.file.Path import kotlin.io.path.* import kotlin.test.* diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/MLSTest.kt similarity index 99% rename from crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt rename to crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/MLSTest.kt index 912afeef85..551b553201 100644 --- a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/MLSTest.kt +++ b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/MLSTest.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.test.runTest import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat import org.assertj.core.api.AssertionsForInterfaceTypes.assertThatNoException import testutils.* -import java.nio.file.Files +import kotlin.collections.toList import kotlin.test.* import kotlin.time.Duration.Companion.milliseconds diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/ProteusClientTest.kt b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/ProteusClientTest.kt similarity index 100% rename from crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/ProteusClientTest.kt rename to crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/ProteusClientTest.kt diff --git a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/testutils/TestUtils.kt b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/testutils/TestUtils.kt similarity index 96% rename from crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/testutils/TestUtils.kt rename to crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/testutils/TestUtils.kt index a96500705f..f826efb617 100644 --- a/crypto-ffi/bindings/jvm/src/test/kotlin/com/wire/crypto/testutils/TestUtils.kt +++ b/crypto-ffi/bindings/shared/src/commonTest/kotlin/com/wire/crypto/testutils/TestUtils.kt @@ -6,12 +6,14 @@ import com.wire.crypto.* import kotlinx.coroutines.runBlocking import java.nio.ByteBuffer import java.nio.file.Files +import java.security.SecureRandom import java.util.UUID +import kotlin.random.Random import kotlin.test.* fun genDatabaseKey(): DatabaseKey { val bytes = ByteArray(32) - val random = java.security.SecureRandom() + val random = SecureRandom() random.nextBytes(bytes) return DatabaseKey(bytes) } @@ -125,7 +127,7 @@ fun initCc(_instance: HasMockDeliveryService): CoreCrypto = runBlocking { fun randomIdentifier(n: Int = 12): String { val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') return (1..n) - .map { kotlin.random.Random.nextInt(0, charPool.size).let { charPool[it] } } + .map { Random.nextInt(0, charPool.size).let { charPool[it] } } .joinToString("") } diff --git a/interop/src/clients/android-interop/src/main/java/com/wire/androidinterop/MainActivity.kt b/interop/src/clients/android-interop/src/main/java/com/wire/androidinterop/MainActivity.kt index 992923140e..e2a26cccdd 100644 --- a/interop/src/clients/android-interop/src/main/java/com/wire/androidinterop/MainActivity.kt +++ b/interop/src/clients/android-interop/src/main/java/com/wire/androidinterop/MainActivity.kt @@ -1,12 +1,12 @@ package com.wire.androidinterop +import android.app.Activity import android.content.Intent import android.os.Bundle -import androidx.activity.ComponentActivity import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.Json -class MainActivity : ComponentActivity() { +class MainActivity : Activity() { val actionHandler = runBlocking { InteropActionHandler(InteropActionHandler.defaultCoreCryptoClient()) } diff --git a/interop/src/clients/gradle/libs.versions.toml b/interop/src/clients/gradle/libs.versions.toml index c37561f064..1d89160288 100644 --- a/interop/src/clients/gradle/libs.versions.toml +++ b/interop/src/clients/gradle/libs.versions.toml @@ -1,10 +1,10 @@ [versions] -kotlin = "2.3.0" +kotlin = "2.0.21" coroutines = "1.10.2" android-tools = "8.12.3" kotlin-gradle = "1.9.21" agp = "8.12.3" -ktx-serialization = "1.9.0" +ktx-serialization = "1.8.0" activity = "1.12.2" [plugins] diff --git a/interop/src/clients/gradle/wrapper/gradle-wrapper.jar b/interop/src/clients/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75..1b33c55baa 100644 Binary files a/interop/src/clients/gradle/wrapper/gradle-wrapper.jar and b/interop/src/clients/gradle/wrapper/gradle-wrapper.jar differ diff --git a/interop/src/clients/gradle/wrapper/gradle-wrapper.properties b/interop/src/clients/gradle/wrapper/gradle-wrapper.properties index 2a84e188b8..d4081da476 100644 --- a/interop/src/clients/gradle/wrapper/gradle-wrapper.properties +++ b/interop/src/clients/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/interop/src/clients/gradlew b/interop/src/clients/gradlew index ef07e0162b..23d15a9367 100755 --- a/interop/src/clients/gradlew +++ b/interop/src/clients/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.