Android 專案打包到 JCenter 的坑

weixin_33728268發表於2015-05-14

搜尋下如何釋出 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()
    }
}

原文連結:https://dourok.info/2015/05/09/trouble-of-publish-aar/

相關文章