如何在不使用FAT AAR库的情况下嵌入.jar/.aar到Android库
不使用FAT AAR实现蓝牙SDK依赖嵌入Android库的方案
问题根源
你当前的依赖模块只是简单暴露本地aar文件,并非标准Android库模块,导致Gradle无法识别其内部资源与类;同时默认Android库打包只会生成依赖声明,不会将依赖的aar/jar内容嵌入最终输出的aar中,因此Demo应用会出现ClassNotFound异常。
解决步骤
1. 将依赖模块改为标准Android库模块
把你当前引用蓝牙SDK的模块(比如name_of_the_module)的build.gradle替换为标准Android库配置,这样Gradle能正确解析其内容:
plugins { id 'com.android.library' } android { compileSdk 33 // 替换为你项目使用的compileSdk版本 defaultConfig { minSdk 21 // 根据需求调整最低兼容版本 targetSdk 33 } } dependencies { // 若该模块包含本地jar文件,直接放入libs目录并添加以下配置 implementation fileTree(dir: 'libs', include: ['*.jar']) }
删除原模块中configurations.maybeCreate相关的配置,Android库模块默认会生成default构件配置。
2. 在主库中配置Gradle任务合并依赖内容
修改你的封装库的build.gradle,添加自定义任务,将依赖的aar/jar的类、资源等合并到最终输出的aar中:
plugins { id 'com.android.library' } android { compileSdk 33 defaultConfig { minSdk 21 targetSdk 33 } packagingOptions { pickFirst '**/*.class' pickFirst '**/*.xml' pickFirst '**/*.so' // 根据依赖情况添加其他需要优先保留的文件类型,避免冲突 } } dependencies { // 以api方式依赖蓝牙SDK模块,确保依赖关系被解析 api project(':name_of_the_module') // 若有多个SDK模块,依次添加 // api project(':another_ble_module') } // 自定义任务:合并依赖内容到输出aar tasks.whenTaskAdded { task -> // 监听bundleXXXAar任务(比如bundleReleaseAar、bundleDebugAar) if (task.name.startsWith('bundle') && task.name.endsWith('Aar')) { task.doLast { def outputAar = task.outputs.files.singleFile def tempRoot = file("$buildDir/temp_aar_merge") tempRoot.deleteDir() tempRoot.mkdirs() // 1. 解压主库aar到临时目录 copy { from zipTree(outputAar) into tempRoot } // 2. 遍历所有api依赖的aar,合并内容 configurations.api.resolvedConfiguration.resolvedArtifacts.each { artifact -> if (artifact.extension == 'aar') { def depTempDir = file("$tempRoot/deps/${artifact.name}") depTempDir.deleteDir() depTempDir.mkdirs() // 解压依赖aar copy { from zipTree(artifact.file) into depTempDir } // 合并classes.jar:将依赖类合并到主库的classes.jar中 def depClassesJar = file("$depTempDir/classes.jar") if (depClassesJar.exists()) { def mergedClassDir = file("$tempRoot/classes") mergedClassDir.deleteDir() mergedClassDir.mkdirs() // 解压主库原classes.jar copy { from zipTree("$tempRoot/classes.jar") into mergedClassDir } // 解压依赖的classes.jar到同一目录 copy { from zipTree(depClassesJar) into mergedClassDir } // 删除原classes.jar,重新打包合并后的类文件 file("$tempRoot/classes.jar").delete() exec { commandLine 'jar', 'cf', "$tempRoot/classes.jar", '-C', mergedClassDir, '.' } } // 合并res资源 def depResDir = file("$depTempDir/res") if (depResDir.exists()) { copy { from depResDir into "$tempRoot/res" duplicatesStrategy = DuplicatesStrategy.INCLUDE // 可根据需求改为RENAME或EXCLUDE } } // 合并assets资源 def depAssetsDir = file("$depTempDir/assets") if (depAssetsDir.exists()) { copy { from depAssetsDir into "$tempRoot/assets" duplicatesStrategy = DuplicatesStrategy.INCLUDE } } // 合并libs目录下的jar文件 def depLibsDir = file("$depTempDir/libs") if (depLibsDir.exists()) { copy { from depLibsDir into "$tempRoot/libs" duplicatesStrategy = DuplicatesStrategy.INCLUDE } } } } // 3. 重新打包临时目录为最终aar outputAar.delete() exec { commandLine 'jar', 'cf', outputAar.path, '-C', tempRoot, '.' } // 清理临时文件 tempRoot.deleteDir() } } }
3. 测试打包
执行主库的bundleReleaseAar或bundleDebugAar任务,生成的aar会包含所有依赖的蓝牙SDK的类与资源。将该aar接入Demo应用后,即可避免ClassNotFound异常。
注意事项
- 冲突处理:若多个依赖存在同名类或资源,需调整
duplicatesStrategy(可选值:INCLUDE、RENAME、EXCLUDE),避免打包失败。 - Gradle兼容性:该方案适配Android Studio Dolphin对应的Gradle 7.4版本,若后续升级Gradle需调整任务逻辑。
- 本地jar依赖:若蓝牙SDK以jar形式存在,直接将jar放入主库的
libs目录,添加api fileTree(dir: 'libs', include: ['*.jar']),任务会自动合并这些jar的类到主库的classes.jar中。
内容的提问来源于stack exchange,提问作者SwHeroCat
相关产品推荐
相关产品推荐

