使用选定的风格将 Android 库 (aar) 发布到 Bintray

Posted

技术标签:

【中文标题】使用选定的风格将 Android 库 (aar) 发布到 Bintray【英文标题】:Publishing Android Library (aar) to Bintray with chosen flavors 【发布时间】:2016-03-23 18:02:24 【问题描述】:

我刚刚在我的项目中添加了一些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 和 here)和 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;

【问题讨论】:

您必须将每种风味更新为不同的工件。 @GabrieleMariotti 如何在 bintray configurations 中指定风味? 我之前没试过。但是您必须在风味块内指定部分 bintray 配置以分配工件名称。 【参考方案1】:

我面临同样的挑战,这是我能做到的最好的:

在 bintray 插件中使用 mavenPublications 和 gradle maven-publish 插件,您可以将任何变体发布到 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.nameJavadoc", 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.nameJavadocJar", type: Jar, dependsOn: javadoc) 
            description "Puts Javadoc for $variant.name in a jar."
            classifier = 'javadoc'
            from javadoc.destinationDir
        
        def sourcesJar = task("$variant.nameSourcesJar", 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.flavorNameCompile"].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 文件中使用的以下ext 属性:

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 文件的 sn-p:

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

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

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

myLibrary $ ../gradlew bintrayUpload

重要:

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

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

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

【讨论】:

作为底部部分的注释,您可以通过指定missingDimensionStrategy 来让消费应用程序与正确的配置对齐,就像missingDimensionStrategy 'brand', 'XXX' missingDimensionStrategy 'environment', 'ZZZ' 感谢您的出色回答。我面临一个问题:在 ~/.m2 目录中,每种风味都有不同的 .jar 文件,但是当我运行 bintrayUpload 时,它会在每种产品风味的 jar 文件中上传相同的内容。 @VikramBhati 正如答案中所说,您需要在发布指定的风味之前更改defaultPublishConfig @LouisCAD 我刚刚尝试了您所说的,但它仍在为所有口味上传相同的 .jar 文件。到目前为止,即使使用 defaultPublishConfig "abc" 运行 bintrayUpload,也会在 bintray 上发布所有风格。所以我不认为bintrayUpload中的defaultPublishConfig是否有任何影响。如果我遗漏了什么,请纠正我。 @LouisCAD 似乎已弃用 publishNonDefault。运行 bintrayUpload 时收到警告 - publishNonDefault 已弃用且不再有效。所有变体现已发布。【参考方案2】:

设置:

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】:

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

您应该为每种风格发布不同的工件(或者,如果您愿意,也可以构建变体)。 这样,您将拥有 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
    

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

【讨论】:

好的,有了这个我可以将不同的口味上传到不同的 bintray 包。但是分类器还在这里,每个包都有所有的味道。 对不起,我不知道你用分类器指的是什么。我正在检查 jcenter 中的 pom 文件,您应该有 groupId/artifactId 来识别库。 是的,我有这个,但分类器也在这里,所以我在每个包上都有androidsdk-0.0.4-lightDebug.aarandroidsdk-0.0.4-lightDebug.aar。所以目前有两个问题。例如,分类器是lightDebug 你找到答案了吗? 不,我仍然上传了 4 个库(2 个版本和发布 + 调试版本),每次在 bintray 上发布新版本时,我都需要删除调试版本。【参考方案4】:

如果有人仍然遇到这个问题,这对我有用 -

假设您要发布您的 flavor1 的发布版本,请将其添加到您的 build.gradle

android 
    ...
    defaultPublishConfig "flavour1Release"

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

像这样在bintray 块中添加这个

bintray 
    ...
    archivesBaseName = 'YOUR_ARTIFACT_ID'
    ...

然后像你一样运行bintrayUpload 任务。

defaultPublishConfig 每次您需要发布新风格时都必须更改。

【讨论】:

删除publishNonDefault true会阻止该模块在调试中用于其他模块,这是一个好主意,但不能完全解决问题 是的,如果你想在调试中使用库模块,你将不得不使用defaultPublishConfig "flavour1Debug"之类的东西。仅当您必须发布到 bintray 时才切换到 defaultPublishConfig "flavour1Release"【参考方案5】:

听起来您不希望文件名中包含分类器。看起来分类器与生成的库文件名相同。您是否尝试过为它们提供相同的文件名但将它们输出到单独的目录? 例如。在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 插件使用的那个,所以它没有帮助。

以上是关于使用选定的风格将 Android 库 (aar) 发布到 Bintray的主要内容,如果未能解决你的问题,请参考以下文章

使用 AAR 和源 JAR 将 Android 库发布到 Maven

如何将“aar”库添加到 AOSP?

使用 Gradle 构建 Android AAR

原生库的 Android AAR 包

如何在Android库AAR中包含第三方JAR,而无需合并代码

无法在库模块中使用本地.aar文件