巧用 GitHub 创建自己的私人 Maven 仓库,及一些开发Library的建议

2014年中的时候,当时国内使用 Android Studio 的人还没有很多,很多人还没处理尝鲜的时候我开始把公司的项目迁移到 Android Studio 上了,开始了挺长一段踩坑的日子,开始接触到了 Gradle,才开始了解到使用它来管理项目的依赖库,由于在过程中有不少第三方库是没有将依赖包发布到 jCenter / Maven Central ,而且个人并不太喜欢把一整个开源项目添加到项目中,导致经常使用一些非官方仓库,从而可能给后续维护带来一些问题。

例如:

  • 依赖库可能有被做修改导致产生不必要的 Bug
  • 依赖库被作者从仓库中删掉
  • 依赖库更新不及时,升级依赖库麻烦
  • 后续跟进的开发者无法得知依赖库的来源
  • 等等一系统问题~

不地可以通过以下两个解决方案解决:

  1. 给作者提 issues 让作者将库提交到 jCenter / Maven Central
  2. 自己 fork 一份代码后提交到 JitPack

其实在过程中一真会出现一些仓库地址的 URL 是 GitHub 的地址。
例如 Emojicon 库,现在最新版本已经发布到 jCenter 了:

build.gradle

1
2
3
4
5
6
7
8
9
...

allprojects {
repositories {
maven { url 'https://raw.githubusercontent.com/rockerhieu/mvn-repo/master/' }
jcenter()
}
}
...

app/build.gradle

1
2
3
4
5
6
...

dependencies {
...
compile 'com.rockerhieu.emojicon:library:1.2'
}

最终定位到了这个仓库 https://github.com/Goddchen/mvn-repo,后来对此进行了一些研究,了解到如何使用公共的 Git 仓库发布依赖库,后面我就把一些常用的库自己编译发布到自己的 GitHub 的 mvn-repo 仓库上,同样达到了相同的效果,并且更可控。

发布一个依赖库到 mvn-repo

在 GitHub 创建 mvn-repo 仓库

这一步就不详述了,相信大家 Git 和 GitHub 使用肯定比我还熟练。

创建一个新的 Android Library 项目

由于本人已经不使用 Eclipse,所以肯定是使用 Android Studio。

创建一个 BlankApp 项目,这个项目是自己在开发过程中为了优化开发流程而写的(之前的版本 被废弃了,这个是重写版,还在构思中)

这是目录结构

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
.
├── BlankApp.iml
├── LICENSE
├── README.md
├── build
│   ├── generated
│   └── intermediates
├── build.gradle
├── examples
│   ├── build
│   ├── build.gradle
│   ├── examples.iml
│   ├── libs
│   ├── proguard-rules.pro
│   └── src
├── gradle
│   └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library
│   ├── build
│   ├── build.gradle
│   ├── gradle.properties
│   ├── library.iml
│   ├── libs
│   ├── proguard-rules.pro
│   └── src
├── local.properties
└── settings.gradle

library 就是一个 Android Library 的Module,examples 是一个Demo Module。

使用 gradle-mvn-push 编译脚本

使用了Chris Banes 大神开发的 gradle-mvn-push Gradle 脚本,Chris Banes大神是 Android-PullToRefreshPhotoView 等流行开源库的作者。

在项目根目录创建 gradle.properties 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
COMPILE_SDK_VERSION=23
BUILD_TOOLS_VERSION=23.0.2
MIN_SDK_VERSION=14
TARGET_SDK_VERSION=23

VERSION_NAME=0.0.1-alpha
VERSION_CODE=1
GROUP=org.blankapp

POM_DESCRIPTION=
POM_URL=https://github.com/lijy91/BlankApp
POM_SCM_URL=https://github.com/lijy91/BlankApp
POM_SCM_CONNECTION=scm:git@github.com:lijy91/BlankApp.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:lijy91/BlankApp.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=lijy91
POM_DEVELOPER_NAME=JianyingLi <lijy91@foxmail.com>

RELEASE_REPOSITORY_URL=file:///Users/Lijy91/Documents/Projects/mvn-repo/
SNAPSHOT_REPOSITORY_URL=file:///Users/Lijy91/Documents/Projects/mvn-repo/snapshots/

RELEASE_REPOSITORY_URLSNAPSHOT_REPOSITORY_URL 两个配置分别是正式版和快照版的本地路径。如果版本号后带有 -SNAPSHOT 编译后会发布到 SNAPSHOT_REPOSITORY_URL 相应的目录下。

library 创建 gradle.properties 文件

app/library/gradle.properties

1
2
3
POM_NAME=BlankApp Library
POM_ARTIFACT_ID=blankapp
POM_PACKAGING=aar

library 模块调用 gradle-mvn-push 脚本

library/build.gradle

