借助强大的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 IDE
的tasks列表
就能看到_makeJar
任务. 双击即可运行.
使用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\
路径添加到windows
的PATH
环境变量中, 即可.
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扫码加群, 小伙伴们都在等着你哦!
关注我的公众号, 每天都能一起玩耍哦!