安卓(Android) 發(fā)布 aar 到 maven 服務器或是本地 Repo

1. 創(chuàng)建修改已有代碼成為安卓庫項目

大家手上都或多或少有些項目可以封裝成 aar 共享給其他同學?;蚴枪鞠嚓P的庫需要封裝并發(fā)布給項目使用。你可以創(chuàng)建一個安卓 library工程,可以參考官方文檔 Create an Android library。
這個步驟就不在具體細講,不是本文的主題。
更新記錄:

  1. 2018-12-06:修改maven服務器賬號,密碼,版本號的獲取方式。解決賬號保護的問題,針對使用CI/CD進行發(fā)布。

2. 修改庫工程的 build.gradle 文件

找到你的 library 工程的 build.gradle 文件。
下圖是我的私人工程的文件目錄結構,其中 audiocore 是 android library project。


打開 audiocore/build.gradle 在尾部追加如下代碼:

apply plugin: 'maven-publish'

def getRepositoryUsername() {
  Properties properties = new Properties()
  properties.load(project.rootProject.file('local.properties').newInputStream())

  def MAVEN_USERNAME_LOCAL = properties.getProperty('MAVEN_USERNAME')
  return hasProperty('MAVEN_USERNAME') ? MAVEN_USERNAME : MAVEN_USERNAME_LOCAL;
}

def getRepositoryPassword() {
  Properties properties = new Properties()
  properties.load(project.rootProject.file('local.properties').newInputStream())

  def MAVEN_PASSWORD_LOCAL = properties.getProperty('MAVEN_PASSWORD')
  return hasProperty('MAVEN_PASSWORD') ? MAVEN_PASSWORD : MAVEN_PASSWORD_LOCAL
}

def getVersionName() {
  def local_version_name = "version-default-SNAPSHOT"
  if (hasProperty("VERSION_NAME")) {
      local_version_name = getProperty("VERSION_NAME")
  }
  return local_version_name
}

task androidJavadocs(type: Javadoc) {
  failOnError false
  source = android.sourceSets.main.java.srcDirs
  classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
  android.libraryVariants.all { variant ->
    if (variant.name == 'release') {
        owner.classpath += variant.javaCompile.classpath
    }
  }
  exclude '**/R.html', '**/R.*.html', '**/index.html'
}

task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
  classifier = 'javadoc'
  from androidJavadocs.destinationDir
}

task androidSourcesJar(type: Jar) {
  classifier = 'sources'
  from android.sourceSets.main.java.srcDirs
}

publishing {
  publications {
  Production(MavenPublication) {
    artifactId = POM_ARTIFACT_ID
    groupId = POM_GROUP_ID
    version = getVersionName()

    artifact bundleRelease
    artifact androidJavadocsJar
    artifact androidSourcesJar

    // The publication doesn't know about our dependencies, so we have to manually add them to the pom
    pom.withXml {

        final dependenciesNode = asNode().appendNode('dependencies')

        ext.addDependency = { Dependency dep, String scope ->
            if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
                return // ignore invalid dependencies

            final dependencyNode = dependenciesNode.appendNode('dependency')
            dependencyNode.appendNode('groupId', dep.group)
            dependencyNode.appendNode('artifactId', dep.name)
            dependencyNode.appendNode('version', dep.version)
            dependencyNode.appendNode('scope', scope)

            if (!dep.transitive) {
                // If this dependency is transitive, we should force exclude all its dependencies them from the POM
                final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
                exclusionNode.appendNode('groupId', '*')
                exclusionNode.appendNode('artifactId', '*')
            } else if (!dep.properties.excludeRules.empty) {
                // Otherwise add specified exclude rules
                final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
                dep.properties.excludeRules.each { ExcludeRule rule ->
                    exclusionNode.appendNode('groupId', rule.group ?: '*')
                    exclusionNode.appendNode('artifactId', rule.module ?: '*')
                }
            }
        }

        // List all "compile" dependencies (for old Gradle)
        configurations.compile.getAllDependencies().each { dep -> addDependency(dep, "compile") }
        // List all "api" dependencies (for new Gradle) as "compile" dependencies
        configurations.api.getAllDependencies().each { dep -> addDependency(dep, "compile") }
        // List all "implementation" dependencies (for new Gradle) as "runtime" dependencies
        configurations.implementation.getAllDependencies().each { dep -> addDependency(dep, "runtime") }
    }
  }

}

repositories {
  maven {
    // change URLs to point to your repos, e.g. http://my.org/repo
    //  def releasesRepoUrl = "$buildDir/repos/releases"
    //  def snapshotsRepoUrl = "$buildDir/repos/snapshots"
    // 測試階段可以使用以上兩個本地地址變量
    def releasesRepoUrl = "http://my.org/repo/movie-release" // change to your self repo url
    def snapshotsRepoUrl = "http://my.org/repo/movie-snapshot"  // change to your self snapshot repo url
    url = getVersionName().endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
    credentials {
        username getRepositoryUsername() 
        password getRepositoryPassword()
      }
    }
  }
}

