Android studio 发布Android Library项目到JCenter

(本来这篇文章只是想当做笔记记录,下了班才写的,第二天起来看到几百个访问量,突然对生活充满了希望,受到了鼓舞,于是决定完善一下。____2016/05/31)

互联网的发展是非常迅猛的,刚刚觉得自己适应了eclipse的用法,突然发现它已经被淘汰了。

OK,今天不是来说eclipse和Android studio的褒贬。我们是来学习技术的。在做SDK相关的开发时发现一个问题,Android studio 使用第三方包超级简单方便。一行代码搞定。

compile ‘com.ruffian.utils.android:utilssdk:0.1.0’

这就可以把第三包(Library)导入到项目编译使用。我的天啊,这么神奇吗?回想起使用eclipse导入项目,当做依赖包使用的艰辛,是不是顿时觉得这种方式碉堡了。

这行神奇的代码背后影藏着什么呢?先问问自己

1.首先这个第三方包如何能为我所用?它在哪里?云服务器?本地?
2.这个第三方包的项目结构怎样?jar?apk?
3.如何能做到,让别人一行代码使用我们的Library包?

1.首先这个第三方包如何能为我所用?它在哪里?云服务器?本地?

通过测试发现,这个第三方包,存在云服务器上,compile 之后Android studio 会将代码下载到本地。通过以下方式查看文件位置

这里写图片描述

项目右键->Library Properties 就可以查看文件位置

这里写图片描述

2.这个第三方包的项目结构怎样?jar?apk?

在Library文件目录项看到三个文件夹,里面分别有一个文件,后缀是

  1. .pom
  2. .jar
  3. .aar

.pom后缀的文件是什么?网上解释:

.pom:Project Object Model,在maven1中叫做project.xml,到maven2后改为pom.xml。该文件用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。一个maven项目可以没有任何源代码,但必须包含pom文件。

打开 .pom 文件,可以看到是关于library项目的一些基本信息。(看来网上说的是真的)

这里写图片描述

.jar:不解释了,就是java/Android代码

.aar: 文件是啥?貌似听过,印象中,aar是 SDK的一种项目结构,使用studio打包。而我们使用eclipse处理SDK Library一般是一个完整的Android项目(包括资源文件)和jar文件,又听人说是属于Android的东西,还几乎只跟Android studio有关。网上是这么解释的:

(1) .aar:文件是在jar文件之上开发的。之所以有它是因为有些Android Library需要植入一些安卓特有的文件,比如AndroidManifest.xml,资源文件,Assets或者JNI。这些都不是jar文件的标准。

诶:这个好像说的通,当初刚开始做SDK开发的时候就是绞尽脑汁在想怎么解决Android资源文件打包的问题,代码打包成jar没问题,但是资源文件,和配置文件不行啊,看来aar的存在是合理的。网上还解释说:

(2) 因此aar文件就时发明出来包含所有这些东西的。总的来说它和jar一样只是普通的zip文件,不过具有不同的文件结构。jar文件以classes.jar的名字被嵌入到aar文件中。文件结构如下:

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

你说是就是啊,我不信呢,那么修改后缀为zip,并解压出来,看看里面什么状况

这里写图片描述

好像差不多是这样的哦,那就先这么认为吧。

3.如何能做到,让别人一行代码使用我们的Library包?

前面简单交代一下1,2两个问题。接下来说说我们一个普普通通的开发者如何做到看似高大上的行为。

其实Android Studio是从build.gradle里面定义的Maven 仓库服务器上下载library的。Apache Maven是Apache开发的一个工具,提供了用于贡献library的文件服务器。有两个标准的Android library文件服务器:jcenter 和 Maven Central。

jcenter 和 Maven Central

先了解一下这两个是什么东西

jcenter: jcenter是一个由 bintray.com维护的Maven仓库 。你可以在这里看到整个仓库的内容。

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

allprojects {
    repositories {
        jcenter()
    }
}

Maven Central: Maven Central 则是由sonatype.org维护的Maven仓库。你可以在这里看到整个仓库。

注:不管是jcenter还是Maven Central ,两者都是Maven仓库

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

projects {
    repositories {
        mavenCentral()
    }
}

注意,虽然jcenter和Maven Central 都是标准的 android library仓库,但是它们维护在完全不同的服务器上,由不同的人提供内容,两者之间毫无关系。在jcenter上有的可能 Maven Central 上没有,反之亦然。

除了两个标准的服务器之外,如果我们使用的library的作者是把该library放在自己的服务器上,我们还可以自己定义特有的Maven仓库服务器。Twitter的Fabric.io 就是这种情况,它们在https://maven.fabric.io/public上维护了一个自己的Maven仓库。如果你想使用Fabric.io的library,你必须自己如下定义仓库的url。

repositories {
    maven { url 'https://maven.fabric.io/public' }
}

然后在里面使用相同的方法获取一个library。

dependencies {
    compile 'com.crashlytics.sdk.android:crashlytics:2.2.4@aar'
}

但是将library上传到标准的服务器与自建服务器,哪种方法更好呢?当然是前者。如果将我们的library公开,其他开发者除了一行定义依赖名的代码之外不需要定义任何东西。

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()。

