将选择的flavors的Android库(aar)发布到Bintray

33

我刚刚在我的项目中添加了一些flavors(或者如果您愿意,可以使用productFlavors)。

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

已上传的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,请查阅文档第23.4.1.3章节

我正在寻找一种解决方案,可以选择要上传的哪些口味。

我已经查看了bintray示例(这里这里)和这个,还有其他示例,但我仍然无法解决问题。

这是我的当前脚本:

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;
}

你必须将每种口味更新为不同的构件。 - Gabriele Mariotti
@GabrieleMariotti,您如何在Bintray“configurations”中指定版本? - Hugo Gresse
我以前没有尝试过。但是你必须在口味块内指定一些bintray配置部分,以指定艺术品名称。 - Gabriele Mariotti
5个回答

14
我面临着同样的挑战,以下是我能做到的最好的方法:
使用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'
    }
}

现在,我终于可以在我的 Android 库模块中使用它,在那里我有多个productFlavors。这是一个可发布的库模块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

当您正确设置了所有内容,将库的名称替换为我的(您可以使用它作为示例),您可以尝试通过首先发布到mavenLocal来发布您的flavored库的版本。要这样做,请运行以下命令:
myLibrary $ ../gradlew publishToMavenLocal

您可以尝试在应用程序的存储库(例如在此处)中添加mavenLocal,并尝试将库添加为依赖项(artifactId 应为口味名称,并将“_”替换为“-”),然后构建它。您还可以使用文件浏览器(在 Finder 中使用 Mac 上的 cmd+shift+G 访问隐藏文件夹)检查目录~/.m2,并查找您的库。 当发布到 bintray/jcenter 时,您只需要运行此命令:
myLibrary $ ../gradlew bintrayUpload

重要提示:

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

如果您需要示例,请随意探索这里我的库“Splitties”。该模块名为concurrency,但我也使用它来处理未经调味的库模块,并且我已经在项目中对所有库模块进行了彻底测试。

如果您需要帮助设置,请联系我。


关于底部部分的说明,您可以通过指定缺失维度策略来使消费应用程序与正确的配置对齐,如下所示:missingDimensionStrategy 'brand','XXX' missingDimensionStrategy 'environment','ZZZ' - MrTristan
感谢您的出色回答。我遇到了一个问题:在~/.m2目录中,每个风味都有不同的.jar文件,但当我运行bintrayUpload时,它会将相同的内容上传到每个产品风味的jar文件中。 - Vikram
@VikramBhati 正如答案所述,您需要在发布指定的 flavor 之前更改 defaultPublishConfig - Louis CAD
@LouisCAD,我刚试了一下你说的方法,但是所有口味上传的都是同一个.jar文件。目前为止,即使使用默认发布配置“abc”运行bintrayUpload,也会将所有口味发布到bintray上。所以我认为defaultPublishConfig在bintrayUpload中没有任何影响。如果我漏掉了什么,请纠正我。 - Vikram
@LouisCAD,看起来 publishNonDefault 已经被废弃了。在运行 bintrayUpload 时得到警告 - publishNonDefault 已被废弃且不再有效。现在所有变体都已发布。 - Vikram
那就解释了。请注意,我不再使用这种方法。我更喜欢制作多个模块,其中一个包含共享代码,其他模块包含我想要更改的内容,然后我选择其中一个。 - Louis CAD

6

背景信息:

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
    }
  }
}

3

如果这个方法不能解决问题,我会删除这个答案。

你应该为每个不同的 flavor(或构建变体,如果你更喜欢这样说)发布一个不同的构件。
这样,你就可以在 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
    }
}

最后,请确保只发布release版本(为什么还要debug版本?)

好的,有了这个,我能够将不同风味上传到不同的bintray包中。但是分类器仍然存在,每个包都有所有的风味。 - Hugo Gresse
抱歉,我不知道你所说的分类器是什么意思。 我正在检查JCenter中的Pom文件,你应该有groupId/artifactId来标识一个库。 - Gabriele Mariotti
是的,我有这个,但分类器也在这里,所以每个包都有 androidsdk-0.0.4-lightDebug.aarandroidsdk-0.0.4-lightDebug.aar。因此,目前存在两个问题。例如,分类器是 lightDebug - Hugo Gresse
你找到答案了吗? - Ali Naddaf
不,我仍然上传了4个库(2种风味和发布+调试版本),每次在bintray上发布新版本时,我需要删除调试版本。 - Hugo Gresse

2
如果您仍然困在这个问题上,以下是我成功解决的方法 -
假设您想要发布flavour1的发布版,请将以下内容添加到build.gradle中。
android {
    ...
    defaultPublishConfig "flavour1Release"
}

如果您的gradle文件中存在publishNonDefault true,请将其删除。

将以下内容添加到bintray块内,如下所示:

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

只需像往常一样运行bintrayUpload任务即可。

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


删除 publishNonDefault true 将会阻止模块在调试中被其他模块使用,这是个不错的想法但并不能完全解决问题。 - Hugo Gresse
是的,如果您想在调试中使用库模块,您将不得不使用类似于 defaultPublishConfig "flavour1Debug" 的东西。只有当您需要发布到 bintray 时,才切换到 defaultPublishConfig "flavour1Release" - k1slay

1

听起来你不想在文件名中包含分类器。看起来分类器与生成的库文件名相同。您是否尝试将它们命名为相同的文件名,但将它们输出到单独的目录中?例如,在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)
        }
    }
}

允许我更改.aar文件名的方法(来自build/outputs/aar/androidsdk/,但不是由bintray插件使用的那个),所以它没有帮助。 - Hugo Gresse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接