Andriod开发学习——Android中实现多级嵌套AAR包

AAR嵌套打包——flat-aar-android

Android studio 的 module 打包一般会打包成 AAR 的形式。如果 module 引用了一个本地的 aar,在打包的时候,这个被引用的 aar 是不会打包进去的,这种设计思想是比较好的,可以很好的避免包冲突的问题。例如 App 引用了两个 aar(1.aar 和 2.aar),1.aar 和 2.aar 都依赖了第三方的 3.aar,如果1.aar 和 2.aar 都把 3.aar 打包进去的话,App 再引用 1.aar 和 2.aar 的时候就会因为都有 3.aar 发生引用冲突。

但是在实际SDK开发过程中,会遇到一些很难处理的情况:例如module1 引用了一个本地 AAR1,且依赖另一个module2,module2引用了另一个本地 AAR2,这该如何将module1打包成aar(需要包含 AAR1,module2以及 AAR2)?——本篇文章就会介绍,这种情况的处理方式。

api和implementation之间的区别。

api:当前module可以使用,依赖当前module的module也可以使用。

implementation:只有当前module可以使用,其他module需要单独重新依赖才可以使用。

一. mModule1 直接依赖 aar(单一依赖)

  1. 拷贝 aar 至 mModule1/libs 目录

  2. 在mModule1/build.gradle 添加以下代码

/ 根节点下添加 repositories 节点
repositories {
    flatDir {
    	dirs 'libs'
  	}
}  

// dependencies节点内添加依赖
dependencies {
	 // aar-name 为 mModule 要依赖的 aar 包的名称,不包含后缀。
	 implementation(name: ‘aar-name’, ext: 'aar')
}

二. mModule1 依赖mModule2,mModule2引用了aar(嵌套依赖)

首先明确一点的是 Android 没有帮我们实现这一点,如果你针对单个模块打包 AAR 是不会把它依赖 module 一起打进去的。所以也延伸出下面几种尝试解决的方式:

最简单方案:把所有 module 合并成一个 module,变成单独 module 打包的形式,全部交给 Android Studio 帮我们完成,但这又走回了原先代码未拆分前的老路,最不该优先考虑的方案。

使用 maven 管理 aar 依赖方案:使用 maven 仓库进行远程依赖时,可在其 POM 文件中看到依赖关系,添加依赖时会自动导入其依赖的其他库。对于这种多个 module 的情况,我们可以把每个 module 都上传到 maven 库,因为上传时会 POM 文件中会保留 module 之间的依赖关系,最终用户添加某一库时也能正确引入其他依赖的库。缺点是使用这种方式通常需要 gradle 构建,在兼容一些旧版本的 Unity Editor 或其他场景下最好是能直接提供库文件,可作为保留方案考虑。

使用 fat-aar 方案: 开源项目一开始 android-fat-aar 就是为了解决这个问题而诞生的,可惜后续开发者也没有在维护了,但是里面一些实现思路是值得借鉴的,通过看 fat-aar.gradle 实现脚本你就知道,这是针对特地版本下的构建环境,把 module 构建 aar 时依赖的其他模块进行 copy 以及合并进来打包,这部分对开发者来说是透明的,所以整个流程足够简单又够用。但是因为项目输出结构跟构建环境有关,所以兼容性是个很大的问题,当然如果你也可以自己去兼容新版的 gradle 构建环境,本文附录可以参考实现。

本文实现的方案就是采用 fat-aar 方案,其实现过程如下:

使用 fat-aar 方案:

1. 在build.gradle(project)中添加 flat-aar 路径
dependencies {
    classpath 'com.github.kezong:fat-aar:1.3.6'
}
2. 在需要依赖嵌套aar的Module中的build.gradle中add plugin
apply plugin: 'com.kezong.fat-aar'
3. 在Module中(有AAR包)中更改依赖
dependencies {
    implementation fileTree(dir: 'libs', include: '*.jar')
    
    // java dependency
    embed project(path: ':lib-java', configuration: 'default')
        
    // aar dependency
    embed project(path: ':lib-aar', configuration: 'default')
        
    // aar dependency
    embed project(path: ':lib-aar2', configuration: 'default')
    
    // local full aar dependency, just build in flavor1
    flavor1Embed project(path: ':lib-aar-local', configuration: 'default')
        
    // local full aar dependency, just build in debug
    debugEmbed(name: 'lib-aar-local2', ext: 'aar')
        
    // remote jar dependency
    embed 'com.google.guava:guava:20.0'
        
    // remote aar dependency
    embed 'com.facebook.fresco:fresco:1.12.0'
        
    // don't want to embed in
    implementation('androidx.appcompat:appcompat:1.2.0')
}

多级本地依赖

如果你想将本地所有相关的依赖项全部包含在最终产物中,你需要在你主library中对所有依赖都加上embed关键字

