Android 项目打包到 JCenter 的坑

2015-05-09

搜索下如何发布 Android 项目的信息,大部分都会找到这篇文章 Publishing Gradle Android Library to jCenter Repository,中文的指引可以看使用Gradle发布项目到JCenter仓库。不过,如果按照这些文章提供的 build.gradle,可能还会遇到一些坑。

调用 getBootClassPath() 出错

具体的错误信息是

Cannot call getBootClasspath() before setTargetInfo() is called.

这个是 gradle 的 android plugin 1.1.0 版本的 bug,见 Issue 152811 - android - Android Gradle Plugin 1.1.0 breaks Javadoc tasks。将插件更新到 1.1.1 以上版本就可以了。

classpath 'com.android.tools.build:gradle:1.1.2'

GBK 编码问题

Windows 用户可能会遇到这个问题,因为你将文件设置为 UTF-8 编码,javadoc 默认的是系统编码,Windows 就是 GBK 编码。所以一旦 java 文件中出现中文注释就会报错,提示无法映射的GBK编码

这个很容易解决,为 javadoc 指明编码就可以。在 gradle 可以这么做: options.encoding = "utf-8",具体的任务代码如下:

task javadoc(type: Javadoc) {
	...
    options.encoding = "utf-8"
	...
}

javadoc 的依赖问题

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

文章中的 javadoc 任务是这样的,重点在 classpath 那一行,这一行的意思是添加 Android 框架到 javadoc 的 classpath 中。不过,如果你的项目使用了其他第三方依赖,那 javadoc 任务很可能会执行失败的,因为上面的代码并没有这些添加第三方依赖到 classpath 中。比如我的项目,有下面这些依赖:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.code.gson:gson:2.3.1'
    compile 'com.android.support:gridlayout-v7:22.1.1'
    compile 'com.android.support:support-v4:22.1.1'
    compile 'com.android.support:appcompat-v7:22.1.1'
}

跑起上面的 javadoc 就会报错,类似下面的错误:

	xxxx.java:20: 错误: 找不到符号
    public static <T> T create(JsonElement json, Class<T> classOfModel) {
                               ^
  符号:   类 JsonElement
  位置: 类 xxxx

这时最简单的方法就是把第三方依赖加入 classpath:

 classpath += project.files(configurations.compile.files,android.getBootClasspath().join(File.pathSeparator))

但是仍然报错

Error:Could not find com.android.support:gridlayout-v7:22.1.1.
Searched in the following locations:
USER_HOME/.m2/repository/com/android/support/gridlayout-v7/22.1.1/gridlayout-v7-22.1.1.pom
USER_HOME/.m2/repository/com/android/support/gridlayout-v7/22.1.1/gridlayout-v7-22.1.1.jar
https://jcenter.bintray.com/com/android/support/gridlayout-v7/22.1.1/gridlayout-v7-22.1.1.pom
https://jcenter.bintray.com/com/android/support/gridlayout-v7/22.1.1/gridlayout-v7-22.1.1.jar
...

这时我的 repositories 是这样的:

allprojects {
    repositories {
        mavenLocal()
        jcenter()
    }
}

找不到 support 库,因为 support 库是 sdk 下载下来的,所以在这两个位置找不到也很正常。Android Plugin 自带的任务执行起来却不会报错,想必是做了特殊处理。

sdk 目录下也有个 maven repository,就是那些 support libs 所在的位置。

ANDROID_HOME\extras\android\m2repository

加进去再试一下

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream()) // local.properties 有 sdk 的绝对位置
allprojects {
    repositories {
        maven {
            url properties.getProperty("sdk.dir")+"/extras/android/m2repository"
        }
        mavenLocal()
        jcenter()
    }
}

依然报错,这次是找到那些库了,但因为 sdk 目录下的库是 aar 格式的,javadoc 不支持。所以问题到这里近乎无解了,幸好我在 stackoverflow 找到另一个 android 生成 javadoc 的方法。稍加改写就可以生成 javadoc 为 maven 所用:

android.libraryVariants.all { variant ->
    println variant.javaCompile.classpath.files
    if(variant.name == 'release') { //我们只需 release 的 javadoc
        task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
            // title = ''
            // description = ''
            source = variant.javaCompile.source
            classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())
            options {
                encoding "utf-8"
                links "http://docs.oracle.com/javase/7/docs/api/"
                linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
            }
            exclude '**/BuildConfig.java'
            exclude '**/R.java'
        }
        task("javadoc${variant.name.capitalize()}Jar", type: Jar, dependsOn: "generate${variant.name.capitalize()}Javadoc") {
            classifier = 'javadoc'
            from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir
        }
        artifacts {
            archives tasks.getByName("javadoc${variant.name.capitalize()}Jar")
        }
    }
}

以 support-v4 为例,configurations.compilevariant.javaCompile.classpath 打印出来的位置是不同的,分别是

  • SDK_HOME\extras\android\m2repository\com\android\support\support-v4\22.1.1\support-v4-22.1.1.aar
  • PROJECT_HOME/MODULE/build/intermediates/exploded-aar/com.android.support/support-v4/22.1.1/jars/libs/internal_impl-22.1.1.jar

看来 Android Plugin 确实有特殊处理。生成 javadoc 没问题其他的也基本没有什么问题,最终的 build.gradlegist

关于 javadoc 的坑写得十分啰嗦,主要是想和大家分享一些 gradle 的使用经验,其实 gradle 并不困难,主要是 Android Plugin 缺乏文档又鲜有例子,所以折腾起来比较难受。Android Plugin 的用户指南是在 New Build System 而 DSL 文档则是在 Android Plug-in for Gradle 右边有个下载 DSL 文档按钮。Gradle 可看官方的用户指南 Gradle User Guide,我还有一个乱糟糟的笔记 这个不足为看了。

如何上传到 JCenter 这个按照一开始提及文章的操作应该是没什么问题的,反正我没遇到问题,成功上传了 lru-image。其实,不用上传到 jcenter 单单运行 install 任务, gradle 会在 maven 的本地仓库中生成工件(artifact),只需将 mavenLocal 添加到 repositories,我们可以像发布到 JCenter 一样引用自己的库,方便打包那些多个项目共享又不想发布的私有库。

allprojects {
    repositories {
        mavenLocal()
        jcenter()
    }
}

Java 8 doclint 导致打包失败

把下面代码加入 build.gradle 后面:

if (JavaVersion.current().isJava8Compatible()) {
    allprojects {
        tasks.withType(Javadoc) {
            options.addStringOption('Xdoclint:none', '-quiet')
        }
    }
}

Stephen Colebourne’s blog: Turning off doclint in JDK 8 Javadoc

上一篇:手伤回顾 下一篇:分享我的 Android Studio Emacs 风格快捷键
keyboard_arrow_up