AS--›Gradle 打包指定文件到jar/dex(支持java和kotlin, 支持jdk9)

借助强大的Gradle构建系统, 可以很轻松的打包出jar, 再借助Android SDK中的dx.bat dx.jar文件, 就能转换成dex

使用Gradle创建生成jar文件的任务

关于jar任务type: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html

/**
 * Jar任务类型, 不支持kotlin文件
 * */
task _makeJar(type: Jar) {
    //任务依赖于assemble任务. 所以此任务执行前, 会先执行assemble任务
    //之所以需要依赖assemble任务, 是因为assemble执行完成后, 会把java文件转换成class文件,
    //然后收集需要的class文件到jar文件.
    dependsOn(assemble)

    //设置生成jar文件所在的路径
    destinationDir = file(rootDir.getAbsolutePath() + "/jar")

    //设置jar文件版本
    version = time()

    //设置jar文件中MANIFEST.MF的内容
    manifest {
        attributes("Manifest-Version": version)
    }

    //设置jar文件名称, 名称后面会自动拼接上 version 值.
    //具体可以查看源码: org.gradle.api.tasks.bundling.AbstractArchiveTask#getArchiveName
    baseName "jar_file_name"

    //保存jar完整路径到全局变量, 此变量主要用于将jar文件转换成dex文件的参数
    project.ext.makeJarPath = getArchivePath().getAbsolutePath()

    //需要打包class文件的路径, 这个路径可以是任意的, 也可以是 assemble 任务生成的.
    //不同的gradle版本, 生成的路径不一样, 可以在 build 文件夹下搜索即可得到.
    from('/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes')
    
    //需要排除的class文件, 比如:去掉R$开头的文件
    exclude {
        it.name.startsWith('R$') || it.name.startsWith('android')
    }

    //需要指定包含的class文件, 此规则优先于 exclude
    include {
        if (it.isDirectory()) {
            true
        } else {
            def name = it.name
            name.startsWith('Java1')
        }
    }
}

支持kt文件

task makeJar(dependsOn: ['compileReleaseJavaWithJavac'], type: Jar) {
    delete 'build/libs/kotlin_and_java.jar' //生成的jar存放路径
    appendix = "demo"
    baseName = "androidJar"
    version = "1.0.0"
    classifier = "release"
    //后缀名
    extension = "jar"
    //最终的 Jar 包名,如果没设置,默认为 [baseName]-[appendix]-[version]-[classifier].[extension]
    archiveName = "kotlin_and_java.jar"
    //需打包的资源所在的路径集
    def srcClassesDir1 = [project.buildDir.absolutePath + "/tmp/kotlin-classes/release"] //Kotlin 生成的classes文件路径
    def srcClassesDir2 = [project.buildDir.absolutePath + "/intermediates/classes/release"] //Java 生成的classes文件路径
    //初始化资源路径集
    from srcClassesDir1, srcClassesDir2
    //去除路径集下部分的资源
    exclude "**/R.class"
    exclude "**/R\$*.class"
    //只导入资源路径集下的部分资源
    include "com/turbo/testapplication/**/*.class"
}

之后再AS IDEtasks列表就能看到_makeJar任务. 双击即可运行.

Jar任务Gradle官方API文档

使用Gradle创建jar转换dex文件的任务

/**
 * 此任务需要依赖_makeJar,因为需要拿到jar文件路径
 * */
task _jarToDex(type: Exec, dependsOn: _makeJar) {
    //借助windows的cmd命令行执行
    commandLine 'cmd'

    doFirst {
        //jar文件对象
        def srcFile = file(project.ext.makeJarPath)
        //需要生成的dex文件对象
        def desFile = file(srcFile.parent + "/" + srcFile.name.substring(0, srcFile.name.lastIndexOf(".")) + ".dex")

        //此行可以不需要
        workingDir srcFile.parent

        //拼接dx.bat执行的参数
        def list = []
        list.add("/c")
        list.add("dx")
        list.add("--dex")
        list.add("--output")
        list.add(desFile)
        list.add(project.ext.makeJarPath)

        //设置参数到cmd命令行
        args list
    }
}

执行此任务前, 请确保dx.bat能在命令行中执行.

在这里插入图片描述

此文件在"Android SDK\build-tools\28.0.3\dx.bat", 请将Android SDK\build-tools\28.0.3\路径添加到windowsPATH环境变量中, 即可.

Exec任务Gradle官方API文档


2019-9-6更新

完整可用代码如下:

