Gradle插件开发:瘦包可用但构建胖包后插件无法被消费项目识别
嘿,我太懂这种前后矛盾的崩溃感了——一开始插件没带依赖报NoClassDefFoundError,好不容易打了Fat Jar,结果连插件本身都找不到了!核心问题出在你的Fat Jar配置破坏了Gradle识别自定义插件的关键机制。
先给你说清楚原因:Gradle能找到my.custom.plugin这个ID,全靠插件Jar里的META-INF/gradle-plugins/my.custom.plugin.properties文件,这个文件里写着插件实现类的全路径。你之前的Jar配置直接把所有依赖Jar解压合并,要么是把自己插件的这个关键文件给覆盖了,要么就是压根没把它正确打包进去。
下面给你两个靠谱的解决方案,优先推荐第一个,毕竟是Gradle官方的路子:
方案1:用官方java-gradle-plugin插件(省心首选)
Gradle专门给自定义插件开发做了java-gradle-plugin插件,它会自动帮你处理插件声明、依赖打包,还能生成正确的元数据,完全不用自己瞎折腾Jar任务。
修改你的plugin/build.gradle:
plugins { id 'java-gradle-plugin' // 如果需要纯正的Fat Jar,再加个shadow插件 id 'com.github.johnrengelman.shadow' version '8.1.1' } // 核心:声明你的插件ID和对应的实现类 gradlePlugin { plugins { customPlugin { id = 'my.custom.plugin' // 替换成你自己插件实现类的全路径,比如com.yourteam.MyPlugin implementationClass = '你的插件实现类全路径' } } } // 配置shadowJar生成Fat Jar,保留插件元数据 shadowJar { archiveBaseName.set("plugin-all") archiveClassifier.set("") // 去掉默认的shadow后缀,方便引用 mergeServiceFiles() // 确保插件的元数据不被覆盖 mergeManifest { attributes 'Implementation-Title': '我的自定义Gradle插件', 'Implementation-Version': project.version } } // 让build任务自动触发shadowJar,构建完直接生成Fat Jar build.dependsOn(shadowJar)
然后在plugin_consumer里,把依赖指向生成的Fat Jar就行:
buildscript { repositories { // 你的仓库配置 } dependencies { classpath fileTree(dir:'../plugin/build/libs', include: ['plugin-all.jar']) } } apply plugin: 'my.custom.plugin'
方案2:修复你原来的Fat Jar配置
要是你不想换插件,那得调整Jar任务,确保自己插件的元数据不被依赖覆盖:
修改plugin/build.gradle的Jar配置:
jar { archiveName = 'plugin.jar' baseName = project.name + '-all' // 先把插件自己的代码和元文件打包进去(这步你之前可能漏了!) from sourceSets.main.output // 再添加依赖,但要排除依赖里的Gradle插件元文件,防止覆盖自己的 from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it).matching { exclude 'META-INF/gradle-plugins/**' exclude 'META-INF/*.properties' // 按需排除,避免冲突 } } } // 遇到重复文件时,优先保留自己的 duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
这里的关键是先打包自己的代码和元文件,再添加依赖,同时排除依赖里可能干扰的META-INF文件,不然依赖里如果有其他Gradle插件,会把你的插件声明给冲掉。
为啥原来的配置会炸?
你之前的Jar任务直接把所有依赖解压合并,要是某个依赖Jar里也有META-INF/gradle-plugins下的文件,就会把你自己的my.custom.plugin.properties给覆盖了,Gradle自然找不到你的插件。另外,你没明确把插件自身的编译输出加进去,搞不好连插件核心代码都没打包进去,可不就找不到嘛!
内容的提问来源于stack exchange,提问作者Ben

