Skip to content

Commit 156b052

Browse files
committed
Address AS duplicate root path issue and desktop compose library loading
1 parent 6ca475b commit 156b052

File tree

4 files changed

+117
-21
lines changed

4 files changed

+117
-21
lines changed

native/kotlin/example/composeApp/build.gradle.kts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,25 @@ tasks.withType<KotlinJvmCompile>().configureEach {
1818
}
1919
}
2020

21+
// Desktop resources path - separate from integration test resources to avoid IDE conflicts
22+
val desktopResourcesPath = layout.buildDirectory.dir("desktopResources")
23+
24+
// Copy resources needed for desktop app
25+
val copyDesktopAppResources = tasks.register<Copy>("copyDesktopAppResources") {
26+
dependsOn(rootProject.tasks.named("copyDesktopJniLibs"))
27+
dependsOn(rootProject.tasks.named("copyTestCredentials"))
28+
from(rootProject.ext.get("jniLibsPath"))
29+
from(rootProject.ext.get("generatedTestResourcesPath"))
30+
into(desktopResourcesPath)
31+
}
32+
2133
kotlin {
2234
androidTarget()
2335
jvm("desktop")
2436

2537
sourceSets {
2638
val desktopMain by getting {
27-
resources.srcDirs(
28-
listOf(
29-
rootProject.ext.get("jniLibsPath"),
30-
rootProject.ext.get("generatedTestResourcesPath")
31-
)
32-
)
39+
resources.srcDirs(desktopResourcesPath)
3340
}
3441

3542
androidMain.dependencies {
@@ -71,7 +78,6 @@ android {
7178

7279
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
7380
sourceSets["main"].res.srcDirs("src/androidMain/res")
74-
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
7581

7682
defaultConfig {
7783
applicationId = "rs.wordpress.example"
@@ -106,6 +112,11 @@ compose.desktop {
106112
application {
107113
mainClass = "rs.wordpress.example.MainKt"
108114

115+
jvmArgs += listOf(
116+
"-Djna.library.path=.",
117+
"-Djava.library.path=."
118+
)
119+
109120
nativeDistributions {
110121
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
111122
packageName = "rs.wordpress.example"
@@ -114,7 +125,34 @@ compose.desktop {
114125
}
115126
}
116127

128+
// Generate BuildConfig with rust module name
129+
val generateBuildConfig = tasks.register("generateBuildConfig") {
130+
val outputDir = layout.buildDirectory.dir("generated/source/buildConfig")
131+
val rustPrimaryModule = rootProject.ext.get("rustPrimaryModule") as String
132+
133+
outputs.dir(outputDir)
134+
135+
doLast {
136+
val buildConfigFile = outputDir.get().file("rs/wordpress/example/BuildConfig.kt").asFile
137+
buildConfigFile.parentFile.mkdirs()
138+
buildConfigFile.writeText("""
139+
package rs.wordpress.example
140+
141+
object BuildConfig {
142+
const val RUST_PRIMARY_MODULE = "$rustPrimaryModule"
143+
}
144+
""".trimIndent())
145+
}
146+
}
147+
148+
kotlin.sourceSets.getByName("desktopMain") {
149+
kotlin.srcDir(layout.buildDirectory.dir("generated/source/buildConfig"))
150+
}
151+
152+
tasks.named("compileKotlinDesktop").configure {
153+
dependsOn(generateBuildConfig)
154+
}
155+
117156
tasks.named("desktopProcessResources").configure {
118-
dependsOn(rootProject.tasks.named("copyDesktopJniLibs"))
119-
dependsOn(rootProject.tasks.named("copyTestCredentials"))
157+
dependsOn(copyDesktopAppResources)
120158
}

native/kotlin/example/composeApp/src/commonMain/kotlin/rs/wordpress/example/shared/repository/AuthenticationRepository.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package rs.wordpress.example.shared.repository
33
import rs.wordpress.example.shared.domain.AuthenticatedSite
44
import uniffi.wp_api.WpAuthentication
55
import uniffi.wp_api.wpAuthenticationFromUsernameAndPassword
6+
import java.net.URI
67
import java.net.URL
78

89
class AuthenticationRepository(
@@ -14,8 +15,8 @@ class AuthenticationRepository(
1415

1516
init {
1617
addAuthenticatedSite(
17-
URL(localTestSiteUrl),
18-
URL("$localTestSiteUrl/wp-json"),
18+
URI(localTestSiteUrl).toURL(),
19+
URI("$localTestSiteUrl/wp-json").toURL(),
1920
localTestSiteUsername,
2021
localTestSitePassword
2122
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package rs.wordpress.example
2+
3+
import java.io.File
4+
import java.nio.file.Files
5+
6+
object NativeLibraryLoader {
7+
private val tempDir = Files.createTempDirectory("wordpress-rs-libs").toFile().apply {
8+
deleteOnExit()
9+
}
10+
11+
fun loadLibraries() {
12+
// Determine the library name based on the OS
13+
val osName = System.getProperty("os.name").lowercase()
14+
val moduleName = BuildConfig.RUST_PRIMARY_MODULE
15+
val libName = when {
16+
osName.contains("mac") || osName.contains("darwin") -> "lib${moduleName}.dylib"
17+
osName.contains("linux") -> "lib${moduleName}.so"
18+
osName.contains("windows") -> "${moduleName}.dll"
19+
else -> throw UnsupportedOperationException("Unsupported OS: $osName")
20+
}
21+
22+
// Extract the native library from jar
23+
try {
24+
val resourceStream = javaClass.classLoader.getResourceAsStream(libName)
25+
if (resourceStream != null) {
26+
val tempFile = File(tempDir, libName).apply {
27+
deleteOnExit()
28+
}
29+
30+
resourceStream.use { input ->
31+
tempFile.outputStream().use { output ->
32+
input.copyTo(output)
33+
}
34+
}
35+
36+
// Make executable
37+
tempFile.setExecutable(true)
38+
println("Extracted native library: ${tempFile.absolutePath}")
39+
} else {
40+
println("Warning: Could not find $libName in resources")
41+
}
42+
} catch (e: Exception) {
43+
println("Warning: Could not extract $libName: ${e.message}")
44+
}
45+
46+
// Set JNA library path to our temp directory
47+
System.setProperty("jna.library.path", tempDir.absolutePath)
48+
System.setProperty("java.library.path", tempDir.absolutePath)
49+
50+
println("Native library path set to: ${tempDir.absolutePath}")
51+
}
52+
}

native/kotlin/example/composeApp/src/desktopMain/kotlin/rs/wordpress/example/main.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ import org.koin.compose.KoinApplication
66
import rs.wordpress.example.shared.App
77
import rs.wordpress.example.shared.di.commonModules
88

9-
fun main() = application {
10-
Window(
11-
onCloseRequest = ::exitApplication,
12-
title = "WordPressRsExample",
13-
) {
14-
KoinApplication(application = {
15-
modules(commonModules())
16-
}) {
17-
// Authentication is not supported on Desktop
18-
App(authenticationEnabled = false, authenticateSite = {})
9+
fun main() {
10+
// Load native libraries before initializing the app
11+
NativeLibraryLoader.loadLibraries()
12+
13+
application {
14+
Window(
15+
onCloseRequest = ::exitApplication,
16+
title = "WordPressRsExample",
17+
) {
18+
KoinApplication(application = {
19+
modules(commonModules())
20+
}) {
21+
// Authentication is not supported on Desktop
22+
App(authenticationEnabled = false, authenticateSite = {})
23+
}
1924
}
2025
}
2126
}

0 commit comments

Comments
 (0)