文章目录
需求
android studio项目,app下的build.gradle可以使用compileOnly files('.../jar/framework.jar')引入sdk的framework.jar,这种是固定死的,不同的芯片平台framework.jar是不一样的,需要针对不同的平台引入不同的framework.jar与代码。
分析
在 Android Gradle 插件中,依赖配置是可以基于 Build Variant(构建变体)进行细粒度控制的。当定义了不同的 productFlavors 时,Gradle 会自动生成对应的依赖配置名称,格式为:
实现
同一项目引用不同的jar
假设有两个不同的平台(Flavor):platformA 和 platformB,它们需要分别引用不同路径或不同版本的 framework.jar。
- 配置 build.gradle (Groovy DSL)
在 app/build.gradle 文件中,首先定义好 productFlavors,然后在 dependencies 块中使用自动生成的配置名称。
groovy
android {
// ... 其他配置
flavorDimensions "platform"
productFlavors {
platformA {
dimension "platform"
//applicationIdSuffix ".platformA" //这行可以删除
// 可以定义特定的构建配置字段等
}
platformB {
dimension "platform"
//applicationIdSuffix ".platformB" // 这行可以删除
}
}
}
dependencies {
// 当构建 variant 为 "platformA" (如 platformADebug) 时,引入此 jar
platformACompileOnly files('../jar/platformA/framework.jar')
// 当构建 variant 为 "platformB" (如 platformBDebug) 时,引入此 jar
// 注意:配置名称是 "Flavor名" + "依赖类型首字母大写"
platformBCompileOnly files('../jar/platformB/framework.jar')
}
- 配置名称规则:
如果 Flavor 名叫 xyz,依赖类型是 compileOnly,则配置名为 xyzCompileOnly。
platformA + CompileOnly -> platformACompileOnly
platformB + CompileOnly -> platformBCompileOnly - 配置 build.gradle.kts (Kotlin DSL)
如果你使用的是 Kotlin DSL (build.gradle.kts),语法略有不同,需要使用 getByName 或直接使用生成的扩展属性(取决于 AGP 版本,推荐显式调用):
kotlin
android {
// ...
flavorDimensions += "platform"
productFlavors {
create("platformA") {
dimension = "platform"
//applicationIdSuffix = ".platformA"
}
create("platformB") {
dimension = "platform"
//applicationIdSuffix = ".platformB"
}
}
}
dependencies {
// 针对 platformA
"platformACompileOnly"(files("../jar/platformA/framework.jar"))
// 针对 platformB
"platformBCompileOnly"(files("../jar/platformB/framework.jar"))
}
- 修改build.gradle
build.grale如果只有一种framework.jar时,写法是这样的:
groovy
gradle.projectsEvaluated {
tasks.withType(JavaCompile).tap {
configureEach {
options.compilerArgs.add("-Xbootclasspath/p:$rootProject.rootDir/jar/frameworkA.jar")
}
}
}
现在需要改成:
groovy
// 移除原来的 gradle.projectsEvaluated 块,改用下面这个
android.applicationVariants.all { variant ->
def flavorName = null
variant.productFlavors.each { flavor ->
if (flavor.dimension == "platform") { // 替换为维度名,上面定的是platform
flavorName = flavor.name
}
}
if (flavorName) {
def jarPath = null
if (flavorName == "platformA") {
jarPath = "$rootProject.rootDir/jar/platformA/framework.jar"
} else if (flavorName == "platformB") {
jarPath = "$rootProject.rootDir/jar/platformB/framework.jar"
}
if (jarPath) {
variant.javaCompileProvider.configure { javaCompile ->
javaCompile.options.compilerArgs.add("-Xbootclasspath/p:$jarPath")
println "Configured bootclasspath for ${variant.name}: $jarPath"
}
}
}
}
- 验证方法
配置完成后,你可以通过以下方式验证:
在 Android Studio 右侧的 Gradle 面板中,展开 app -> Tasks -> android。
你会看到类似 assemblePlatformADebug 和 assemblePlatformBDebug 的任务。
分别运行这两个任务,会对应不同的平台framework.jar。
同一项目调用不同的java
上面已经介绍了如何在同一项目中引入不同平台的framework.jar,现在有了新的需求:
不同平台如果要运行不同的java代码怎么处理,比如平台A有函数funA但是平台B却没有,在平台A中又要调用这个funA,在平台B上编译就会报没有这个函数。
- 目录结构规划
假设两个 Flavor 分别是 platformA 和 platformB。需要调整 src 目录结构如下:
text
app/
├── src/
│ ├── main/ <-- 【公共代码】所有平台共用的代码
│ │ ├── java/
│ │ │ └── com/example/app/
│ │ │ ├── MainActivity.java
│ │ │ └── CommonUtil.java
│ │ └── AndroidManifest.xml
│ │
│ ├── platformA/ <-- 【平台 A 独有代码】只有 build platformA 时才会编译这里
│ │ └── java/
│ │ └── com/example/app/
│ │ └── PlatformSpecific.java (包含 funA)
│ │
│ └── platformB/ <-- 【平台 B 独有代码】只有 build platformB 时才会编译这里
│ └── java/
│ └── com/example/app/
│ └── PlatformSpecific.java (可以是空实现,或者根本没有这个文件)
- 代码实现细节
场景描述:
funA() 只在平台 A 存在。
主逻辑需要调用 funA(),
文件:src/platformA/java/com/example/app/PlatformServiceImpl.java
java
//PlatformSpecific.java
class PlatformSpecific {
public static funA() {
// 具体实现....
}
}
但在平台 B 上不能调用(或者调用一个空操作)。
文件:src/platformB/java/com/example/app/PlatformServiceImpl.java
java
//PlatformSpecific.java
class PlatformSpecific {
public static funA() {
// 置为空,不实现
}
}
调用,在需要调用的地方调用funcA函数,
假设是文件:src/main/java/com/example/app/MainActivity.java
java
PlatformSpecific.funcA();
- 核心原理
- 源码集合并:当执行 assemblePlatformADebug 时,Gradle 的 Java 编译任务会将 src/main/java 和 src/platformA/java 下的所有 .java 文件放在一起编译。此时,它看得到 PlatformServiceImpl (A 版)。
- 隔离性:当执行 assemblePlatformBDebug 时,Gradle 只会合并 src/main/java 和 src/platformB/java。src/platformA/java 下的文件完全不可见,就像不存在一样。
- 编译通过:因为 main 代码依赖的是 PlatformServiceImpl 这个类名,而这个类名在两个 Flavor 的源集中都存在(只是实现不同),所以无论编译哪个 Flavor,编译器都能找到类的定义,不会报 "Cannot resolve symbol" 错误。
- 验证
-
使用Android Studio编译
打开View--Build Variants, 要编译platformA的debug版本就选择platformADebug, 要编译platformB的Release版本就选择platformBRelease,

然后顶部栏点击Build--Make Project就开始编译了:

-
使用gradlew指令编译
bash
# 构建 platformA 的 Debug 包
./gradlew :app:assemblePlatformADebug
# 构建 platformB 的 Debug 包
./gradlew :app:assemblePlatformBDebug
通用公式
bash
./gradlew :app:assemble<FlavorName首字母大写><BuildType首字母大写>

编译完成后,APK 文件通常位于:
app/build/outputs/apk//release/
例如平台 A 的包可能在:
app/build/outputs/apk/platformA/release/app-platformA-release.apk
作者:帅得不敢出门