如何阻止宿主应用直接依赖多模块Android库的子模块?
解决多模块Android库禁止直接依赖子模块的方案
核心思路
通过控制子模块的发布范围、仓库权限,结合Gradle配置与编译期检查,既能保留多模块架构的可维护性,又能阻止宿主应用直接依赖子模块。
1. 隔离子模块的发布仓库
将子模块仅发布到内部私有仓库(如公司内部Nexus/Artifactory),根模块则发布到对外可访问的仓库。宿主应用只能访问对外仓库,自然无法获取子模块制品。
- 子模块的Gradle发布配置示例(build.gradle.kts):
publishing { repositories { maven { url = uri("https://internal.acme.com/repo/internal") credentials { username = System.getenv("INTERNAL_REPO_USER") password = System.getenv("INTERNAL_REPO_PWD") } } } }
根模块从内部仓库拉取子模块依赖,同时发布到对外仓库供宿主使用。
2. 给子模块添加私有标记并构建时拦截
在子模块的POM元数据中添加自定义私有属性,然后在根模块配套的Gradle插件中添加依赖检查逻辑:一旦发现宿主直接依赖标记为私有的子模块,立即终止构建。
- 子模块POM配置:
publishing { publications { create<MavenPublication>("release") { from(components["release"]) pom { properties.set(mapOf("private-sdk-module" to "true")) } } } }
- 自定义Gradle插件的检查逻辑:
project.dependencies.all { if (this is ModuleDependency) { val moduleId = "${group}:${name}" if (moduleId.startsWith("corp.acme:sdk-module") && isPrivateModule(moduleId)) { throw GradleException("禁止直接依赖SDK内部子模块:${moduleId}") } } } // 辅助方法:解析子模块POM判断是否为私有模块 fun isPrivateModule(moduleId: String): Boolean { // 实现从仓库拉取POM并读取private-sdk-module属性的逻辑 }
3. 编译期Lint拦截非法访问
给子模块的所有公开类添加自定义内部注解(如@InternalSdkModule),编写Lint规则扫描宿主代码,一旦发现引用了带该注解的类,直接抛出编译错误。
- 自定义Lint规则示例:
class InternalModuleUsageDetector : Detector(), SourceCodeScanner { override fun getApplicableAnnotations(): List<String> { return listOf("corp.acme.sdk.annotations.InternalSdkModule") } override fun visitAnnotation(context: JavaContext, annotation: UAnnotation, clazz: UClass) { if (isHostAppProject(context.project)) { context.report( issue = ISSUE_INTERNAL_MODULE_USAGE, scope = clazz, location = context.getLocation(clazz), message = "禁止直接使用SDK内部模块的类" ) } } private fun isHostAppProject(project: Project): Boolean { // 判断当前项目是否为宿主应用的逻辑,比如根据groupId或模块类型 return project.group.toString() != "corp.acme" } companion object { val ISSUE_INTERNAL_MODULE_USAGE = Issue.create( id = "InternalModuleUsage", briefDescription = "直接使用了SDK内部模块", explanation = "SDK内部模块仅允许根模块调用,禁止宿主直接使用", category = Category.CORRECTNESS, priority = 9, severity = Severity.ERROR, implementation = Implementation(InternalModuleUsageDetector::class.java, Scope.JAVA_FILE_SCOPE) ) } }
将该Lint规则打包成插件,要求宿主应用必须引入,从编译层面阻断非法访问。
内容的提问来源于stack exchange,提问作者peshkira
相关产品推荐
相关产品推荐

