You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Compose多平台桌面项目动态加载Jar遇MissingResourceException问题

Compose Multiplatform桌面端动态加载Jar资源缺失问题解决

核心原因

Compose Resources桌面端默认使用调用类的ClassLoader加载资源,但动态加载的Jar使用自定义URLClassLoader,默认的ResourceReader并未使用这个加载器查找Jar内的composeResources目录,导致资源路径匹配但无法读取。

具体解决步骤

1. 自定义适配动态ClassLoader的ResourceReader

在主项目或功能模块中添加自定义ResourceReader,让它能使用动态加载的ClassLoader读取资源:

import org.jetbrains.compose.resources.ResourceReader
import java.io.InputStream

class DynamicResourceReader(private val classLoader: ClassLoader) : ResourceReader {
    override fun getResourceAsStream(path: String): InputStream? {
        // 直接使用传入的ClassLoader查找资源
        return classLoader.getResourceAsStream(path)
    }
}

2. 动态加载Jar时替换全局ResourceReader

修改动态加载代码,在实例化PluginApp后,替换Compose的全局ResourceReader为自定义实现,传入对应的URLClassLoader:

val url = File(pluginJarPath).toURI().toURL()
val classLoader = URLClassLoader(arrayOf(url), this.javaClass.classLoader)
return try {
    val pluginClass = classLoader.loadClass("com.sample.feature.ComposeApp")
    // 替换全局ResourceReader,让Compose使用动态加载的ClassLoader读取资源
    org.jetbrains.compose.resources.ResourceReader_desktopKt.setPlatformResourceReader(
        DynamicResourceReader(classLoader)
    )
    pluginClass.getDeclaredConstructor().newInstance() as PluginApp
} catch (e: Exception) {
    e.printStackTrace()
    null
}

注:如果需要加载多个插件,需在切换插件时重新设置对应插件的ResourceReader,保证资源隔离。

3. 确保Jar打包完整包含资源

检查Jar打包任务,明确包含composeResources目录(避免资源遗漏):

val jarVersion = 1.0.0
tasks.register<Jar>("jars") {
    archiveBaseName.set("feature")
    archiveVersion.set(jarVersion)
    manifest {
        attributes["Implementation-Title"] = "Feature Plugin App"
        attributes["Implementation-Version"] = jarVersion
    }
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    // 包含jvmMain的所有输出(类文件+资源文件)
    from(sourceSets["jvmMain"].output)
    // 显式确认composeResources目录被打包
    from(sourceSets["jvmMain"].resources) {
        include("composeResources/**")
    }
}

4. 可选:插件卸载时恢复原有ResourceReader

如果应用支持插件卸载,记得恢复原来的ResourceReader:

// 加载插件前保存原有ResourceReader
val originalReader = org.jetbrains.compose.resources.ResourceReader_desktopKt.getPlatformResourceReader()

// 加载插件时替换为自定义Reader
// ...

// 卸载插件时恢复原有Reader
org.jetbrains.compose.resources.ResourceReader_desktopKt.setPlatformResourceReader(originalReader)

验证

完成上述修改后,重新打包功能模块Jar并动态加载,导航到功能模块页面即可正常读取资源,不再抛出MissingResourceException。

内容的提问来源于stack exchange,提问作者Alex Shapkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 13:43:11