使用maven publish插件发布产物(aar)全过程实践-程序员宅基地

技术标签: java  maven  

背景

平时开发中会把一些独立的功能模块抽取出来作为sdk,既方便业务接入,又能让其他业务线快速复用。那么我们就需要将sdk打包上传到maven仓库,让业务侧依赖即可。

一、编译后的产物

在上传产物到maven仓库之前,我们的知道产物到底是什么。

Android Gradle插件根据项目gradle中应用不同的插件类型在编译组装后会生成不同的产物:

image.png

1.1 APK 构件
Android项目的主工程app的gradle配置文件依赖:

apply plugin: 'com.android.application' 

因此,在通过编译命令./gradlew assembleDebug 或./gradlew assembleRelease后,就会在build/outputs/apk文件下生成产物:

image.png

如图,apk就是产物(构件)。

1.2 AAB(Android app bundle)构件

如果是海外市场,在Google Play上架的应用必须要打aab包,而不是之前的apk格式。具体区别就暂不讨论了~ 编译命令为:./gradlew bundleDebug 或./gradlew bundleRelease。产物为:

image.png

1.3 AAR 构件

一般的module在编译打包后,会生成aar:

image.png

二、publish插件


有了产物,我们就需要把产物上传到maven仓库(一般是私有仓库),方便公司项目直接依赖。而上传就要用到publish插件。APG 3.6.0之前用的maven插件,之后都用maven-publish插件。

2.1 maven-publish插件使用


我们可以新建一个gradle文件,如:maven_publish.gradle。专门用来上传aar。配置如下:

 //maven-publish 新方式
plugins {
    //todo 1 上传插件
    id 'maven-publish'
}

afterEvaluate{
    publishing {
        publications {

            // Creates a Maven publication called "myPublication".
            myPublication(MavenPublication) {
                groupId 'com.sdk.aarpub'
                artifactId 'aar-test'
                version '1.2.2'             // Your package version
//                artifact publishArtifact    //Example: *./target/myJavaClasses.jar*
                artifact "build/outputs/aar/aar-test-release.aar"//aar包的目录

                //带上依赖 ,否则会报错
                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')

                    def scopes = [configurations.compile]
                    if (configurations.hasProperty("api")) {
                        scopes.add(configurations.api)
                    }
                    if (configurations.hasProperty("implementation")) {
                        scopes.add(configurations.implementation)
                    }
                    if (configurations.hasProperty("debugImplementation")) {
                        scopes.add(configurations.debugImplementation)
                    }
                    if (configurations.hasProperty("releaseImplementation")) {
                        scopes.add(configurations.releaseImplementation)
                    }

//                    if (project.ext.targetType != "jar") {
//                        scopes.add(configurations.provided)
//                    }

                    scopes.each { scope ->
                        scope.allDependencies.each {
                            if (it instanceof ModuleDependency) {
                                boolean isTransitive = ((ModuleDependency) it).transitive
                                if (!isTransitive) {
                                    println "<<<< not transitive dependency: [${it.group}, ${it.name}, ${it.version}]"
                                    return
                                }
                            }

                            if (it.group == "${project.rootProject.name}.libs" || it.version == 'unspecified') {
                                return
                            }

                            if (it.group && it.name && it.version) {
                                def dependencyNode = dependenciesNode.appendNode('dependency')
                                dependencyNode.appendNode('groupId', it.group)
                                dependencyNode.appendNode('artifactId', it.name)
                                dependencyNode.appendNode('version', it.version)
                                dependencyNode.appendNode('scope', scope.name)
                            }
                        }
                    }
                }
            }
        }

        // Repositories *to* which Gradle can publish artifacts
        repositories {
            maven {
            //上传到项目本地仓库
                url uri('../local_mavenrepo')
//            credentials {
//                username "default"
//                password "default"
//            }
            }
        }
    }
} 

在assemble命令后,执行publish命令:

./gradlew publish 

