Android studio 发布Android Library项目到JCenter

Posted Ruffian-痞子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android studio 发布Android Library项目到JCenter相关的知识,希望对你有一定的参考价值。

互联网的发展是非常迅猛的,刚刚觉得自己适应了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中的方法测试一下,能正确调用。没问题!你做到了

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

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

以上是关于Android studio 发布Android Library项目到JCenter的主要内容,如果未能解决你的问题,请参考以下文章

android studio有啥用

如何使用 Android Studio 在发布模式下调试 Android App

如何发布 Android .aar 源码让 Android Studio 自动找到它们?

Android Studio 将项目从 Eclipse 导入 Android Studio

Android SDK 未安装在 Android Studio 上

无法压缩 apk android android studio 2.2