Skip to content

Commit 800fd0e

Browse files
committed
fix(audio): support resource: and other URL schemes in GraalVM native images
Res.getUri returns a resource:/ URL inside a native image (there is no jar on disk), which resolveFilePath passed through as a raw path — the native decoder cannot open it and playback failed silently. Treat any non-file URL scheme (jar:, resource:, ...) as an openable stream and extract it to a temp file once, instead of special-casing jar: only. Also bumps nucleus.rodio to 1.0.2: playback callbacks were stripped by native-image because the JNI adapter was an anonymous class.
1 parent 07545e7 commit 800fd0e

2 files changed

Lines changed: 21 additions & 10 deletions

File tree

audioplayer/src/jvmMain/kotlin/io/github/kdroidfilter/composemediaplayer/audio/AudioPlayer.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,27 @@ actual class AudioPlayer actual constructor() {
166166
}
167167

168168
private fun resolveFilePath(url: String): String {
169-
if (url.startsWith("jar:", ignoreCase = true)) return extractToTempFile(url)
170-
if (!url.startsWith("file:", ignoreCase = true)) return url
171-
val uri = runCatching { URI(url) }.getOrNull()
172-
if (uri != null) {
173-
val path = runCatching { Paths.get(uri).toString() }.getOrNull()
174-
if (!path.isNullOrBlank()) return path
175-
val uriPath = uri.path
176-
if (!uriPath.isNullOrBlank()) return uriPath
169+
if (url.startsWith("file:", ignoreCase = true)) {
170+
val uri = runCatching { URI(url) }.getOrNull()
171+
if (uri != null) {
172+
val path = runCatching { Paths.get(uri).toString() }.getOrNull()
173+
if (!path.isNullOrBlank()) return path
174+
val uriPath = uri.path
175+
if (!uriPath.isNullOrBlank()) return uriPath
176+
}
177+
return url.substring(5)
177178
}
178-
return url.substring(5)
179+
// Any other URL scheme is not directly openable by the native decoder:
180+
// `jar:` in packaged JVM apps, `resource:` in GraalVM native images
181+
// (what `Res.getUri` returns there), etc. Extract the stream to a temp
182+
// file once. A Windows drive letter ("C:\...") is not a scheme.
183+
val scheme = url.substringBefore(':', "")
184+
val isScheme =
185+
scheme.length > 1 &&
186+
scheme.first().isLetter() &&
187+
scheme.all { it.isLetterOrDigit() || it == '+' || it == '-' || it == '.' }
188+
if (isScheme) return extractToTempFile(url)
189+
return url
179190
}
180191

181192
/**

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ktlint = "14.2.0"
1818
androidx-lifecycle-runtime-ktx = "2.10.0"
1919
jna = "5.18.1"
2020
platformtoolsDarkmodedetector = "0.7.4"
21-
rodio = "1.0.1"
21+
rodio = "1.0.2"
2222
slf4jSimple = "2.0.17"
2323

2424
# minSdk = 21 failed to compile because the project indirectly depends on the library [androidx.navigationevent:navigationevent-android:1.0.1] which requires minSdk = 23

0 commit comments

Comments
 (0)