2.2 maven插件使用

旧方式:

plugins {
    //todo 1 上传插件
    id 'maven'
}


uploadArchives{
    // 方式一
    repositories {
        mavenDeployer{
            repository(url: uri('../local_mavenrepo'))
            //todo 2 配置版本信息 方式二
            pom.groupId = 'com.sdk.aarpub'
            pom.artifactId = 'aar-test'
            pom.version = '1.1.0'
        }
        //mavenLocal 这个是本机上的maven本地缓存仓库
//        mavenLocal()
    }

} 

在assemble命令后,执行uploadArchives命令:

./gradlew uploadArchives 

2.3 业务侧使用


在项目的根gradle文件中,配置仓库:

maven { url '../local_mavenrepo/'} 


在对应的模块中引入依赖:

implementation 'com.sdk.aarpub:aar-test:1.2.2' 

三、问题总结

3.1 项目中依赖本地aar的时候打包报错Direct local .aar file dependencies are not supported when building an AAR…

原因:当打包aar时候直接依赖本地的aar是不被允许的。 解决方案:通过把依赖的aar放到单独的模块中,让直接依赖本地aar变成依赖模块。

  1. 新建一个文件夹aar-lib
  2. 新建一个libs文件夹,把oaid_sdk_1.0.30.aar放入到libs目录中

image.png

 3. 新建build.gradle文件,写入如下内容

configurations.maybeCreate("default")
def publishArtifact = artifacts.add("default", file('libs/oaid_sdk_1.0.30.aar')) 


在项目的settings文件中引入该模块

include ':aar-lib' 


删除报错模块中的aar文件,替换原来依赖方式

//    implementation files('libs/oaid_sdk_1.0.30.aar') 旧的方式
    implementation project(path:":aar-lib") 

3.2 module打包aar时依赖aar导致的类引用不到的问题

3.1 只是解决了在项目打包过程中依赖本地aar的问题。 当module作为sdk同时又依赖aar时,此时接入sdk会报错,提示引用不到aar中的类。当然我们可以直接把aar给到业务测,直接引入即可,但这样增加了接入成本。因此,我们的解决方案跟原理跟3.1一样,但是会把aar上传到远程库,作为远程来依赖。

比如 A模块依赖了oaid_sdk_1.0.30.aar,同时A模块作为sdk是要提供给业务侧app使用的。

按照3.1的方式创建一个aar-lib,build.gradle内容有所不同:

plugins {
    id 'maven-publish'
}

//生成文档注释
task androidJavadocs(type: Javadoc) {
    failOnError = false
    source = android.sourceSets.main.java.srcDirs
    ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
    classpath += files(ext.androidJar)
}
//将文档打包成jar
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
    archiveClassifier.set('javadoc')
    from androidJavadocs.destinationDir
}
//将源码打包,这一点对kotlin来说很重要,否则业务侧无法看到源码
task androidSourcesJar(type: Jar) {
    archiveClassifier.set('sources')
    from android.sourceSets.main.java.srcDirs
}
configurations.maybeCreate("default")
def publishArtifact = artifacts.add("default", file('libs/oaid_sdk_1.0.30.aar'))

afterEvaluate{
    publishing {
        publications {

            myPublication(MavenPublication) {
                groupId 'com.sdk.aarpub'
                artifactId 'aar-lib'
                version '1.0.0'             // Your package version
                artifact(androidSourcesJar)//将源码打包进aar,如果不需要可以去掉
                artifact(androidJavadocsJar)//将注释打包进aar,如果不需要可以去掉
                // 将aar推送到远程仓库
                artifact publishArtifact    //Example: *./target/myJavaClasses.jar*
            }
        }

        // Repositories *to* which Gradle can publish artifacts
        repositories {
            maven {
                url uri('../local_maverepo')
//            credentials {
//                username "default"
//                password "default"
//            }
            }
        }
    }
} 

执行发布命令

./gradlew :aar-lib:publish 


