Android通过aar方式可以把代码,资源文件等等打成一个包,提供给第三方使用或者自己使用,aar包含这所需要的依赖资源,避免了大量的模块引用,加快了编译的速度,另外在SDK开发中通常是以aar的方法或者远程依赖提供给第三方使用。下面总结下aar生成依赖的方式和应用存在的一些问题。下面举例:
app依赖library,library依赖BaseLibrary,这种情况下如果library需要生成aar提供给app使用或者提供给第三方使用,就需要合理的进行打包资源,生成aar,下面介绍集中常用的方式:
一、分模块打包aar
1、生成aar
这种方式首先对BaseLibrary打包,生成一个base-aar,,然后在对library打包生成library-aar,把两个aar都集成到app里面进行使用。通过如下命令:
./gradlew BaseLibrary:assemble
./gradlew library:assemble
生成aar,然后在对应的build/outputs/aar文件夹下找到对应的文件。将两个aar放在app/libs下,在对应的gradle中添加:
implementation files('libs/base.aar')
implementation files('libs/library.aar')
重新编译即可。
2、注意事项
通过这种方式可以将jar包打进去到aar,但是对于implementation或者api的依赖则无效,如果base-aar中含有远程依赖,则需要重新将依赖文件拷贝到app的gradle的dependencies中去,否则会找不到类。
二、整体打包aar
对于第一种方式的不足是如果aar比较多的话用起来比较繁琐,这时候可以将BaseLibrary和library合并成一个aar来进行使用。如果将base-aar放入ibrary-aar直接打包生成aar会出现下面classes.jar嵌套的情况:
这种情况显然是有问题的,因此不能这样使用。下面介绍一种开源的方式:
1、使用方式
参考:https://github.com/kezong/fat-aar-android
2、集成
project/build.gradle下:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
}
}
library/build.gradle下:
apply plugin: 'com.kezong.fat-aar'
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
embed project(':BaseLibrary')
}
3、使用
./gradlew library:assemble
这时候生成的library-aar即是包含base-aar的aar,即将两个aar合并成为一个,此时还是不能找到implementation或者api的依赖,如果base-aar或者library-aar中含有远程依赖,则需要重新将依赖文件拷贝到app的gradle的dependencies中去,否则会找不到类。下面可以通过embed将一个implementation或者api打入aar中,如:
apply plugin: 'com.kezong.fat-aar'
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
embed project(':BaseLibrary')
embed 'com.google.code.gson:gson:2.8.4'
embed 'com.github.bumptech.glide:glide:4.11.0'
}
生成的aar包中就包含gons和glide的源码了,如下:
4、注意事项
尽管这种方式很便捷的能将implementation或者api的依赖合并为一个aar,但是还是存在很多兼容性问题,导致编译失败,常见的如下:
(1)资源冲突
假如BaseLibrary和library有个values/strings的内容:
<string cancel">取消</string>
或者values/colors的内容:
<color name="c_1A1B1F">#1A1B1F</color>
这时候就会引起资源冲突,解决方法是保证每个library的资源名称不一样。
(2)依赖冲突
假如第三方的库和aar或者本地依赖未打成aar的库有多个不同版本的gson,这时候需要exclude多余的gson,保证只能使用一个,这样如果引用的比较多或者比较深的话很难完全找到,用起来也很麻烦。
其他的问题请参考:https://www.jianshu.com/p/8f9cf6271c20?tdsourcetag=s_pcqq_aiomsg
三、使用本地仓库
以上两种方式都是生成本地aar方式,这种方式不能够理想的打包进去implementation的依赖,maven方式则可以不用担心这种情况,生成的maven仓库的pom文件则包含了依赖的所以信息,当使用生成的仓库使用,则可以自动的拉取下来所需的aar文件和相关依赖。
1、project/build.gradle
buildscript /repositories里面添加mavenLocal(),如下:
buildscript {
repositories {
mavenLocal()
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:3.4.0"
}
}
2、app/build.gradle
apply plugin: 'maven'
uploadArchives {
configuration = configurations.archives
repositories {
mavenDeployer {
//这里必须要file://localhost/,后面的地址换成你本地的绝对路径,下面是mac的路径
repository(url: "file://localhost/" + "/Users/xxx/Desktop/aar")
pom.project {
version '1.0.0'
artifactId 'library-demo'
groupId 'com.test.demo'
packaging 'aar'
description '测试aar本地仓库'
}
}
}
}
参数定义如下:
- repository url 路径可自定义
- version 版本
- artifactId 名称
- groupId 包名
- packaging 类型
- description 描述
3、执行
./gradlew uploadArchives
4、结果
5、使用
在项目最外层build.gradle 文件中添加如下代码
allprojects {
repositories {
google()
jcenter()
//注意:路径与之前生成路径保持一致,需要加上file://,下面是mac地址
maven{ url "file:///Users/xxx/Desktop/aar"}
//或者,二选一
maven {
url "file://${new File(project.rootProject.rootDir, 'aar').getAbsolutePath()}"
}
}
}
之后添加依赖:
implementation 'com.test.demo:library-demo:1.0.0'
重新编译一下即可使用。
四、使用jcenter仓库
1、jcenter仓库配置
本地maven仓库虽然解决了依赖问题,但是之只能在本地使用,但是在开发中使用最多的全球三大仓库是mavenCentral()、jcenter()、google()仓库,下面以jcenter仓库为例,介绍本地library的上传。
1.1、注册Jcenter
备注:网上很多帖子说这块需要注册个人版的,直接点进去是企业版的,没法发布,我在最新的官方上没遇到这种情况,直接点进去注册就行。
备注:另外网上很多帖子说注册需要国外邮箱才行,国内的不行,比如说google邮箱,我用的是公司的企业邮箱注册,一切顺利。
1.2、新建仓库
这样就注册完成!返回首页,下面会多一个仓库名称,就是你建立的仓库:
点进去啥也没有:
网上有的帖子说还需要Add New Package,这个步骤其实不用,到此仓库就建立完成了,准备工作已经做好了。
2、gralde环境配置
2.1、插件配置
gradle推送到jcenter需要使用两个插件:
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
在projct/build.gradle下面添加:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
}
}
2.2、library/build.gradle配置
在library/build.gradle最下面配置如下:
配置好在使用的时候即可:
implementation 'com.test.demo:payLib:1.0.0'
- com.test.demo:给个库的配置一样,因此在jcenter中写死了,去每次重复的编写。
- payLib:就是上面libraryName的名称,一般和模块名称一致。
- 1.0.0:版本号,每次提交到jcenter的时候必须升级版本号,否则提交失败。
这样,每个模块需要提交的jcenter的时候就配置上面几行代码,方便灵活,下面介绍jcenter.gradle的内容。
2.3、jcenter.gradle
jcenter.gradle位于项目的根目录,包括三大内容:
- 完成maven相关文件的生成与打包。
- 生成javadoc.jar和source.jar。
- 文件的打包上传到bintray.com。
首先需要使用引入的插件:
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
(1)完成maven相关文件的生成与打包
//项目在github主页地址
def siteUrl = 'https://github.com/xxx/xxx'
//Git仓库的地址
def gitUrl = 'https://github.com/xxx/xxx'.git'
//这块的内容就是implementation 'com.test.demo:payLib:1.0.0'的com.test.demo,要使用啥改成啥
group = 'com.test.demo'
//项目引用的版本号
version = project.versionName
install {
repositories.mavenInstaller {
// 生成pom.xml和参数
pom {
project {
packaging 'aar'
//可选,项目名称。
name project.libraryName
//可选,项目描述。
description project.libraryDesc
// 项目主页,这里是引用上面定义好。
url siteUrl
// 软件开源协议,现在一般都是Apache License2.0
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
//填写开发者基本信息,复制我的,这里需要修改。
developers {
developer {
//开发者的个人信息
id 'zhangsan'
name 'zhangsan'
email 'zhangsan@qq.com'
}
}
// SCM
scm {
// Git仓库地址.
connection gitUrl
// Git仓库地址。
developerConnection gitUrl
// 项目主页。
url siteUrl
}
}
}
}
}
(2)生成javadoc.jar和source.jar
// 生成jar包的task
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
// 生成jarDoc的task
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
// destinationDir = file("../javadoc/")
failOnError false // 忽略注释语法错误,如果用jdk1.8你的注释写的不规范就编译不过。
}
// 生成javaDoc的jar
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
这块没啥好讲的,直接复制即可。
(3)文件的打包上传到bintray.com
// 这里是读取Bintray相关的信息,不要把帐号密码的信息直接写在这里,写在local.properties中,这里动态读取。
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
// Bintray的用户名。
user = properties.getProperty("bintray.user")
// Bintray刚才保存的ApiKey。
key = properties.getProperty("bintray.apikey")
configurations = ['archives']
pkg {
//id
userOrg = user
//Repository名字 需要自己在bintray网站上先添加
repo = properties.getProperty("bintray.rep")
//发布到JCenter上的项目名字
name = project.libraryName
//项目描述
desc = project.libraryDesc
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = ["Apache-2.0"]
// 是否是公开项目。
publish = true
}
}
//如果你的项目里面有中文注释的话,必须将格式设置为UTF-8,不然会出现乱码
javadoc {
options {
encoding "UTF-8"
charSet 'UTF-8'
author true
version true
links "http://docs.oracle.com/javase/7/docs/api"
}
}
为了控制权限,不要把帐号密码的信息直接写在这里,写在local.properties中,这里动态读取。包括用户名、密码、仓库名称。
- 用户名:就是登录jcenter的用户名。
- 仓库名称:就是上上面创建的仓库名称。
- 密码:点击头像,选择Edit Your Profile,出现
2.4、local.properties
- bintray.rep=你的仓库名称
- bintray.apikey=获取到的key
- bintray.user=你的登录名称
3、推送到jcenter
项目右上角gradle,点击bintrayUpload就上传上去了。
上传完成之后,打开https://bintray.com/,就会看到之前仓库新建的内容:
点开刚刚提交项目的主页,点击右下角的添加到jcenter按钮,填写信息,也可以不填:
提交之后大概40分钟左右就通过了,不通过的话也会收到邮件的说明不通过原因,修改后再次提交即可。
注意事项:
Jcenter提交的maven仓库代码必须开源,私有的,本地的,内部的,别人访问不到的等等代码仓库无法通过提交审核,如果不能开源的aar库,需要使用其他仓库,mavenCentral理论上也需要开源项目才能上传,但是可以通过添加许可证、开源协议等的方式上传非开源的依赖库,这个过程比较漫长和繁琐,另外开源项目mavenCentral相比Jcenter也不容易,所以还是推荐Jcenter方法,不开源的项目内部搭建私有仓库或者提供arr包也可以解决问题。