Android Library的依赖方式及发布

最近发布一个项目,发现以前发布到 JCenter 的步骤都忘光了,又得到处翻资料,真是尴尬…..

还是那句老话,好记性不然烂笔头,在此整理 Android Studio 依赖相关 以及 如何发布项目到 JCenter



Android Studio 添加依赖

Module 依赖

module 依赖是指在本地创建一个 module,然后如下步骤,依赖此模块。

图一

这样做的好处就是随时可以修改 module。

上图可以看到,Android Studio(以下简称 AS)提供了三种依赖方式。



本地依赖

本地依赖是指,将 jar 或者 aar 直接拷贝到项目的 libs 文件夹下 ,然后对其进行依赖。

  • jar 的依赖如图一,拷贝进 libs 目录后,AS 才能识别到。
  • aar 的本地依赖官方没有提供解决方案,不过高手在民间。


在讲解本地 aar 依赖之前,先科普一下 aar 文件。

aar 文件是基于 jar 文件之上开发的。因为有些Android Library 需要植入一些安卓特有的文件,比如 AndroidManifest.xml,资源文件,Assets或者JNI。这些文件在 Jar 中是没有的,因此诞生了 aar 文件。

aar 文件和 jar 一样,只是普通的zip文件。不过具有不同的文件结构。jar文件以classes.jar的名字被嵌入到aar文件中。

