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

如何在不使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 21:02:09