将 Android 库 (aar) 发布到具有所选风格的 Bintray

Publishing Android Library (aar) to Bintray with chosen flavors

我刚刚在我的项目中添加了一些 flavors(或者 productFlavors,如果你愿意的话)。

事实是,当我将库发布到 bintray 时,所有风格都已上传(这很棒),但我无法使用它们。使用的插件是官方的here

上传的aar:

 androidsdk-0.0.4-fullRelease.aar
 androidsdk-0.0.4-fullDebug.aar
 androidsdk-0.0.4-lightRelease.aar
 androidsdk-0.0.4-lightDebug.aar

如您所述,fullRelease 被命名为 classifier,请参阅 doc chapter 23.4.1.3

我正在寻找一种解决方案来选择我要上传的口味。

我已经看过 bintray 示例(here and here) and this,还有其他示例,但我仍然卡住了。

这是我当前的脚本:

apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'

buildscript {
    repositories {
        jcenter()
    }
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 23
        versionCode 64
        versionName "0.0.4"
    }

    publishNonDefault true

    productFlavors {
        full {
        }
        light {
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:recyclerview-v7:23.1.1'
    fullCompile 'com.squareup.picasso:picasso:2.5.0'
}

version = android.defaultConfig.versionName

uploadArchives {
    repositories.mavenDeployer {
        pom.project {

            packaging 'aar'

        }
    }
}

////////////////////////////////
// Bintray Upload configuration

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

bintray {
    user = properties.getProperty("bintray.user")
    key = properties.getProperty("bintray.apikey")

    configurations = ['archives']
    pkg {
        repo = "MyRepo" // repo name
        userOrg = 'hugo'
        name = "AndroidSDK" // Package name
        websiteUrl = siteUrl
        vcsUrl = gitUrl
        publish = true
    }
}

要导入我目前正在使用的库:

compile ('com.example.lib:sdk:0.0.8:fullRelease@aar') {
    transitive = true;
}

我没有尝试过,所以如果不能解决问题我会删除答案。

您应该 post 为每种口味制作不同的工件(如果您愿意,也可以构建变体)。
通过这种方式,您将拥有 jcenter x 工件,每个工件都有一个 pom 文件。

类似于:

groupId
|--library-full
|----.pom
|----.aar
|--library-light
|----.pom
|----.aar

在你的顶级文件中你可以定义

allprojects {
    repositories {
        jcenter()
    }

    project.ext {
        groupId="xxx" 
        libraryName = ""
        ......
    }
}

然后在你的库模块中:

productFlavors {
        full {
            project.ext.set("libraryName", "library-full");
        }
        light {
            project.ext.set("libraryName", "library-light");
        }
}

bintray {

    //...
    pkg {
        //...Do the same for other variables
        name = project.ext.libraryName
    }
}

最后确保只发布发布构建类型(为什么还要发布调试版本?)

听起来您不希望文件名中包含分类器。看起来分类器与生成的库文件名相同。您是否尝试过给它们相同的文件名但将它们输出到不同的目录? 例如。在 android 范围内:

libraryVariants.all { variant ->
    variant.outputs.each { output ->
        def outputFile = output.outputFile
        if (outputFile != null && outputFile.name.endsWith('.aar')) {
            def fileName = "same_name-${version}.aar"
            output.outputFile = new File(outputFile.parent+"/${archivesBaseName}", fileName)
        }
    }
}

如果有人仍然被这个问题困扰,这对我有用 -

假设你想为你的 flavor1 发布发布版本,将它添加到你的 build.gradle

android {
    ...
    defaultPublishConfig "flavour1Release"
}

删除 publishNonDefault true 如果它存在于您的 gradle 文件中。

像这样在 bintray 块中添加这个

bintray {
    ...
    archivesBaseName = 'YOUR_ARTIFACT_ID'
    ...
}

然后 运行 bintrayUpload 任务。

每次您需要发布新口味时,都必须更改 defaultPublishConfig

我遇到了同样的挑战,这是我能做到的最好的:

使用 mavenPublications 和 gradle maven-publish 插件以及 bintray 插件,您可以将任何变体发布到 mavenLocal 和 bintray。

这是我在我要发布的所有项目库模块末尾应用的 publish.gradle 文件:

def pomConfig = {
    licenses {
        license {
            name 'The Apache Software License, Version 2.0'
            url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
        }
    }
    developers {
        developer {
            id 'louiscad'
            name 'Louis CAD'
            email 'louis.cognault@gmail.com'
        }
    }
    scm {
        connection 'https://github.com/LouisCAD/Splitties.git'
        developerConnection 'https://github.com/LouisCAD/Splitties.git'
        url siteUrl
    }
}

def publicationNames = []
publishing.publications {
    android.libraryVariants.all { variant ->
        if (variant.buildType.name == "debug") return // Prevents publishing debug library

        def flavored = !variant.flavorName.isEmpty()

        /**
         * Translates "_" in flavor names to "-" for artifactIds, because "-" in flavor name is an
         * illegal character, but is well used in artifactId names.
         */
        def variantArtifactId = flavored ? variant.flavorName.replace('_', '-') : project.name

        /**
         * If the javadoc destinationDir wasn't changed per flavor, the libraryVariants would
         * overwrite the javaDoc as all variants would write in the same directory
         * before the last javadoc jar would have been built, which would cause the last javadoc
         * jar to include classes from other flavors that it doesn't include.
         *
         * Yes, tricky.
         *
         * Note that "${buildDir}/docs/javadoc" is the default javadoc destinationDir.
         */
        def javaDocDestDir = file("${buildDir}/docs/javadoc ${flavored ? variantArtifactId : ""}")

        /**
         * Includes
         */
        def sourceDirs = variant.sourceSets.collect {
            it.javaDirectories // Also includes kotlin sources if any.
        }
        def javadoc = task("${variant.name}Javadoc", type: Javadoc) {
            description "Generates Javadoc for ${variant.name}."
            source = variant.javaCompile.source // Yes, javaCompile is deprecated,
            // but I didn't find any working alternative. Please, tweet @Louis_CAD if you find one.
            destinationDir = javaDocDestDir
            classpath += files(android.getBootClasspath().join(File.pathSeparator))
            classpath += files(configurations.compile)
            options.links("http://docs.oracle.com/javase/7/docs/api/");
            options.links("http://d.android.com/reference/");
            exclude '**/BuildConfig.java'
            exclude '**/R.java'
            failOnError false
        }
        def javadocJar = task("${variant.name}JavadocJar", type: Jar, dependsOn: javadoc) {
            description "Puts Javadoc for ${variant.name} in a jar."
            classifier = 'javadoc'
            from javadoc.destinationDir
        }
        def sourcesJar = task("${variant.name}SourcesJar", type: Jar) {
            description "Puts sources for ${variant.name} in a jar."
            from sourceDirs
            classifier = 'sources'
        }

        def publicationName = "splitties${variant.name.capitalize()}Library"
        publicationNames.add(publicationName)

        "$publicationName"(MavenPublication) {
            artifactId variantArtifactId
            group groupId
            version libraryVersion

            artifact variant.outputs[0].packageLibrary // This is the aar library
            artifact sourcesJar
            artifact javadocJar

            pom {
                packaging 'aar'
                withXml {
                    def root = asNode()
                    root.appendNode("name", 'Splitties')
                    root.appendNode("url", siteUrl)
                    root.children().last() + pomConfig
                    def depsNode = root["dependencies"][0] ?: root.appendNode("dependencies")

                    def addDep = {
                        if (it.group == null) return // Avoid empty dependency nodes
                        def dependencyNode = depsNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', it.group)
                        dependencyNode.appendNode('artifactId', it.name)
                        dependencyNode.appendNode('version', it.version)
                        if (it.hasProperty('optional') && it.optional) {
                            dependencyNode.appendNode('optional', 'true')
                        }
                    }

                    // Add deps that everyone has
                    configurations.compile.allDependencies.each addDep
                    // Add flavor specific deps
                    if (flavored) {
                        configurations["${variant.flavorName}Compile"].allDependencies.each addDep
                    }
                    // NOTE: This library doesn't use builtTypes specific dependencies, so no need to add them.
                }
            }
        }
    }
}

group = groupId
version = libraryVersion

afterEvaluate {
    bintray {
        user = bintray_user
        key = bintray_api_key
        publications = publicationNames

        override = true
        pkg {
            repo = 'splitties'
            name = project.name
            desc = libraryDesc
            websiteUrl = siteUrl
            issueTrackerUrl = 'https://github.com/LouisCAD/Splitties/issues'
            vcsUrl = gitUrl
            licenses = ['Apache-2.0']
            labels = ['aar', 'android']
            publicDownloadNumbers = true
            githubRepo = 'LouisCAD/Splitties'
        }
    }
}

为了让它工作,我需要定义 bintray_userbintray_api_key 属性。我个人只是将它们放在我的 ~/.gradle/gradle.properties 文件中,如下所示:

bintray_user=my_bintray_user_name
bintray_api_key=my_private_bintray_api_key

我还需要在根项目的 build.gradle 文件的 publish.gradle 文件中定义以下分机属性:

allprojects {
    ...
    ext {
        ...
        // Libraries
        groupId = "xyz.louiscad.splitties"
        libraryVersion = "1.2.1"
        siteUrl = 'https://github.com/LouisCAD/Splitties'
        gitUrl = 'https://github.com/LouisCAD/Splitties.git'
    }
}

现在,我终于可以在我有多个 productFlavors 的 android 库模块中使用它了。这是可发布库模块的 build.gradle 文件的片段:

plugins {
    id "com.jfrog.bintray" version "1.7.3" // Enables publishing to bintray
    id "com.github.dcendents.android-maven" version "1.5" // Allows aar in mavenPublications
}

apply plugin: 'com.android.library'
apply plugin: 'maven-publish' // Used for mavenPublications

android {
    ...
    defaultPublishConfig "myLibraryDebug" // Allows using this library in another
    // module in this project without publishing to mavenLocal or Bintray.
    // Useful for debug purposes, or for your library's sample app.
    defaultConfig {
        ...
        versionName libraryVersion
        ...
    }
    ...
    productFlavors {
        myLibrary
        myLibrary_logged // Here, the "_" will be replaced "-" in artifactId when publishing.
        myOtherLibraryFlavor
    }
    ...
}

dependencies {
    ...
    // Timber, a log utility.
    myLibrary_loggedCompile "com.jakewharton.timber:timber:${timberVersion}"; // Just an example
}
...

ext {
    libraryDesc = "Delegates for kotlin on android that check UI thread"
}

apply from: '../publish.gradle' // Makes this library publishable

当你正确地完成所有这些设置后,使用你的库的名称而不是 mine's(你可以将其用作示例),你可以尝试通过尝试发布你的风味库的一个版本首先发布到 mavenLocal。 为此,运行 此命令:

myLibrary $ ../gradlew publishToMavenLocal

然后您可以尝试在应用程序的存储库中添加 mavenLocal (example here) 并尝试将您的库添加为依赖项(artifactId 应该是风格名称,“_”替换为“-”)并建造它。 您还可以检查您的文件资源管理器(在 Finder 中的 Mac 上使用 cmd+shift+G 来访问隐藏文件夹)目录 ~/.m2 并查找您的库。

当需要发布到 bintray/jcenter 时,您只需 运行 这个命令:

myLibrary $ ../gradlew bintrayUpload

重要提示:

在将您的库发布到 mavenLocal、Bintray 或其他 Maven 存储库之前,您通常需要针对使用该库的示例应用程序试用您的库。这个示例应用程序应该是同一项目中的另一个模块,只需要具有项目依赖项,它应该如下所示:compile project(':myLibrary')。但是,由于您的库有多个 productFlavors,您需要测试所有这些。不幸的是,目前无法从示例应用程序的 build.gradle 文件中指定要使用的配置(除非您在库的 build.gradle 文件中使用 publishNonDefault true,这会破坏 maven 和 bintray 的发布) ,但您可以在库的模块中指定默认配置(即 buildVariant):defaultPublishConfig "myLibraryDebug"android 闭包中。您可以在 Android Studio 中的 "Build Variants" 工具 Windows 中查看您的库的可用构建变体。

如果您需要示例,请随时探索 my library "Splitties" here。 flavored 模块被命名为 concurrency,但我也将我的脚本用于 unflavored 库模块,并且我在项目中的所有库模块上对其进行了全面测试。

如果您需要帮助进行设置,可以联系我。

设置:

buildTypes {
  debug {
  }
  release {
  }
}

publishNonDefault true

修复:

defaultPublishConfig 'release'

// Fix for defaultPublishConfig not working as expected
// ref: https://github.com/dcendents/android-maven-gradle-plugin/issues/11
libraryVariants.all { variant ->
  if( publishNonDefault && variant.name == defaultPublishConfig ) {
    def bundleTask = tasks["bundle${variant.name.capitalize()}"]
    artifacts {
      archives(bundleTask.archivePath) {
        classifier null //necessary to get rid of the suffix in the artifact
        builtBy bundleTask
        name name.replace('-' + variant.name, '')//necessary to get rid of the suffix from the folder name
      }
    }
  }
}

此修复程序仍会发布所有工件,但会发布一个没有风格后缀的默认工件,这足以使其全部正常工作。

仅上传默认工件的修复​​方法如下(如果 bintray 插件知道 POM 过滤器是什么):

install {
  repositories.mavenInstaller {
    /*
    POM filters can be used to block artifacts from certain build variants.

    However, Bintray does not respect POM filters, therefore this only works for maven deploy plugin.
    Also, bintray crashes with named filters, since it always expects a /build/pom/pom-default.xml,
  which does not happen with named filters.
    */
    filter { artifact, file ->
      // this how the default classifier is identified in case the defaultPublishConfig fix is applied
      artifact.attributes.classifier == null
    }
  }
}