aar文件如下:

  • /AndroidManifest.xml (mandatory)
  • /classes.jar (mandatory)
  • /res/ (mandatory)
  • /R.txt (mandatory)
  • /assets/ (optional)
  • /libs/*.jar (optional)
  • /jni//*.so (optional)
  • /proguard.txt (optional)
  • /lint.jar (optional)

在此说明一下,aar 文件的生成只能在 Android Library 中,也就是gradle脚本的声明是apply plugin: 'com.android.library'的 module,然后编译后就会在 build/outputs/aar 文件夹里生成aar文件。

生成 aar

本地 aar 依赖需要在 app 的 build.gradle 文件添加如下内容

1
2
3
4
5
repositories {
flatDir {
dirs 'libs' //this way we can find the .aar file in libs folder
}
}

之后再其它项目里面添加 gradle 依赖

1
2
3
dependencies {
compile(name:'dor', ext:'aar')
}

以上就是 aar 的本地依赖。



远程依赖

远程依赖就是在 app 的 build.gradle 中直接添加(当然也可以通过图一搜索的方式)

1
2
3
dependencies {
compile 'com.squareup.picasso:picasso:2.5.2'
}

这样一行代码就完成了依赖,也是最常见的依赖方式。


远程依赖库的来源

我刚开始也不明白AS 是怎样凭借 一行代码得到这些library的。

查阅资料才知道,AS 是从项目 build.gradle 文件里面定义的Maven 仓库服务器上下载library的。

Apache Maven 是 Apache 开发的一个工具,提供了用于贡献library的文件服务器。

总的来说,只有两个标准的 Android library 文件服务器:JCenter 和 Maven Central。

不管是 「JCenter」还是「Maven Central」 ,两者都是Maven 仓库,只是他们维护的服务器不同,由不同的人提供。


JCenter

JCenter 是一个由 bintray.com 维护的Maven仓库 ,整个仓库的内容在 http://jcenter.bintray.com/

在项目的build.gradle 文件中如下定义仓库,就能使用jcenter了

1
2
3
4
5
allprojects {
repositories {
jcenter()
}
}


Maven Centra

Maven Central 则是由 sonatype.org 维护的Maven仓库,整个仓库的内容在 https://oss.sonatype.org/content/repositories/releases/

在项目的build.gradle 文件中如下定义仓库,就能使用Maven Central了

1
2
3
4
5
allprojects {
repositories {
mavenCentral()
}
}


jcenter 与 Maven Central 的区别

事实上两个仓库都具有相同的使命:提供Java或者Android library服务。上传到哪个(或者都上传)取决于开发者。

起初,Android Studio 选择Maven Central作为默认仓库。如果你使用老版本的Android Studio创建一个新项目,mavenCentral()会自动的定义在build.gradle中。

但是Maven Central的最大问题是对开发者不够友好。上传library异常困难。上传上去的开发者都是某种程度的极客。同时还因为诸如安全方面的其他原因,Android Studio团队决定把默认的仓库替换成jcenter。正如你看到的,一旦使用最新版本的Android Studio创建一个项目,jcenter()自动被定义,而不是mavenCentral()。

以下是使用Jcenter的原因:

  • jcenter通过 CDN 发送library,开发者可以享受到更快的下载体验。
  • jcenter是全世界最大的Java仓库,因此在Maven Central 上有的,在jcenter上也极有可能有。
  • 上传library到仓库很简单,不需要像在 Maven Central上做很多复杂的事情。
  • 友好的用户界面
  • 如果你想把library上传到 Maven Central ,你可以在bintray网站上直接点击一个按钮就能实现

基于上述原因,我们发布 Android Library 最好是发布到 Jcenter 上。


Gradle 下载依赖库的原理

在项目的 build.gradle 文件中加入一行代码的时候,这些库是怎样下载到我们的项目中呢?

一般来说,library 的字符串形式,包含3部分

GROUP_ID:ARTIFACT_ID:VERSION

以冒号「:」为分隔

  • GROUP_ID

    library的group,通常以开发者包名 加 library的名称来命名group。

  • ARTIFACT_ID

    library的真实名称

  • VERSION

    library 的版本号

例如Android 界大名鼎鼎的 Square 公司的 Library

1
2
3
4
5
6
dependencies {
compile 'com.squareup:otto:1.3.7'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'
}

添加上述的依赖库后,Gradle 会根据项目的build.gradle 文件中配置的Maven 仓库,询问仓库服务器这个library是否存在,(如果配置了多个仓库,会依次询问这些仓库)如果存在,Gradle 会获得 library 的存储路径,然后 AS 将下载这些文件到我们的电脑上,与我们的项目一起编译。

一般存储路径都是这样的形式:GROUP_ID/ARTIFACT_ID/VERSION_ID。

例如:

Jcenter库的地址:http://jcenter.bintray.com/com/squareup/otto/1.3.7

Maven Central 库的地址:https://oss.sonatype.org/content/repositories/releases/com/squareup/otto/1.3.7/


上传 Library 到 JCenter

我们总是用别人的库,如果自己写一个库分享给别人用,那样不是更酷嘛!

我们可以通过 Gradle 把项目发布到 Maven 库中,至于选 Maven Central 还是 JCenter,通过前面的介绍,当然是选 JCenter 更好。

整个发布过程如下图:

上传到 JCenter 的过程

可以看到整个过程还是挺清晰的,但不亲自去试试,就不知道有多少坑!


1.注册 Bintray 并创建私有 Maven 仓库

JCenter 是由 Bintray 维护的 Maven 库,所有首先得去 Bintray 网站注册一个账号。

就是因为注册这一步有个巨坑,害得自己填了好久。

打开 Bintray官网 ,天真的我就直接点了 START YOUR FREE TRIAL ,然后欲哭无泪。

Bintray 组织注册

Bintray 官网在2016年底改版了,直接点注册是组织用户,而非个人用户,这将导致最后一直提交失败。

最后只能重新注册新的个人账户。

个人账户注册在首页的底部,要把页面拉下去才看得到。

Bintray 个人注册

或者直接点击这个 注册个人账户

后边注册的步骤就很简单了,有 github或者 google 账户的直接登录就行了,如果需要注册这里的邮箱不能是国内的邮箱。


登录上之后,点击右上角的小箭头 Edit Profile —> API Key —> 输入密码 —> 复制 API Key。

获取 API Key

这个 API Key 在后面会有用到。

然后创建私有的 Maven 仓库,在个人首页点击 Add New Repository

添加仓库

然后按照下图填写内容

创建仓库

最后点击 Create 创建,这样就创建了仓库。


2. 配置项目

接下来就是配置要发布的项目,这里借助 bintray-release 这个开源库来快速发布,注意,这个插件只能帮助 android library 的 module 来实现快速发布。

首先是在项目的根目录 build.gradle 中配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
//首先添加这个
classpath 'com.novoda:bintray-release:+'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
//开源库中有中文注释,添加下面这些
allprojects {
tasks.withType(Javadoc) {
options {
encoding "UTF-8"
charSet 'UTF-8'
links "http://docs.oracle.com/javase/7/docs/api"
}
}
}

然后在将要发布的 module 下的 build.gradle 中添加如下配置

1
2
3
4
5
6
7
8
9
10
//for upload
apply plugin: 'com.novoda.bintray-release'
publish {
userOrg = 'deemons' //注册的用户名
groupId = 'com.deemons.dor' //引用时第一部分
artifactId = 'dor' //引用时的第二部分
publishVersion = '0.2.0' //引用时的第三部分,版本号
desc = 'android network'//描述
website = 'https://github.com/Deemonser/Dor'//项目地址
}

并且,需要忽略错误信息:

1
2
3
4
5
6
android {
lintOptions {
abortOnError false
}
}

完成上面的配置后,就可以通过命令上传项目到 Bintray 。


3.提交项目到 Bintray

执行下面这个命令

1
./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false

替换里面的 BINTRAY_USERNAME (注册的用户名) 和 BINTRAY_KEY (分配的 API_Key)。

如果没报错,并且看到BUILD SUCCESS,就表示上传成功了。

在 mac 下,如果出现拒绝该命令./gradlew: Permission denied,可以先运行 chmod +x gradlew

这时候在自己的 Bintray 上,点击前面创建的 maven 仓库。

maven 仓库

可以看到发布上来的 library 了

上传的 library


4.将 Bintray 的项目发布到 JCenter

点击刚刚上传的项目,看到下面的详细信息。

发布到 JCenter

这时候,点击右下角的 Add to JCenter 按钮后,跳转到一个提交页面。

然后什么也不做,直接点击Send。

然后就是漫长的等待Bintrary 的审核,如果请求审核通过,会收到一封邮件。

最后就是测试 一行代码 依赖。

如果成功了,那就大功告成啦~


本地仓库

远程依赖的方式,不仅仅适用于上面 JCenter 和 Maven Central 两个常见的远程库,其实我们自己也可以创建一个本地的依赖库,区别就在于,一个是远程云端仓库,另一个是本地自建的仓库,但他们用法相同。

本地仓库路径

本地仓库路径有两个:

  • 构建时,指定 maven 在本地存储的地方。
  • maven本地仓库的默认位置:在用户的目录下.m2/repository/的仓库目录。

构建时,不论如何指定本地仓库,同时会在默认仓库会生成同样一份依赖库。


指定本地仓库路径

自定义本地路径

1
2
3
4
5
6
repositories {
//绝对路径
maven { url '/Users/deemons/.m2/repository' }
//相对路径
//maven { url uri('../myRepo') }
}

默认本地路径:

1
2
3
repositories {
mavenLocal()//用户的目录下.m2/repository/的仓库目录
}


发布本地库

在 Library 的 gradle.build 文件中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
apply plugin: 'maven'
uploadArchives{
repositories.mavenDeployer{
// 本地仓库路径
repository(url:"file:/Users/deemons/.m2/repository")
// 唯一标识
pom.groupId = "com.android.test"
// 项目名称
pom.artifactId = "test"
// 版本号
pom.version = "1.0.0"
}
}

然后,在 AS 右侧 gradle 栏中,找到 uploadArchives 这个Task,点击执行。

在项目中使用的话,首先在根 build.gradle 文件中配置仓库路径

1
2
3
4
repositories {
...
mavenLocal()
}

其次,直接当做远程仓库去依赖:

1
compile 'com.android.test:test:1.0.0'


@aar 的作用

在项目中,经常看到这种依赖

1
2
compile 'com.android.support:appcompat-v7:22.1.1@aar'
compile 'com.android.support:support-v4:22.1.1@jar'

注意 @aar@jar ,我们一般不会用到两个东西,有时候加上也没什么问题,那这到底有什么作用?

翻墙查找 stack overflow ,终于找到了答案。

它有两个作用:

  • 如果不添加 @ 这种后缀,那么这个依赖库的类型将由其作者决定。如果添加@aar ,则表示指定这个依赖库的类型是 aar,同理,@jar 指定依赖库是 jar。
  • 添加 @ 后缀后,将不会下载此库的依赖,即禁止这个库传递依赖。

因此,为了确保添加 @ 后缀时,能完全下载此库的依赖关系树,应该这样编写:

1
2
3
compile ('com.android.support:appcompat-v7:22.1.1@aar') {
transitive = true
}


参考

新版Bintray-极简上传Library到JCenter

Android studio中使用Maven发布本地仓库

Why should I include a gradle dependency as @aar


坚持分享技术,但行好事,莫问前程 ~^o^~