gradle

Gradle Customizing publishing

2020-08-17  本文已影响0人  jxcyly1985

Publish Libraries

发布公共的库的主要步骤

设置基本发布

apply plugin: 'java-library'
apply plugin: 'maven-publish'


java {
    withJavadocJar()
    withSourcesJar()
}

publishing {
    publications {
        VCamSDK(MavenPublication) {
            groupId = 'com.example.demo'
            artifactId = 'ApiDemo'
            version = '1.0.1.a'
            from components.java
        }
    }

    repositories {
        maven {
            name = 'MyM1'
            url = "http://com.example.org/nexus/content/groups/public/"
        }
    }
}
publishing process

元数据

元数据主要是描述需要发布的内容

比较官方的说法,即元数据是序列化Gradle组件模型的一种格式,类似POM文件

添加自定义工件

upload.gradle文件

ext {
    aar_version = '1.0.6'
    commit_id = ''
}

def outputAARDebugFile
    def outputAARReleaseFile
    android.libraryVariants.all { variant ->
        if (variant.buildType.name == "debug") {
            variant.outputs.all { output ->
                outputAARDebugFile = output.outputFile
            }
        }
        if (variant.buildType.name == "release") {
            variant.outputs.all { output ->
                outputAARReleaseFile = output.outputFile
            }
        }
    }


    def outputAARDebug = artifacts.add("archives", outputAARDebugFile)

    def outputAARRelease = artifacts.add("archives", outputAARReleaseFile)

    project.ext.commit_id = "git log -n 1 --pretty=%t".execute().text.trim()
    println('project.ext.commit_id ' +  project.ext.commit_id)
    
    publishing {
        publications {
            ToolDebug(MavenPublication) {
                groupId = 'com.example'
                artifactId = 'tool'
                version = project.ext.aar_version + '-' +project.ext.commit_id + '-debug'
                artifact outputAARDebug
                pom {
                    name = 'tool'
                    packaging = "aar"
                    description = 'utility method for tool usage'
                }
            }

            VCamSDKRelease(MavenPublication) {
                groupId = 'com.example'
                artifactId = 'tool'
                version = project.ext.aar_version + '-' + project.ext.commit_id + '-release'
                artifact outputAARRelease
                pom {
                    name = 'tool'
                    packaging = "aar"
                    description = 'utility method for tool usage'
                }
            }

        }

        repositories {
            maven {
                name = 'myExample'
                url = "http://com.example.org/nexus/content/groups/public/"
            }
            
            maven {
                name = 'mylocal'
                url = "file:///c:/build/repo"
            }
        }
    }

    tasks.getByName('publishToolDebugPublicationToMylocalRepository').dependsOn('assembleDebug')
    tasks.getByName('publishToolReleasePublicationToMyExampleRepository').dependsOn('assembleRelease')

通过配置上传脚本,我们做到了

代码方式

从上面的例子,我们可以会发现,我们通过脚本方式添加了

这两个出版物,用来区分不同的buildType,分别支持Debug和Release的发布,但是我们使用Android发布aar的时候,除了针对不同的buildType,可能还会有不同的渠道差异,而且支持的渠道会不同的改变,如果有手写的脚本方式,会造成添加渠道,就需要在upload.gradle脚本中也同步手动修改,显然这种方式效率比较低,作为一个合格程序员这是不能接受的,因为需要增加代码配置方式

upload.gradle

import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream

apply plugin: 'maven-publish'

def deleteVersionFile() {
    def path = "$buildDir/generated/upload/"
    def versionDir = file(path)
    File[] files = versionDir.listFiles();
    for (File child : files) {
        child.delete()
    }
    versionDir.delete()
}


def createVersionFile() {

    project.ext.fullCommitId = "git log -n 1 --pretty=%T".execute().text.trim();
    //for test
    project.ext.fullCommitId = '1111'
    def path = "$buildDir/generated/upload/" + fullCommitId + ".txt"
    def versionFile = file(path)
    versionFile.getParentFile().mkdirs()
    versionFile.createNewFile()
    versionFile.append(fullCommitId.getBytes())
}

def copy(InputStream input, OutputStream output) {
    int bytesRead;
    byte[] BUFFER = new byte[4096 * 1024];
    while ((bytesRead = input.read(BUFFER)) != -1) {
        output.write(BUFFER, 0, bytesRead);
    }
}