1
2
... 
apply from: 'https://raw.githubusercontent.com/lijy91/gradle-mvn-push/master/gradle-mvn-push.gradle'

加在文件的未行即可,然后执行 Sync Now 即可

编译到本地 Git 仓库,并Push到远程仓库

Build

1
$ ./gradlew clean build uploadArchives

执行些命令后,会在 /Users/Lijy91/Documents/Projects/mvn-repo/ 创建相关的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.
├── README.md
└── org
└── blankapp
├── blankapp
│   ├── 0.0.1-alpha
│   │   ├── blankapp-0.0.1-alpha-javadoc.jar
│   │   ├── blankapp-0.0.1-alpha-javadoc.jar.md5
│   │   ├── blankapp-0.0.1-alpha-javadoc.jar.sha1
│   │   ├── blankapp-0.0.1-alpha-sources.jar
│   │   ├── blankapp-0.0.1-alpha-sources.jar.md5
│   │   ├── blankapp-0.0.1-alpha-sources.jar.sha1
│   │   ├── blankapp-0.0.1-alpha.aar
│   │   ├── blankapp-0.0.1-alpha.aar.md5
│   │   ├── blankapp-0.0.1-alpha.aar.sha1
│   │   ├── blankapp-0.0.1-alpha.pom
│   │   ├── blankapp-0.0.1-alpha.pom.md5
│   │   └── blankapp-0.0.1-alpha.pom.sha1
│   ├── maven-metadata.xml
│   ├── maven-metadata.xml.md5
│   └── maven-metadata.xml.sha1
└── ...

Push

1
2
3
$ git add .
$ git commit -am "Add BlankApp Library"
$ git push -u origin master

到此,一个私人的Maven仓库已经创建完成

如何使用 mvn-repo

1、只需将 mvn-repo 地址添加到您的 build.gradle 文件:

1
2
3
4
repositories {
maven { url 'https://raw.githubusercontent.com/lijy91/mvn-repo/master/' }
jcenter()
}

2、在要集成的项目中的 build.gradle 中添加依赖,如下:

1
2
3
dependencies {
compile 'org.blankapp:blankapp:0.0.1-alpha@aar'
}

对于自己开发第三方库的一些建议

尽量不依赖第三方库

我最早写的一个基础框架库,就引用了一些个人认为比较好用的 JSON 解析库,ORM库,后来应用在其他项目的时候发现有一些是在这个项目中是使用不到的,造成了耦合度过大,后面维护难度过大。所以建议尽量不要依赖,或者参考最后面两个建议的做法。

ARTIFACT_ID 不要使用 librarysdk等名称

如果 ArtifactId 使用的是 library,sdk 这种名字,编译后生成的相关文件就会是 library.jar、sdk.jar 这种文件,不便于分辨。

例如 FIR.im 的 SDK

1
compile 'im.fir:sdk:latest.integration@aar'

最终在 Android Studio 看到的 External Libraries 就会出现一个sdk.jar 的文件,如果你引用了多个 ArtifactId 为 library 的类库,那就会出现 library.jarlibrary1.jar 这样的文件,根本无法分辨。

后来在我的建议下修改为

1
compile 'im.fir:fir-sdk:latest.integration@aar'

多模块

以下是之前我对 Ping++ SDK 提的一些建议
将基础部分封装为一个sdk 模块,并提供统一的接口,然后支付宝,微信支付,百度钱包等根据sdk模块提供的接口进行开发,后面如果用户需要接入或者升级支付平台的内容,即可以通过在 build.gradle 文件添加相应平台的依赖即可。

在 build.gradle 使用时类似这样子

1
2
3
compile 'com.pingxx:pingxx-sdk:1.0.+'
compile 'com.pingxx:pingxx-alipay:1.0.+'
compile 'com.pingxx:pingxx-wxpay:1.0.+'

避免引用后项目出现重复功能的库

这个问题估计是大多数项目都有出现的问题,例如有我的项目使用了 Fastjson 作为我的JSON解析库,但我使用的HTTP库 Retrofit 1.x 却使用 Gson,这个时候我的项目里就引用了两个同样功能的库,而且在我们不注意的时候,包括HTTP库,图片加载库等等都有可能会有重叠,会大大增加我们APK的大小。

后来Retrofit2解决了这个问题,它把数据转换为独立出来了,我们可以自由选择自己的数据转换库,类似这样

1
2
3
4
5
6
7
com.squareup.retrofit2:converter-gson      // Gson
com.squareup.retrofit2:converter-jackson // Jackson
com.squareup.retrofit2:converter-moshi // Moshi
com.squareup.retrofit2:converter-protobuf // Protobuf
com.squareup.retrofit2:converter-wire // Wire
com.squareup.retrofit2:converter-simplexml // Simple XML
com.squareup.retrofit2:converter-scalars // Scalars (primitives, boxed, and String)

Enjoy~