有许多将Maven Central替换成jcenter的理由,下面是几个主要的原因。

- jcenter通过CDN发送library,开发者可以享受到更快的下载体验。

- jcenter是全世界最大的Java仓库,因此在Maven Central 上有的,在jcenter上也极有可能有。换句话说jcenter是Maven Central的超集。

- 上传library到仓库很简单,不需要像在 Maven Central上做很多复杂的事情。

- 友好的用户界面

- 如果你想把library上传到 Maven Central ,你可以在bintray网站上直接点击一个按钮就能实现。

这么看起来好像jcenter更有优势一点,而且Android studio都将它作为默认的了,关键是它容易实现,好吧,那就把重心放在jcenter。

关于如何将Android Library发布到JCenter的操作可以查看下面这篇文章

https://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en

卧槽,这么坑爹,丢给你们一个英文网站就算完了?那好咯,给多一个中文的翻译

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0623/3097.html

这是一篇好文章,能看懂的话基本都知道怎么回事了,列举的条条是道,但是好像有点坑爹,怎么弄都跑不起来,或者各种报错。程序员嘛,谁跟你讲道理,跑起来才是硬道理。好吧,下面是我尝试了之后做了一下总结跟改进。反正我是成功实现了。我跑起来了,怎么样。

  1. 第1部分:在bintray上创建package
  2. 第2部分:准备一个Android Studio项目
  3. 第3部分:把library上传到你的bintray空间
  4. 第4部分:测试使用

第1部分:可以参考上面链接文章操作,注册账号,创建包名。图文并茂真的可以参考,就不在重复

第2部分:创建一个Android studio项目,然后添加一个module,做为library项目

2.1创建项目

这里写图片描述

2.2配置项目[ 这个是最关键的啦 ](跳过功能代码部分,可以写一个最简单的log类)

为了快速上手,这里直接给出几个配置文件的代码
1.在library模块中添加以下3个文件
1.1 project.properties

#project
project.name=UtilsSdk
project.groupId=com.ruffian.utils.android
project.artifactId=utilssdk
project.versionName=0.1.0
project.packaging=aar
#这两个值可以随便找一个项目
project.siteUrl=https://github.com/adamrocker/volley
project.gitUrl=https://github.com/adamrocker/volley.git

#javadoc
javadoc.name=UtilsSdk

解释一下文件(记得实际项目中一定要替换成开发者自己的项目名称,包名等等)

project.name:项目名称
project.groupId:项目组ID,通常情况下如果你的包名为com.example.test,那么项目组ID就是com.example
project.artifactId:项目ID,通常情况下如果你的包名为com.example.test,那么项目ID就是test
project.packaging:包类型,Android库是aar
project.siteUrl:项目官方网站的地址,没有的话就用Github上的地址,例如:https://github.com/adamrocker/volley
project.gitUrl:项目的Git地址,例如:https://github.com/adamrocker/volley.git
javadoc.name:生成的javadoc打开后主页显示的名称,通常跟项目名称一样即可

1.2 local.properties

#bintray
bintray.user=ruffian
bintray.apikey=******************

#developer
developer.id=Ruffian
developer.name=RuffianZhong
developer.email=RuffianZhong@gmail.com

解释一下文件(记得实际项目中一定要替换成开发者自己的项目名称,包名等等)

bintray.user:你的Bintray的用户名
bintray.apikey:你的的Bintray的API Key
developer.id:通常是你在开源社区的昵称
developer.name:你的姓名
developer.email:你的邮箱

1.3 bintrayUpload.gradle

apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'

// load properties
Properties properties = new Properties()
File localPropertiesFile = project.file("local.properties");
if (localPropertiesFile.exists()) {
    properties.load(localPropertiesFile.newDataInputStream())
}
File projectPropertiesFile = project.file("project.properties");
if (projectPropertiesFile.exists()) {
    properties.load(projectPropertiesFile.newDataInputStream())
}

// read properties
def projectName = properties.getProperty("project.name")
def projectGroupId = properties.getProperty("project.groupId")
def projectArtifactId = properties.getProperty("project.artifactId")
def projectVersionName = properties.getProperty("project.versionName")
def projectPackaging = properties.getProperty("project.packaging")
def projectSiteUrl = properties.getProperty("project.siteUrl")
def projectGitUrl = properties.getProperty("project.gitUrl")

def developerId = properties.getProperty("developer.id")
def developerName = properties.getProperty("developer.name")
def developerEmail = properties.getProperty("developer.email")

def bintrayUser = properties.getProperty("bintray.user")
def bintrayApikey = properties.getProperty("bintray.apikey")

def javadocName = properties.getProperty("javadoc.name")

group = projectGroupId

// This generates POM.xml with proper parameters
install {
    repositories.mavenInstaller {
        pom {
            project {
                name projectName
                groupId projectGroupId
                artifactId projectArtifactId
                version projectVersionName
                packaging projectPackaging
                url projectSiteUrl
                licenses {
                    license {
                        name 'The Apache Software License, Version 2.0'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }
                developers {
                    developer {
                        id developerId
                        name developerName
                        email developerEmail
                    }
                }
                scm {
                    connection projectGitUrl
                    developerConnection projectGitUrl
                    url projectSiteUrl
                }
            }
        }
    }
}

// This generates sources.jar
task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    classifier = 'sources'
}

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