使用上面代碼會需要3個變量,我們將他們添加到 gradle.properties 文件里面:

POM_ARTIFACT_ID=audiocore
POM_GROUP_ID=com.javan.movie
VERSION_NAME=0.1.0.2-SNAPSHOT  // 如果發(fā)布非 SNAPSHOT快照版本的時候刪除尾部版本的 -SNAPSHOT

3. 執(zhí)行發(fā)布命令

打開 Gradle 控制窗口如下圖:


雙擊執(zhí)行 publish 的 task。
如果成功會出現如下日志:

4. 測試發(fā)布是否成功

在 app 工程的 build.gradle 修改依賴的寫法:

dependencies {
  implementation fileTree(dir: 'libs', include: ['*.jar'])
  // implementation project(':audiocore')
  implementation "com.javan.movie:audiocore:0.1.0.2-SNAPSHOT" //修改此處的 group id、庫名稱、 version name
  implementation 'com.android.support:appcompat-v7:27.0.2'
}

通過下工程如何通過,說明整體已經跑通。

5. 優(yōu)化配置

從上面的配置上有個缺陷,它會暴露你的 Maven 服務器的賬號和密碼。而且這個賬號密碼也不適合提交到代碼倉庫里面。目前有兩種解決方案:

1. 將私有的Maven服務器上傳權限關閉賬號驗證

簡單說就是任何人都可以往你的私人服務器發(fā)布AAR或JAR,取消賬號驗證。修改配置文件

repositories {
    maven {
        // change URLs to point to your repos, e.g. http://my.org/repo
        //  def releasesRepoUrl = "$buildDir/repos/releases"
        //  def snapshotsRepoUrl = "$buildDir/repos/snapshots"
        // 測試階段可以使用以上兩個本地地址變量
        def releasesRepoUrl = "http://my.org/repo/movie-release" // change to your self repo url
        def snapshotsRepoUrl = "http://my.org/repo/movie-snapshot"  // change to your self snapshot repo url
        url = VERSION_NAME.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
        /*
        credentials {
            username '<your account name>'
            password '<your account password>'
        }*/
    }
  }
}

2. 在環(huán)境變量里面配置 Maven 賬號和密碼

  ?  ~ echo "export ORG_GRADLE_PROJECT_MAVEN_PASSWORD=<your account password>" >> ~/.bash_profile
  ?  ~ echo "export ORG_GRADLE_PROJECT_MAVEN_USERNAME=<your account name>" >> ~/.bash_profile
  ?  source ~/.bash_profile

這個命名規(guī)則可以使得在 Gradle 編譯環(huán)境變量里面出現 MAVEN_USERNAME, MAVEN_PASSWORD 這兩個參數可以直接在 build.gradle 文件訪問。

然后修改:

  repositories {
    maven {
        // change URLs to point to your repos, e.g. http://my.org/repo
        //  def releasesRepoUrl = "$buildDir/repos/releases"
        //  def snapshotsRepoUrl = "$buildDir/repos/snapshots"
        // 測試階段可以使用以上兩個本地地址變量
        def releasesRepoUrl = "http://my.org/repo/movie-release" // change to your self repo url
        def snapshotsRepoUrl = "http://my.org/repo/movie-snapshot"  // change to your self snapshot repo url
        url = VERSION_NAME.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
        credentials {
            username MAVEN_USERNAME
            password MAVEN_PASSWORD
        }
    }
  }
}

再重復執(zhí)行一次第三的步驟。如果找不到變量,可以重新下 Android Stuido 讓前面的配置生效。

總結

使用maven進行安卓庫的發(fā)布,不僅減少了與項目或是其他同學私下給庫帶來的風險,也給庫添加了版本管理。方便代碼追溯。并且我們也配置了發(fā)布 sources.jar 這樣配合的同學也可以調試項目的 java 層工程。方便相關同學進行錯誤的輔助定位。提升開發(fā)效率。當然對于一些存在保密性的代碼,就不建議把 sources.jar 發(fā)布出來。

artifact bundleRelease
artifact androidJavadocsJar
// artifact androidSourcesJar // 關閉源代碼文件發(fā)布。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容