让A模块依赖第二步中推送到远程的aar库

implementation 'com.sdk.aarpub:aar-lib:1.0.0' 


重新打包A模块,当app依赖A模块时候,A模块中的aar就会被引用到了
当然在A模块发布的时候记得要带上依赖:

 //带上依赖 ,否则会报错
                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')

                    def scopes = [configurations.compile]
                    if (configurations.hasProperty("api")) {
                        scopes.add(configurations.api)
                    }
                    if (configurations.hasProperty("implementation")) {
                        scopes.add(configurations.implementation)
                    }
                    if (configurations.hasProperty("debugImplementation")) {
                        scopes.add(configurations.debugImplementation)
                    }
                    if (configurations.hasProperty("releaseImplementation")) {
                        scopes.add(configurations.releaseImplementation)
                    }

//                    if (project.ext.targetType != "jar") {
//                        scopes.add(configurations.provided)
//                    }

                    scopes.each { scope ->
                        scope.allDependencies.each {
                            if (it instanceof ModuleDependency) {
                                boolean isTransitive = ((ModuleDependency) it).transitive
                                if (!isTransitive) {
                                    println "<<<< not transitive dependency: [${it.group}, ${it.name}, ${it.version}]"
                                    return
                                }
                            }

                            if (it.group == "${project.rootProject.name}.libs" || it.version == 'unspecified') {
                                return
                            }

                            if (it.group && it.name && it.version) {
                                def dependencyNode = dependenciesNode.appendNode('dependency')
                                dependencyNode.appendNode('groupId', it.group)
                                dependencyNode.appendNode('artifactId', it.name)
                                dependencyNode.appendNode('version', it.version)
                                dependencyNode.appendNode('scope', scope.name)
                            }
                        }
                    }
                } 


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/Misdirection_XG/article/details/125193292

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chuyouyinghe/article/details/138166989

智能推荐

BaseServlet(MVC架构的Servle类都继承于该类)-程序员宅基地

文章浏览阅读220次。该类无需在web.xml注册:但继承的Servlet类需要在web.xml注册1、 通过该抽象类能使得请求参数method使得Servlet类来决定调用哪个方法,同时该方法返回值为转发 或者重定向地址(该方法会通过返回值自行判断)2、Servlet类只需要继承该类,请求参数加上方法名(?method=方法名)同时在Servlet类中定义一个同名方法返回值为 S...

5.参数估计——点估计与区间估计概念,置信区间的公式求法与Python实现求出结果-程序员宅基地

文章浏览阅读2.5k次,点赞2次,收藏22次。点估计与区间估计概念,置信区间的公式求法与Python实现求出结果_点估计

Java面向对象高级部分——字节输出流OutputStream(三十二)_outputstream 实例化-程序员宅基地

文章浏览阅读473次。在进行IO操作时,我们必须遵循以下的几个步骤:1、使用File找到一个文件2、使用字节流或者字符流子类为字节流或字符流实例化3、进行读写操作4、关闭流在整个IO包中,流的操作分为两种:字节流:字节输出流:OutputStream字节输入流:InputStream字符流:字符输出流:Writer字符输入流:Reader字节输出流OutputStream:public abstract clas..._outputstream 实例化

交互设计知识总结-程序员宅基地

文章浏览阅读155次。从用户角度来说,交互设计是一种如何让产品易用,有效而让人愉悦的技术,它致力于了解目标用户和他们的期望,了解用户在同产品交互时彼此的行为,了解“人”本身的心理和行为特点,同时,还包括了解各种有效的交互方式,并对它们进行增强和扩充。系统应该让用户时刻清楚当前发生了什么事情,也就是快速的让用户了解自己处于何种状态、对过去发生、当前目标、以及对未来去向有所了解,一般的方法是在合适的时间给用户适当的反馈,防止用户使用出现错误。在此,特别要注意在用户操作具有毁灭性效果的功能时要有提示,防止用户犯不可挽回的错误。

