AAR⽂件常识
AAR,为 Android ⽽⽣。
在使⽤ Eclipse 开发 Android 的那个时代(其实也就⼏年前⽽已),如果想代码打包,只有 JAR 包⼀个⽅法,但是 JAR 只能把 Java ⽂件代码打包进去,如果要使⽤⼀个有布局和资源的库的话,除了将 JAR 放⼊ libs 外,还需要引⼊相关的资源和配置⽂件,⼗分不优雅。
Android Studio 出来之后,出现了⼀个新的⽅法,打包 AAR ⽂件 ,这个不仅可以把 Java ⽂件给打进去,还包含 l 和资源⽂件等,使⽤的话,直接引⼊⼀个 AAR ⽂件就⾜够了,⾮常⽅便。
如何⽣成 AAR ⽂件
AAR,名字来源于 Android Archive,见名知义,是⼀个 Android 库项⽬的⼆进制归档⽂件,使⽤ Android Studio ,⾮常简单可以⽣成⼀个 AAR ⽂件。
1.⾸先创建⼀个 Android library Module.
2.等待 Gradle 构建完毕, 就可以在项⽬名称/模块名称/build/outputs/aar/中到这个库项⽬的 AAR ⽂件了。
3.如果修改了代码,也可以通过 Build > Make Project 的⽅式重新⽣成⽂件。
其实这个过程,也⽣成了对应的 JAR 包,⽂件在
项⽬名称/模块名称/build/intermediates/bundles/debug(release)/classes.jar,classes.jar 这个library 对应的 JAR 包。
不过在 AAR ⽂件中,修改后缀名打开后,⾥⾯也有 classes.jar ,和这个 classes.jar 是同样的内容,
AAR ⽂件的结构
AAR ⽂件的⽂件扩展名为 .aar,⽂件本⾝是⼀个 zip ⽂件,以下内容是必须包含的:
/l
/classes.jar
/res/
/R.txt
此外,根据打包的 Library Module 情况不同,打包出来的 AAR ⽂件也可能包含以下内容:
/assets/
/libs/名称.jar
/jni/abi 名称/名称.so(其中 abi 名称 是 Android ⽀持的 ABI 之⼀)
/
/lint.jar
我们拿到上个步骤中⽣成的 .aar ⽂件,⼿动将后缀名改成 .zip⽂件,解压之后的样⼦是这个样⼦的:
项⽬中使⽤ AAR ⽂件的两种⽅式
AAR ⽂件使⽤有两种⽅式,⼀种是使⽤在线的(⽹上的),⼀种是添加本地的 AAR ⽂件。
本地 AAR 使⽤
1.把 aar ⽂件放在⽬标 module ⼀个⽂件⽬录内,⽐如就放在 libs ⽬录内。
2.在⽬标 module 的 adle ⽂件添加如下内容:
1 2 3 4 5 6 7 8 9repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
compile(name:'AAR的名字', ext:'aar') }
远程 AAR 使⽤
事实上,在⼯作项⽬中,远程的 AAR ⽂件的使⽤频率⽐本地⾼,因为⽤起来很⽅便,我们依赖很多的第三⽅库就是远程⼀览的⽅式。远程的 AAR 使⽤的前提是有⼀个远程的库链接,然后通过 Gradle 下载依赖,因此有下⾯的两个步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13allprojects {
repositories {
// google的官⽅仓库
google()
// 出名的公共中央仓库
jcenter()
mavenCentral()
//如果有私库,也要添加链接 //....
}
}
其中 google() 是⾕爹的官⽅库的仓库地址, jcenter() 和 mavenCentral() 是⽐较出名的的中央仓库,
基本第三⽅库都会上传到这些仓库。有时公司也会有⾃⼰的⼀些封装库,不想对外暴露,就放在⾃⼰的私有仓库中,仓库的地址也要在这⾥添加。
1 2 3dependencies {
implementation 'com.android.support:support-v4:25.3.1' }
AAR 使⽤的注意事项
AAR 使⽤起来爽歪歪,但是以下问题也要注意,否则使⽤过程中可能引起不适~
应⽤模块的 minSdkVersion 必须⼤于或等于 Library Module 中定义的版本
AAR 作为相关应⽤模块的⼀部分编译,因此,库模块中使⽤的 API 必须与应⽤模块⽀持的平台版本兼容,所以 AAR 中的
minSdkVersion 要尽量的设置低⼀点。
资源合并问题
如果 aar 中有资源⽂件,集成过程中,很容易出现资源冲突,例如两个相同名字的图⽚什么的。为了避免这个问题,有两种⽅法,⼀是制定⼀个不⽤冲突的命名规范,⼆是 library Module 的 adle 中设置资源前缀。第⼀种,嗯,全靠⾃觉,维护起来很难,推荐第⼆种解决⽅法。
1 2 3 4android {
resourcePrefix "<;前缀>" }
aar 不能使⽤ assets 原始资源
⼯具不⽀持在库模块中使⽤原始资源⽂件(保存在 assets/ ⽬录中)。应⽤使⽤的任何原始资源都必须存储在应⽤模块⾃⾝的
assets/ ⽬录中
aar 的混淆
通过对 library Module 的混淆,可以打出⼀个混淆后的 aar 包,这样的话,就不⽤要求在依赖此 aar 的同时,还要⼿动添加对应的混淆规则了。
具体做法是:
1.将混淆规则写⼊ 。
2.library Module 的 adle ⽂件设置 consumerProguardFiles 属性,引⽤第⼀步创建的混淆的⽂件。
1 2 3 4 5 6android {
defaultConfig {
consumerProguardFiles '' }
...
}
以上是默认的构建类型,如果 library Module 需要对不同的 buildType 做特别的处理,还需要专门设置。
1.library Module 的 adle 中设置 publishNonDefault = true,请注意,设置 publishNonDefault 会增加构建时间。
1 2 3 4android {
maven打包本地jar包...
publishNonDefault true }
2.app 的 adle 中设置不同构建类型的处理。
1 2 3 4 5dependencies {
debugCompile project(path: ':library', configuration: 'debug') releaseCompile project(path: ':library', configuration: 'release') }
在依赖本⾝就带有混淆规则的 AAR 的时候,AAR 的 ProGuard ⽂件将附加⾄ app 的 ProGuard 配置⽂件 ()。所以,aar 的混淆规则可能会影响 app,因此,制定 aar 的混淆规则的时候,也要谨慎⼀点,只包括⾃⼰的类即可,不要把范围设置太⼤。
AAR 内部三⽅库依赖的问题
项⽬的开发过程中,发现⼀个问题:
使⽤ Android Studio 打包出来的 AAR ,不会将其依赖的三⽅库打包进去。
举个例⼦,library Test 依赖了 okhttp,打包成了 Test.aar ,app 使⽤本地⽅式引⽤了 Test.aar,但是⽆法使⽤ okhttp,为了不报错,app 还需要添加 okhttp 依赖。
Google Android Studio 的负责⼈在 stackoverflow 上解释了 的原因,是因为将不同的library打包在⼀起,涉及到资源和配置⽂件智能合并,所以是个⽐较复杂的问题,同时也容易造成相同的依赖冲突。
官⽅虽然不⽀持,但是开发者的能⼒是⽆限的,为了解决此问题,开发出来了⼀个 Gradle 插件 , 这种⽅式是抛弃 Android Studio ⾃带的打包 AAR 的⽅法,⽽是⾃⼰编写⼀个⽣成 AAR 的脚本。也是很厉害了,但是很不幸,⽬前来看 gradle 2.2.3+ 以上,这个就不适⽤了。
不过,不要慌,这个问题可以通过使⽤ Maven 依赖解决。因为 library Module 上传 Maven 后,会⽣成 ⼀个 .pom ⽂件,记录 library Module 的依赖。当 Gradle 依赖 Maven 上的这个库时,会通过 pom ⽂件下载对应依赖。如果不想要对应依赖的话,可以通过下⾯的⽅法关闭 Gradle 的依赖传递。
举个例⼦如下:
1 2 3 4 5 6 7 8 9 10 11//正常依赖
implementation 'com.chemao.android:chemao-sdk:1.2.3'
//关闭全部依赖传递-⽅法1
implementation 'com.chemao.android:chemao-sdk:1.2.3@aar'
//关闭全部依赖传递-⽅法2
implementation('com.chemao.android:chemao-sdk:1.2.3') {
transitive = false
}
先来看下Android Gradle plugin 3.0⼏个引⼊依赖的⽅法:
Implementation
对于使⽤了该命令编译的依赖,对该项⽬有依赖的项⽬将⽆法访问到使⽤该命令编译的依赖中的任何程序,也就是将该依赖隐藏在内部,⽽不对外部公开。
使⽤implementation会使编译速度有所增快:⽐如我在⼀个library中使⽤implementation依赖了gson库,然后我的主项⽬依赖了library,那么,我的主项⽬就⽆法访问gson库中的⽅法。这样的好处是编
译速度会加快,我换了⼀个版本的Gson库,但只要library的代码不改动,就不会重新编译主项⽬的代码。
api
等同于compile指令
compileOnly
等同于provided,只在编译时有效,不会参与打包,不会包含到apk⽂件中。可以⽤来解决重复导⼊库的冲突(下⽂会提到)。
更多细节内容可以看下
远程仓库依赖
我们先来看下主⼯程下的adle⽂件
buildscript {
ext.kotlin_version = '1.1.51'
repositories {
google()
jcenter()
}
dependencies {
classpath 'ls.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual adle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
复制代码
引⼊远程仓库依赖是很⽅便的,但在之前我们需要声明远程仓库的地址。上⾯有两个仓库地址的声明,⼀个在buildscript {},另⼀个
在repositories {}。看代码中系统给我们的注释就知道:前者是gradle脚本⾃⾝执⾏所需依赖(Gradle插件),后者是项⽬本⾝需要的依赖(普通代码库)。所以如果你没有引⼊远程的Gradle插件,那么就不⽤在buildscript {}下的dependencies下添加依赖。
关于Gradle插件的开发可以看下这篇⽂章:
再来看下⼏种远程依赖的添加⽅式:
implementation 'commons-lang:commons-lang:2.6'
implementation group: 'de.guice', name: 'guice', version: '1.0'
implementation('org.hibernate:hibernate:3.1') {
//不同版本同时被依赖时,那么强制依赖这个版本的,默认false
force = true
//exclude可以设置不编译指定的模块,有三种写法:
exclude module: 'cglib'
exclude group: 'org.jmock'
exclude group: 'org.unwanted', module: 'iAmBuggy'
/
/禁⽌依赖的传递,gradle⾃动添加⼦依赖项(依赖包所需的依赖),设置为false,则需要⼿动添加每个⼦依赖项,默认为true。
transitive = false
}
复制代码
同样的配置下的版本冲突,会⾃动使⽤最新版;⽽不同配置下的版本冲突,gradle同步时会直接报错。可使⽤exclude、force解决冲突。⽐如你同时依赖了两个版本的v7包:
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:appcompat-v7:23.1.1'
复制代码
最终只会使⽤26.1.0版本。但是如
implementation 'com.android.support:appcompat-v7:23.1.1',和androidTestImplementation 'com.and
st.espresso:espresso-core:2.1',所依赖的com.android.support:support-annotations版本不同,就会导致冲突。除了可以⽤exclude、force解决外,也可以⾃⼰统⼀为所有依赖指定support包的版本,不需要为每个依赖单独排除了:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论