def appendZipFile(File sourceFile) {
    // read war.zip and write to append.zip
    ZipFile sourceZip = new ZipFile(sourceFile);
    def tmpZip = new File("$buildDir/generated/upload/tmp.zip")
    ZipOutputStream append = new ZipOutputStream(new FileOutputStream(tmpZip));

    // first, copy contents from existing war
    Enumeration<? extends ZipEntry> entries = sourceZip.entries();
    while (entries.hasMoreElements()) {
        ZipEntry e = entries.nextElement();
        println("copy: " + e.getName());
        append.putNextEntry(e);
        if (!e.isDirectory()) {
            copy(sourceZip.getInputStream(e), append);
        }
        append.closeEntry();
    }

    // now append some extra content
    ZipEntry e = new ZipEntry("$project.ext.fullCommitId" + ".txt");
    println("append: " + e.getName());
    append.putNextEntry(e);
    append.write(project.ext.fullCommitId.getBytes());
    append.closeEntry();

    // close
    sourceZip.close();
    append.close();
    sourceFile.delete()
    tmpZip.renameTo(sourceFile)
}

def addVersionFile(File aarFile) {
    println('addVersionFile aarFile ' + aarFile.getAbsoluteFile())
    createVersionFile()
    appendZipFile(aarFile)
}


project.afterEvaluate {

    def debugVariants = android.libraryVariants.findAll { element ->
        //println("element " + element.properties)
        element.buildType.name == 'debug'
    }
    println("debugVariants size " + debugVariants.size())

    def ReleaseVariants = android.libraryVariants.findAll { element ->
        //println("element " + element.properties)
        element.buildType.name == 'release'
    }
    println("ReleaseVariants size " + ReleaseVariants.size())
    def libVariants = debugVariants + ReleaseVariants
    def repoCount = project.ext.repository.size()

    println("repoCount " + repoCount);
    for (int i = 0; i < repoCount; ++i) {
        publishing.repositories.maven {
            name = project.ext.repository[i]['name']
            url = project.ext.repository[i]['url']
            println('name ' + name + ' url ' + url)
        }

    }

    def flavors = android.productFlavors
    flavors.all { flavor ->
        println("flavor " + flavor.name)
    }

    project.ext.abbreviatedCommitId = "git log -n 1 --pretty=%t".execute().text.trim()
    //针对不同的版本添加不同的出版物
    def publishingTaskNames = new HashMap<Object, Object>()
    def artifactFile = new HashMap<Object, Object>()
    for (variant in libVariants) {
        def buildType = variant.buildType.name
        buildType = buildType.substring(0, 1).toUpperCase() + buildType.substring(1)
        def flavorName = variant.flavorName
        if (variant.flavorName != null && !variant.flavorName.isEmpty()) {
            flavorName = flavorName.substring(0, 1).toUpperCase() + flavorName.substring(1)
        }
        def publicationName = project.ext.baseName + flavorName + buildType
        def taskName = 'bundle' + flavorName + buildType + 'Aar'

        artifactFile.put(publicationName, variant.outputs[0].outputFile)
         // to support 1.0.+
        def publicationVersion = ''
        if (buildType == 'Release') {
            publicationVersion = flavorName + '_' + project.ext.version
        } else {
            publicationVersion = project.ext.abbreviatedCommitId + '_' + flavorName + "_" + buildType  + "_" + project.ext.version
        }

    
        publishing.publications.create(publicationName, MavenPublication) {
            groupId = project.ext.groupId
            artifactId = project.ext.artifactId
            version = publicationVersion 
            println('version ' + version)
            artifact tasks.getByName(taskName)
            pom {
                name = project.ext.pom['name']
                packaging = project.ext.pom['packaging']
                description = project.ext.pom['description']
            }
        }

        for (int i = 0; i < repoCount; ++i) {
            def publishTaskName = 'publish' + publicationName + 'PublicationTo' + project.ext.repository[i]['name'] + 'Repository'
            println("publishTaskName " + publishTaskName)
            publishingTaskNames.put(publishTaskName, publicationName)
        }

        def publishLocalTaskName = 'publish' + publicationName + 'PublicationTo' + 'MavenLocal'
        publishingTaskNames.put(publishLocalTaskName, publicationName)

    }


    for (taskName in publishingTaskNames.keySet()) {
        println("taskName:" + taskName)
        def aarFile = artifactFile[publishingTaskNames[taskName]]
        println("addVersionFile aarFile:" + aarFile)
        tasks.getByName(taskName).doFirst {
            addVersionFile(aarFile)
        }
        tasks.getByName(taskName).doLast {
            println("deleteVersionFile for task:" + taskName)
            deleteVersionFile()
        }
    }

    tasks.withType(PublishToMavenRepository) {
        onlyIf {
            println("PublishToMavenRepository publication.name  " + publication.name)
            publication.name.contains('Release')
        }
        doFirst {
            'git pull --rebase'.execute()
            def status = 'git status'.execute().text.trim()
            if (!status.contains('working tree clean')) {
                throw new RuntimeException('check your code is sync with gerrit!')
            }
        }
    }
    tasks.withType(PublishToMavenLocal) {
        onlyIf {
            println("PublishToMavenLocal publication.name  " + publication.name)
            publication.name.contains('Debug')
        }
    }
}