// This generates javadoc.jar
task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

artifacts {
    archives javadocJar
    archives sourcesJar
}

// javadoc configuration
javadoc {
    options {
        encoding "UTF-8"
        charSet 'UTF-8'
        author true
        version projectVersionName
        links "http://docs.oracle.com/javase/7/docs/api"
        title javadocName
    }
}

// bintray configuration
bintray {
    user = bintrayUser
    key = bintrayApikey
    configurations = ['archives']
    pkg {
        repo = "maven"
        name = projectName
        websiteUrl = projectSiteUrl
        vcsUrl = projectGitUrl
        licenses = ["Apache-2.0"]
        publish = true
    }
}

bintrayUpload.gradle这个文件不用解释,不用修改,直接复制

2.在library目录下的build.gradle文件 最后一行 添加代码

apply from: "bintrayUpload.gradle"

引用本地的 “bintrayUpload.gradle” 文件。这个文件的代码直接复制到项目中即可,不需要修改。

3.在项目目录下的build.gradle文件中添加所需插件

 dependencies {       
        classpath 'com.android.tools.build:gradle:1.2.3'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
    }

解释一下

android-maven-gradle-plugin插件是用来打包Maven所需文件的
gradle-bintray-plugin插件是用来将生成的Maven所需文件上传到Bintray的

好了,精华都在那几个配置文件里面了,前提是在bintray上面已经建好了账号。填好包名
接下来就要上传代码到bintray中了。

第3部分:把library上传到你的bintray空间

3.1请到Android Studio的终端(Terminal)选项卡

这里写图片描述

第一步是检查代码的正确性,以及编译library文件(aar,pom等等),输入下面的命令:

gradlew install

如果没有什么问题,会显示:

BUILD SUCCESSFUL

现在我们已经成功一半了。下一步是上传编译的文件到bintray,使用如下的命令:

gradlew bintrayUpload

如果显示如下你就大声问问周围的人:“你看我吊不!”,然后去在bintray的网页上检查一下你的package

SUCCESSFUL

但是你怎么可能有我那么吊,你肯定一直在报错,哈哈。报错就对了。

常见问题

Error:Cause: org/gradle/api/publication/maven/internal/DefaultMavenFactory
这时候你只需将android-maven-gradle-plugin 插件版本改为
classpath ‘com.github.dcendents:android-maven-gradle-plugin:1.3’ 即可

—我是分隔符—

You are using JDK version ‘java version “1.7.0_71”’. Some versions of JDK 1.7 (e.g. 1.7.0_10) may cause class loading errors in Gradle.Please update to a newer version (e.g. 1.7.0_67)
同样的你只需要将android-maven-gradle-plugin 插件版本改为
classpath ‘com.github.dcendents:android-maven-gradle-plugin:1.3’ 即可

—我是分隔符—

No value has been specified for property ‘packageName’.
出这个问题肯定是看文档不仔细,把project.properties文件放在了项目根目录下,一定要放在mudule目录下才可以

—我是分隔符—

Could not upload to ‘https://.pom’: HTTP/1.1 400 Bad Request [message:Unable to upload files: Maven group, artifact or version defined in the pom file do not match the file path ‘***.pom’]
这个问题一般都是你的module的名字和你在project.properties 配置的artifactId不一致导致的,改成一样的即可

估计这几个问题之后就应该可以看见SUCCESS了。现在看看bintray网站上面的变化

1.
这里写图片描述
2.
这里写图片描述
3.
这里写图片描述

终于把代码放到了网上,现在需要将代码从bintray同步到jcenter。这一步很简单,查看链接中的文章有说明。

那现在是不是就可以实现1行代码实现吊炸天的操作?哪有那么容易,随便弄一下就想一行代码搞定?
得2行代码!!

因为代码从bintray同步到jcenter需要几个小时的时间,但是我已经等不及想看看自己成果,那么就多写一行代码配置一下library路径就可以了

新建一个Android studio 测试项目。

在项目根目录下的build.gradle中添加,因为项目还没有发布到jcenter,相当于现在是在自己的服务器维护这个library

allprojects {
    repositories {
        jcenter(){
            //开发者bintray的路径,当项目发布到jcenter之后就可以去除这行代码
            url 'https://dl.bintray.com/ruffian/maven/'
        }
    }
}

引入Library项目,在APP目录下的build.gradle中添加

dependencies {
    //utils
    compile 'com.ruffian.utils.android:utilssdk:0.1.0'
}

sync now

ok,搞定,在activity中调用Library中的方法测试一下,能正确调用。没问题!你做到了

备注:文章中有些想法来自网络,一时间找不到原文链接,还望原作者见谅

有什么问题可以留言讨论,共同进步

猜你喜欢

转载自blog.csdn.net/u014702653/article/details/51541587