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

如何阻止宿主应用直接依赖多模块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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:52:40