通过这种方式我们增加了一些优化

基于一下的android配置

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions 'platform', 'model'
    productFlavors {
        x50 {
            dimension 'model'
        }

        x60 {
            dimension 'model'
        }

        mtk {
            dimension 'platform'
        }
        qcom {
            dimension 'platform'
        }
    }

我们可以看到生成了对应的任务,我们通过gradle运行对应的任务就可以执行不同的发布

config-publication.png

添加外部依赖的POM信息

           pom.withXml {
//                def addNode = { rootNode, list ->
//                    list.each {
//                        if (null != it.group) {
//                            def dependency = rootNode.appendNode('dependency')
//                            dependency.appendNode('groupId', 'com.vivo.vivo3rdalgointerface')
//                            dependency.appendNode('artifactId', 'VivoAlgoSDK')
//                            dependency.appendNode('version', 'common_1.0.1.1')
//                            dependency.appendNode('scope', 'compile')
//                        }
//                    }
//                }

//                def rootNode = asNode().appendNode('dependencies')
//                // 查询所有 implementation, api, compile 依赖
//                def implementations = configurations.findByName("implementation").allDependencies
//                // 查询所有 variantNameImplementation, api, compile 依赖
//                def variantNameImplementations = configurations.findByName("${variantName}Implementation").allDependencies
//
//                // 遍历添加依赖节点
//                addNode(rootNode, implementations)
//                addNode(rootNode, variantNameImplementations)

                // 创建根节点
                def rootNode = asNode().appendNode('dependencies')

                def dependency = rootNode.appendNode('dependency')
                dependency.appendNode('groupId', project.ext.algo_groupId)
                dependency.appendNode('artifactId', project.ext.algo_artifactId)
                dependency.appendNode('version', project.ext.algo_version)
                dependency.appendNode('scope', 'compile')
            }

分组

考虑发布任务混在一起容易不小心点击出错,我们可以增加分组

//保存任务返回结果

def pubToMyM1Tasks = tasks.withType(PublishToMavenRepository) {
        onlyIf {
            println("PublishToMavenRepository publication.name  " + publication.name)
            publication.name.contains('Release')
        }
        doFirst {
            'git pull --rebase'.execute()
            def status = 'git status'.execute().text.trim()
            if (!status.contains('working tree clean')) {
                throw new RuntimeException('check your code is sync with gerrit!')
            }
        }
    }
def pubToLocalTasks = tasks.withType(PublishToMavenLocal) {
    onlyIf {
        println("PublishToMavenLocal publication.name  " + publication.name)
        publication.name.contains('Debug')
    }
}

pubToVivoTasks.all {
        if(publication.name.contains('Release')){
            setGroup('publishTo-MyM1')
        }
    }

pubToLocalTasks.all {
    if(publication.name.contains('Debug')){
        setGroup('publishTo-Local')
    }
}

Classifier

分类

我们依赖配置的信息如下:

configurationName "group:name:version:classifier@extension"

那么我们publish的时候通过配置classifier那么就可以在引用的时候通过classifier@extension引入,同时在生成的文件也添加了对应的

后缀-[classifier].extension

如下:

 artifact tasks.getByName(taskName) {
    classifier android
    extension project.ext.pom['packaging']
 }
 pom {
     name = project.ext.pom['name']
     description = project.ext.pom['description']
 }

aar发布

首先aar项目build.gradle引入upload.gradle

apply from: 'upload.gradle'

后续可以把upload.gradle做成在线插件引入

在根目录配置发布信息

ext {
    baseName = "XXXLib"         
    groupId = "com.example"     
    artifactId = "xxxlib"
    version = '1.0.6'
    abbreviatedCommitId = ''
    fullCommitId = ''
    pom = [name       : "XXXLib",
           packaging  : "aar",
           description: "XXXLib for all normal android usage"]

    repository = [
            [name: 'MyM1', url: 'https://com.example.org/maven1/'],
            [name: 'MyM2', url: 'https://com.example.org/maven2/'],
    ]
}

ext字段配置信息是对应于dependencies的依赖项

configurationName "group:name:version:classifier@extension"

例如

implementation 'com.vivo.camera:VCameraSDK:1.0.6@aar'

配置之后,通过

implementation groupId:artifactId:version@extension 引入发布的AAR包

这里我们会发现aar包的名字其实不对定位依赖起作用

如果当前的VCameraSDK分支添加了不同项目的支持,例如添加了pd1969和pd2001,可以在AAR模块的build.gradle

android {

​ .............

​ .............

}

扩展中添加

flavorDimensions 'product'
productFlavors {
    x88 {
        dimension 'product'
    }
   x99 {
        dimension 'product'
    }
}

app集成

基于buildType和productFlavor的配置和Gradle的依赖管理,我们就可以在项目集成中做到

上一篇 下一篇

猜你喜欢

热点阅读