/**
 * Email:angcyo@126.com
 *
 * 脚本测试环境:
 * com.android.tools.build:gradle:3.5.0
 * gradle-5.4.1-all
 *
 * 要求:
 * 1.正确配置的`java`环境
 * 2.可直接在`命令行(cmd)`运行`dx`命令, `dx`命令配置如下:
 * 请将"{AndroidSDK}\build-tools\{任意版本}\" 路径添加到windows的PATH环境变量中
 *
 * 注意:
 * 如果使用JDK9和以上版本, 出现以下错误:
 *
 * -Djava.ext.dirs=D:\android\sdk\build-tools\29.0.2\lib is not supported.  Use -classpath instead.
 * Error: Could not create the Java Virtual Machine.
 * Error: A fatal exception has occurred. Program will exit.
 *
 * 请参考: https://www.jianshu.com/p/77db2ea8098f
 *
 * @author angcyo* @date 2019/09/06
 * Copyright (c) 2019 ShenZhen O&M Cloud Co., Ltd. All rights reserved.
 */

ext.dexConfig = [

        //需要打包的包名(包含包名下的所有类)
        "includePackageNames": [
                "com/angcyo/uikitdemo/dex",
                "com/angcyo/uikitdemo/dex2"
        ],
        //文件名 (默认是工程名+时间的组合)
        "dexFileName"        : "",
        //当前版本
        "versionCode"        : "1",
        "versionName"        : "v1.0.0",

        //内部使用
        "jarPath"            : "",
        "dexPath"            : ""
]


task _makeDex() {
    dependsOn("jarToDex")

    doFirst {
        println "开始打包dex文件:$dexConfig.includePackageNames"
    }

    doLast {
        println "打包完成:$dexConfig.dexPath"
    }
}


/**
 * 这里的依赖任务`compileApkReleaseJavaWithJavac`请根据"compile(.*)JavaWithJavac"匹配规则
 * 找到自己工程对应任务名.
 *
 * 此任务执行后, 才会生成kotlin语言对应的 .class 文件.
 * */
task makeJar(dependsOn: ['compileApkReleaseJavaWithJavac'], type: Jar) {

    //需要打包进jar的包名(此包名下的所有class)
    def includePackageNames = dexConfig.includePackageNames

    //编译类型 风味类型
    def buildFlavors = "apkRelease"
    def buildDir = project.buildDir.getAbsolutePath()

    def javaClassPath = "$buildDir/intermediates/javac/$buildFlavors/classes"
    def kotlinClassPath = "$buildDir/tmp/kotlin-classes/$buildFlavors"

    //jar 输出目录
    destinationDirectory.set(rootProject.file("dex"))

    //名字规则
    //[archiveBaseName]-[archiveAppendix]-[archiveVersion]-[archiveClassifier].[archiveExtension]
    //jar 文件名

    if (dexConfig.dexFileName.isEmpty()) {
        archiveBaseName.set(project.name)
        def time = new Date().format("yyyy-MM-dd_HH-mm", TimeZone.getTimeZone("Asia/Shanghai"))
        archiveAppendix.set(time)
    } else {
        archiveBaseName.set(dexConfig.dexFileName)
    }

    archiveVersion.set(dexConfig.versionName)
    archiveExtension.set("jar")

    //archiveClassifier.set("all")

    //复制文件的源路径
    from kotlinClassPath, javaClassPath
    //需要匹配的规则, 如果未设置, 则全部复制
    //include javaClassPath, kotlinClassPath

    //需要匹配的规则, 如果未设置, 则全部不排除
    //exclude

    include { fileTree ->
        includePackageNames.any {
            it.startsWith(fileTree.path)
        } || includePackageNames.any {
            fileTree.path.startsWith(it)
        }
    }

    //写入jar文件中的 META-INF/MANIFEST.MF 文件的信息
    manifest {
        attributes["Build-Time"] = new Date().format("yyyy-MM-dd_HH-mm-ss", TimeZone.getTimeZone("Asia/Shanghai"))
        attributes["Author"] = "angcyo"
        attributes["Copyright"] = "Wayto"
        attributes["versionName"] = dexConfig.versionName
        attributes["versionCode"] = dexConfig.versionCode
    }

    dexConfig.jarPath = archiveFile.get().getAsFile().getAbsolutePath()
}

task jarToDex(dependsOn: ['makeJar'], type: Exec) {
    //借助windows的cmd命令行执行
    commandLine 'cmd'

    doFirst {
        //jar文件对象
        def srcFile = file(dexConfig.jarPath)
        //需要生成的dex文件对象
        def desFile = file(srcFile.parent + "/" + srcFile.name.substring(0, srcFile.name.lastIndexOf(".")) + ".dex")

        dexConfig.dexPath = desFile.getAbsolutePath()

        //此行可以不需要
        workingDir srcFile.parent

        //拼接dx.bat执行的参数
        def list = []
        list.add("/c")
        list.add("dx")
        list.add("--dex")
        list.add("--output")
        list.add(desFile)
        list.add(dexConfig.jarPath)

        //设置参数到cmd命令行
        args list
    }
}


群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.

联系作者

点此快速加群

请使用QQ扫码加群, 小伙伴们都在等着你哦!

关注我的公众号, 每天都能一起玩耍哦!

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页