1. 程式人生 > >Gradle配置:Android Library打包至Maven倉庫

Gradle配置:Android Library打包至Maven倉庫

開發Android Library專案,需要把aar包給商戶app接入,如果按照原始的方法手動給包的話,那就太low了。而且Library中dependencies和proguard等都要商戶app再寫一遍,這實在是和low,對於商戶來說,其實只要一句簡單的程式碼就好了。

compile 'xxx.xx.xx:xxx:3.x'

先直接上程式碼:
project下的build.gradle:

buildscript {
    repositories {
        jcenter()
        maven { url "https://plugins.gradle.org/m2/"
} } dependencies { classpath 'com.android.tools.build:gradle:2.1.3' classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.4.10" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } }

library的build.gradle:

apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'

android {
    publishNonDefault true
    compileSdkVersion 23
    buildToolsVersion '23.0.3'

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 23
        //在打包的aar中加入proguard檔案
consumerProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug{ } } libraryVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.aar')) { def fileName = getArtifactFileName() output.outputFile = new File(outputFile.parent, fileName) } } } } dependencies { compile 'com.android.support:support-v4:23.0.1' compile 'de.greenrobot:eventbus:2.4.0' compile files('libs/other-library.jar') } repositories { maven { url "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } } publishing { publications { aar(MavenPublication) { groupId = GROUP artifactId POM_ARTIFACT_ID version = VERSION_NAME artifact "${project.buildDir}/outputs/aar/${getArtifactFileName()}" //generate POM file pom.withXml { def root = asNode() def dependenciesNode = root.appendNode('dependencies') def repositoriesNode = root.appendNode('repositories') //Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each configurations.compile.allDependencies.each { if (it.group != null) { def dependencyNode = dependenciesNode.appendNode('dependency') dependencyNode.appendNode('groupId', it.group) dependencyNode.appendNode('artifactId', it.name) dependencyNode.appendNode('version', it.version) } } //add the repositories exclude local repositories,such as file:/D:/AndroidSDK/extras/android/m2repository/ project.repositories.each { if (!it.url.toString().startsWith('file')) { def repositoryNode = repositoriesNode.appendNode('repository') repositoryNode.appendNode('url', it.url) repositoryNode.appendNode('name', it.name) repositoryNode.appendNode('releases').appendNode("enabled",true) repositoryNode.appendNode('snapshots').appendNode("enabled",false) } } } } } } artifactory { contextUrl = REPOSITORY_URL publish { repository { // The Artifactory repository key to publish to repoKey = VERSION_NAME.contains("SNAPSHOT") ? SNAPSHOT_REPOSITORY_KEY : RELEASE_REPOSITORY_KEY username = ARTIFACTORY_USERNAME password = ARTIFACTORY_PASSWORD } defaults { // Tell the Artifactory Plugin which artifacts should be published to Artifactory. publications('aar') publishArtifacts = true // Properties to be attached to the published artifacts. properties = ['build.status': "$it.project.status".toString()] publishPom = true publishIvy = false } } } def getArtifactFileName() { return "${POM_ARTIFACT_ID}-${VERSION_NAME}.aar" } //在執行artifactoryPublish之前需要生成上傳Maven倉庫的Pom文件。 artifactoryPublish {}.dependsOn(getTasks().getByPath(":sdk:generatePomFileForAarPublication"))

gradle.properties:

#artifactory configs
VERSION_NAME=3.7.0-SNAPSHOT
#VERSION_NAME=3.7.0
VERSION_CODE=31
GROUP=com.example.yourproject
POM_ARTIFACT_ID=libraryname
POM_NAME=libraryname
POM_PACKAGING=aar
#你要上傳的maven倉庫地址
REPOSITORY_URL=http://mvn.hz.com/artifactory
#倉庫的具體兩個小位置,一個是snapshot和releases,這兩個的區別自行上網查詢。snapshot是快照,可以存放用於測試的包,release就是正式釋出的包
SNAPSHOT_REPOSITORY_KEY=libs-snapshots
RELEASE_REPOSITORY_KEY=libs-releases
#在gradle.properties中增加string變數不需要'或者",直接填寫內容即可。這兩個變數是上傳maven倉庫的賬戶和密碼,在我的例子中上傳不需要賬戶密碼,就置為空了
ARTIFACTORY_USERNAME=
ARTIFACTORY_PASSWORD=

程式碼已上完,分批來看下:

apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'

這裡是我們要使用的外掛,主要使用這兩個外掛來上傳至maven倉庫。

consumerProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

這句是在打的包中加入混淆規則,這樣商戶app在接入的時候,不用再去關心你的library的混淆規則。如果你不加這句,那麼你要告訴你商戶app要keep住哪些。。。

libraryVariants.all { variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.aar')) {
                def fileName = getArtifactFileName()
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }
    }

def getArtifactFileName() {
    return "${POM_ARTIFACT_ID}-${VERSION_NAME}.aar"
}

這句只是修改每次編譯生成的aar包的名字。上述兩部分組成。

下面分兩部分,第一步是生成pom文件和aar包。第二部是將pom和aar包上傳至maven倉庫。
先看下第一步

publishing {
    publications {
        aar(MavenPublication) {
            groupId = GROUP
            artifactId POM_ARTIFACT_ID
            version = VERSION_NAME
            artifact "${project.buildDir}/outputs/aar/${getArtifactFileName()}"
            //generate POM file
            pom.withXml {
                def root = asNode()
                def dependenciesNode = root.appendNode('dependencies')
                def repositoriesNode = root.appendNode('repositories')
                //Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each
                configurations.compile.allDependencies.each {
                    if (it.group != null) {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', it.group)
                        dependencyNode.appendNode('artifactId', it.name)
                        dependencyNode.appendNode('version', it.version)
                    }
                }
                //add the repositories exclude local repositories,such as file:/D:/AndroidSDK/extras/android/m2repository/
                project.repositories.each {
                    if (!it.url.toString().startsWith('file')) {
                        def repositoryNode = repositoriesNode.appendNode('repository')
                        repositoryNode.appendNode('url', it.url)
                        repositoryNode.appendNode('name', it.name)
                        repositoryNode.appendNode('releases').appendNode("enabled",true)
                        repositoryNode.appendNode('snapshots').appendNode("enabled",false)
                    }
                }
            }
        }
    }
}

這裡會生成pom文件,pom主要就是對你的library的一個描述,看個例子:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.yourproject</groupId>
  <artifactId>libraryname</artifactId>
  <version>3.7.0-SNAPSHOT</version>
  <packaging>aar</packaging>
  <dependencies>
    <dependency>
      <groupId>com.android.support</groupId>
      <artifactId>support-v4</artifactId>
      <version>23.0.1</version>
    </dependency>
    <dependency>
      <groupId>de.greenrobot</groupId>
      <artifactId>eventbus</artifactId>
      <version>2.4.0</version>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <url>https://jcenter.bintray.com/</url>
      <name>BintrayJCenter</name>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
</project>

所以在我們的例子中加入了library依賴的dependency和repository。如果不加dependency的話,在商戶app中需要再加入library的依賴項。
!!!!但是!!!!加入repository好像沒用,我依舊要在商戶app中加入repository,目前還沒找到為什麼,讀者若知道和我說下!!!!
生成aar的話,就呼叫gradle的assembleRelease就好了。

第二步上傳至maven:

artifactory {
    contextUrl = REPOSITORY_URL
    publish {
        repository {
            // The Artifactory repository key to publish to
            repoKey = VERSION_NAME.contains("SNAPSHOT") ? SNAPSHOT_REPOSITORY_KEY : RELEASE_REPOSITORY_KEY
            username = ARTIFACTORY_USERNAME
            password = ARTIFACTORY_PASSWORD
        }
        defaults {
            // Tell the Artifactory Plugin which artifacts should be published to Artifactory.
            publications('aar')
            publishArtifacts = true
            // Properties to be attached to the published artifacts.
            properties = ['build.status': "$it.project.status".toString()]
            publishPom = true
            publishIvy = false
        }
    }
}

其實也很簡單,就是指明倉庫地址,賬戶密碼,型別等就好了。

這時候sync下你的程式碼,會發現在gradle task中多了幾個task。
這裡寫圖片描述
artifactoryPublish就是上傳aar到maven中,也就是我們剛剛說的第二步。
generatePomFileForAarPublication就是生成pom文件,也就是我們剛剛說的第一步。
後面三個我就不太清楚具體是幹嘛的。

如果你直接執行artifactoryPublish的話,可能會出錯,因為你可能還沒生成pom文件。所以我在build.gradle中加了一句依賴:

//在執行artifactoryPublish之前需要生成上傳Maven倉庫的Pom文件。
artifactoryPublish {}.dependsOn(getTasks().getByPath(":sdk:generatePomFileForAarPublication"))

這句話的意思就是在執行artifactoryPublish任務之前,需要執行generatePomFileForAarPublication。這樣就不會出錯了。

好了,現在雙擊artifactoryPublish任務進行上傳,看下結果:
這裡寫圖片描述

下面給出了引用的程式碼:

compile(group: 'com.example.yourproject', name: 'libraryname', version: '3.7.0-20161213.023523-29', ext: 'aar')

好了,在商戶app中只用加入這一句就好了。
加入之後,build之後你會發現剛剛library專案中的eventbus和support庫都會自動導進來了,而商戶app中卻不用宣告,是否很簡單易用呢?

接下來講下遇到的坑吧:
1.pom檔案中配置的repository不管用,就是說pom中的依賴項並不從我配置的repositories中尋找,所以別人加入你的aar的話,還需要在build.gradle中加入你使用的倉庫。
2.在repository節點中,有個屬性叫做updatePolicy,updatePolicy更新snapshot包的頻率,屬性有四個值always(實時更新) daily(每天更新) interval:xxx(隔xxx分鐘更新一次) never(從不更新) 預設為daily ,如果repository節點不起作用的話,那麼policy不起作用的話,如何你不更新版本號就在原來的版本上釋出的話,可能會拉取不到最新的包。
目前看到一種解決辦法是隻需執行一下mvn clean install 即可完成依賴更新,完成以上操作可完成無需更改版本釋出,依賴方也不需要更改pom。