比如,mainLib依赖lib1,lib1依赖lib2,如果你想将所有依赖都打入最终产物,你必须在mainLib的build.gradle中对lib1以及lib2都加上embed关键字。

三、实例演示

在这里插入图片描述

如图所示,Module3依赖Module0、Module1、Module2,其中Module1、Module2都依赖Module0,每个Module都引用一个aar包,如何将分别Module0、1或者Module0、2打包到Module3生成新的aar?

具体实现步骤如下:

1. 在build.gradle(project)中添加 flat-aar 路径
dependencies {
    classpath 'com.github.kezong:fat-aar:1.3.6'
}
2. 在Module3中的build.gradle中add plugin,add depencies
apply plugin: 'com.kezong.fat-aar'
    
android {
    flavorDimensions 'environment'
    productFlavors{
        total{
            dimension "environment"
            buildConfigField("int","algorithmType","-1")
        }
        Module1{
            dimension "environment"
            buildConfigField("int","algorithmType","0")
        }
         Module2{
            dimension "environment"
            buildConfigField("int","algorithmType","1")
        }
       
    }

    repositories {
        flatDir { dirs 'libs'}
    }
}
    
dependencies {
    //传统依赖
     api project(path: ':Module0')
     api project(path: ':Module1')
     api project(path: ':Module2')
       
    //在打包时的任务指令(打包release包)
    def taskName = gradle.startParameter.taskNames
    for(def name:taskName){
        def ts = name.toString().toLowerCase()
        if(ts.contains('release') && !ts.contains('app')){
            embed project(path: ':Module0', configuration: 'default')
            Module1Embed project(path: ':Module1', configuration: 'default')
            Module2Embed project(path: ':Module2', configuration: 'default')
            totalEmbed project(path: ':Module1', configuration: 'default')
            totalEmbed project(path: ':Module2', configuration: 'default')
            break
        }
    }
}
3. 在Module1、2中的build.gradle中add plugin,add depencies
plugins {
    id 'com.kezong.fat-aar'
}

dependencies {
    //传统依赖
    api project(path: ':evaCore')
    api(name: 'aar1', ext: 'aar') //Module1
    api(name: 'aar2', ext: 'aar') //Module2
        
    //在打包时的任务指令(打包release包)
    def taskName = gradle.startParameter.taskNames
    for(def name:taskName){
        def ts = name.toString().toLowerCase()
        if(ts.contains('release') && !ts.contains('app')){
            embed(name: 'aar1', ext: 'aar')//Module1
            embed(name: 'aar2', ext: 'aar')//Module2
            break
        }
    }
}
4. 在Module0中的build.gradle中add plugin,add depencies
plugins {
    id 'com.kezong.fat-aar'
}

dependencies {
    //传统依赖 
    api(name: 'aar0', ext: 'aar') 
        
    //在打包时的任务指令(打包release包)
    def taskName = gradle.startParameter.taskNames
    for(def name:taskName){
        def ts = name.toString().toLowerCase()
        if(ts.contains('release') && !ts.contains('app')){
            embed(name: 'aar0', ext: 'aar')
            break
        }
    }
}

附录

附录一:远程依赖

如果你想将所有远程依赖在pom中声明的依赖项同时打入在最终产物里的话,你需要在build.gradle中将transitive值改为true,例如:

fataar {
    /**
     * If transitive is true, local jar module and remote library's dependencies will be embed.
     * If transitive is false, just embed first level dependency
     * Local aar project does not support transitive, always embed first level
     * Default value is false
     * @since 1.3.0
     */
    transitive = true
}

如果你将transitive的值改成了true,并且想忽略pom文件中的某一个依赖项,你可以添加exclude关键字,例如:

embed('com.facebook.fresco:fresco:1.11.0') {
    // exclude any group or module
    exclude(group:'com.facebook.soloader', module:'soloader')
    // exclude all dependencies
    transitive = false
}

附录二:Gradle版本支持

VersionGradle PluginGradle
1.0.13.1.0 - 3.2.14.4 - 6.0
1.1.63.1.0 - 3.4.14.4 - 6.0
1.1.103.0.0 - 3.4.14.1 - 6.0
1.2.63.0.0 - 3.5.04.1 - 6.0
1.2.83.0.0 - 3.5.94.1 - 6.8
1.2.11 - 1.2.143.0.0 - 3.6.94.1 - 6.8
1.2.15 - 1.2.163.0.0 - 4.0.24.1 - 6.8
1.2.173.0.0 - 4.0.24.9 - 6.8
1.2.18+3.0.0 - 4.1.04.9 - 6.8
1.3.+3.0.0 - 4.1.04.9 - 6.8
1.3.43.0.0 - 4.1.04.9+

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值