Android Studio同一个工程根据不同芯片平台加载不同的framework.jar及使用不同的代码

文章目录

需求

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。

  1. 配置 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')
}
  1. 配置名称规则:
    如果 Flavor 名叫 xyz,依赖类型是 compileOnly,则配置名为 xyzCompileOnly。
    platformA + CompileOnly -> platformACompileOnly
    platformB + CompileOnly -> platformBCompileOnly
  2. 配置 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"))
}
  1. 修改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"
            }
        }
    }
}
  1. 验证方法
    配置完成后,你可以通过以下方式验证:
    在 Android Studio 右侧的 Gradle 面板中,展开 app -> Tasks -> android。
    你会看到类似 assemblePlatformADebug 和 assemblePlatformBDebug 的任务。
    分别运行这两个任务,会对应不同的平台framework.jar。

同一项目调用不同的java

上面已经介绍了如何在同一项目中引入不同平台的framework.jar,现在有了新的需求:

不同平台如果要运行不同的java代码怎么处理,比如平台A有函数funA但是平台B却没有,在平台A中又要调用这个funA,在平台B上编译就会报没有这个函数。

  1. 目录结构规划
    假设两个 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  (可以是空实现,或者根本没有这个文件)
  1. 代码实现细节
    场景描述:
    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();
  1. 核心原理
  • 源码集合并:当执行 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" 错误。
  1. 验证
  • 使用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

作者:帅得不敢出门

相关推荐
xiangxiongfly9152 小时前
Android LeakCanary源码分析
android·leakcanary
黄林晴2 小时前
紧急预警!Android 17 定位权限大改,你的 App 要适配了
android
夏沫琅琊3 小时前
Android API 发送短信技术文档
android·kotlin
周周不一样3 小时前
Android基础笔记1
android·笔记·gitee
取码网3 小时前
影视APP源码 SK影视 安卓+苹果双端APP 反编译详细视频教程+源码
android
musk12123 小时前
android webview 黑屏问题 , 页面加载时间有点长的情况下
android
夏沫琅琊3 小时前
Android 彩信导出技术文档
android·kotlin
sp42a3 小时前
安卓原生 MQTT 通讯 Java 实现
android·java·mqtt