使用单例模式封装go-kafka链接(github.com/Shopify/sarama)_kafka-go封装-程序员宅基地

文章浏览阅读2.9k次。package kafkaimport (“errors”“github.com/Shopify/sarama”“github.com/luslin/webs/src/server1/conf”“github.com/luslin/webs/src/server1/dbsource/redis”“github.com/prometheus/common/log”“sync”)va..._kafka-go封装

Toeplitz矩阵以及矩阵乘法FFT加速_toeplitz矩阵乘向量例子-程序员宅基地

文章浏览阅读3.9k次。Toeplitz矩阵以及矩阵乘法FFT加速1.Toeplitz矩阵托普利兹矩阵,简称为T型矩阵,它是由Bryc、Dembo、Jiang于2006年提出的。托普利兹矩阵的主对角线上的元素相等,平行于主对角线的线上的元素也相等;矩阵中的各元素关于次对角线对称,即T型矩阵为次对称矩阵。这里我们使用matlab中自带的函数生成一个toeplitz矩阵的例子:x=[1 2 3 4];y=[1 5 6 7 8 9];z=toeplitz(x,y);我们可以得到一个这样的矩阵结果:我们可以看到,其中x中_toeplitz矩阵乘向量例子

随便推点

JDBC对数据库的crud综合练习题_crdu练习-程序员宅基地

文章浏览阅读302次。1.创建数据库use teamdb;drop table if exists employee;drop table if exists department;create table department( deptId int primary key not null, deptName varchar(50) not null, deptAddress varchar(2..._crdu练习

amend用法 git 信息_git commit --amend 修改git提交记录用法详解-程序员宅基地

文章浏览阅读175次。有时你提交过代码之后,发现一个地方改错了,你下次提交时不想保留上一次的记录;或者你上一次的commit message的描述有误,这时候你可以使用接下来的这个命令:git commit --amend。git功能十分强大,接下来我将讲解一下git commit --amend命令的用法~git log之后,可以看到你之前提交过的git历史:接下来,在bash里输入wq退出log状态,执行:$ gi..._$ git commit --amend [master 708afd6] [sda][add]时间同步apk date: thu apr 13

谈谈判别式模型和生成式模型?-程序员宅基地

文章浏览阅读487次。今日面试题谈谈判别式模型和生成式模型?解析:判别方法:由数据直接学习决策函数 Y = f(X),或者由条件分布概率 P(Y|X)作为预测模型,即判别模型。生成方法:由数据..._谈谈判别式模型和生成式模型

python中git克隆代码失败_使用Git clone代码失败的解决方法-程序员宅基地

文章浏览阅读830次。今天从GitHub上找到一份代码,想要clone到本地,便利用Git去clone代码,结果报了以下错误:error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054fatal: The remote end hung up unexpectedlyfatal: early EOFfatal: index-pa..._python无法使用clone

数字单片机的技术发展-程序员宅基地

文章浏览阅读1.8k次。数字单片机的技术发展 数字单片机的技术进步反映在内部结构、功率消耗、外部电压等级以及制造工艺上。在这几方面,较为典型地说明了数字单片机的水平。在目前,用户对单片机的需要越来越多,但是,要求也越来越高。下面分别就这四个方面说明单片机的技术进步状况。 1、 内部结构的进步 单片机在内部已集成了越来越多的部件,这些部件包括一般常用的电路,例如:定时器,比较器,A/D转换器,D

sqlite3 调用sqlite3_exec查询数据时出现"callback requested query abort"-程序员宅基地

文章浏览阅读4.9k次,点赞6次,收藏7次。不知道有没有人跟我一样,在调用sqlite3的API中sqlite3_exec()函数时出现abort问题,今天我就遇到了,如下图。函数基本原型为: int sqlite3_exec(sqlite3*,const char *sql,sqlite_callback,void *param,char **errmsg); 主要功能是用于查询数据库里的_callback requested query abort