From 4a82de7515d19e7612c4fbd591e75b810bd4088c Mon Sep 17 00:00:00 2001 From: BODE090 Date: Thu, 15 May 2025 17:20:43 +0200 Subject: [PATCH] Context: KMP Application installed on Windows Machine -> Crash When a KMP App is installed on a Windows Machine, I usually got this Exception: java.nio.file.FileSystemNotFoundException: Provider "jar" not installed at java.base/java.nio.file.Path.of(Unknown Source) at java.base/java.nio.file.Paths.get(Unknown Source) at com.goterl.resourceloader.ResourceLoader.getFileFromFileSystem(ResourceLoader.java:247) at com.goterl.resourceloader.ResourceLoader.copyToTempDirectory(ResourceLoader.java:88) at com.goterl.resourceloader.SharedLibraryLoader.load(SharedLibraryLoader.java:53) at com.goterl.resourceloader.SharedLibraryLoader.load(SharedLibraryLoader.java:47) at com.ionspin.kotlin.crypto.LibsodiumInitializer.loadLibrary(LibsodiumInitializer.kt:30) at com.ionspin.kotlin.crypto.LibsodiumInitializer.initializeWithCallback(LibsodiumInitializer.kt:58) The Plugin was unusable for installed Versions of the Client, but was working during development It seemed that the SharedLibrary Loader was making some trouble loading the Files / Libs correctly when the Application was installed Here's a Native approach and with that, the installed version of the KMP app was working properly --- .../kotlin/crypto/LibsodiumInitializer.kt | 63 +++++++++++-------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/LibsodiumInitializer.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/LibsodiumInitializer.kt index 74f5358c..b83c7de3 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/LibsodiumInitializer.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/com/ionspin/kotlin/crypto/LibsodiumInitializer.kt @@ -1,11 +1,13 @@ package com.ionspin.kotlin.crypto -import com.goterl.resourceloader.SharedLibraryLoader import com.ionspin.kotlin.crypto.GeneralLibsodiumException.Companion.ensureLibsodiumSuccess import com.sun.jna.Native import com.sun.jna.Platform import java.io.File +import java.io.IOException import java.lang.RuntimeException +import java.nio.file.Files +import java.util.UUID /** * Created by Ugljesa Jovanovic (jovanovic.ugljesa@gmail.com) on 02/Aug/2020 @@ -13,37 +15,48 @@ import java.lang.RuntimeException actual object LibsodiumInitializer { private var isPlatformInitialized = false - private fun loadLibrary() : JnaLibsodiumInterface { - val libraryFile = when { - Platform.isMac() -> { - SharedLibraryLoader.get().load("libdynamic-macos.dylib", JnaLibsodiumInterface::class.java) - } - Platform.isLinux() -> { - if (Platform.isARM()) { - SharedLibraryLoader.get().load("libdynamic-linux-arm64-libsodium.so", JnaLibsodiumInterface::class.java) - } else { - SharedLibraryLoader.get() - .load("libdynamic-linux-x86-64-libsodium.so", JnaLibsodiumInterface::class.java) + private fun loadLibrary(): JnaLibsodiumInterface { + try { + val libraryName = when { + Platform.isMac() -> "libdynamic-macos.dylib" + Platform.isLinux() -> { + if (Platform.isARM()) { + "libdynamic-linux-arm64-libsodium.so" + } else { + "libdynamic-linux-x86-64-libsodium.so" + } } + + Platform.isWindows() -> "libdynamic-msvc-x86-64-libsodium.dll" + Platform.isAndroid() -> "" + else -> throw RuntimeException("Unsupported platform") } - Platform.isWindows() -> { - SharedLibraryLoader.get().load("libdynamic-msvc-x86-64-libsodium.dll", JnaLibsodiumInterface::class.java) - } - Platform.isAndroid() -> { - File("irrelevant") - } - else -> throw RuntimeException("Unknown platform") + return if (Platform.isAndroid()) { + Native.load("sodium", JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface + } else { + val libraryPath = extractLibraryPath(libraryName) + Native.load(libraryPath, JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface + } + } catch (e: Exception) { + throw RuntimeException("Failed to load native library: ${e.message}", e) } + } + private fun extractLibraryPath(libraryName: String): String { + try { + val inputStream = LibsodiumInitializer::class.java.classLoader.getResourceAsStream(libraryName) + ?: throw IOException("Library $libraryName not found in resources") - val library = if (Platform.isAndroid()) { - Native.load("sodium", JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface - } else { - Native.load(libraryFile.absolutePath, JnaLibsodiumInterface::class.java) as JnaLibsodiumInterface - } + val tempDir = System.getProperty("java.io.tmpdir") + val tempFile = File(tempDir, "libsodium-${UUID.randomUUID()}-$libraryName") + tempFile.deleteOnExit() - return library + Files.copy(inputStream, tempFile.toPath()) + return tempFile.absolutePath + } catch (e: IOException) { + throw RuntimeException("Failed to extract native library: $libraryName", e) + } }