mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-27 00:38:11 -07:00
Add support for predexing.
This commit is contained in:
parent
20167caae9
commit
84cc83d8b1
3 changed files with 87 additions and 29 deletions
|
@ -31,8 +31,10 @@ class AndroidFiles {
|
||||||
fun explodedManifest(project: Project, mavenId: MavenId) =
|
fun explodedManifest(project: Project, mavenId: MavenId) =
|
||||||
KFiles.joinDir(exploded(project, mavenId), "AndroidManifest.xml")
|
KFiles.joinDir(exploded(project, mavenId), "AndroidManifest.xml")
|
||||||
|
|
||||||
fun explodedClassesJar(project: Project, mavenId: MavenId) =
|
fun aarClassesJar(dir: String) = KFiles.joinDir(dir, "classes.jar")
|
||||||
KFiles.joinDir(exploded(project, mavenId), "classes.jar")
|
|
||||||
|
fun explodedClassesJar(project: Project, mavenId: MavenId) = aarClassesJar(
|
||||||
|
KFiles.joinDir(exploded(project, mavenId)))
|
||||||
|
|
||||||
fun classesDir(project: Project, variant: Variant): String =
|
fun classesDir(project: Project, variant: Variant): String =
|
||||||
KFiles.joinDir(project.directory, project.buildDirectory, variant.toIntermediateDir(), "classes")
|
KFiles.joinDir(project.directory, project.buildDirectory, variant.toIntermediateDir(), "classes")
|
||||||
|
@ -55,5 +57,8 @@ class AndroidFiles {
|
||||||
fun androidHome(project: Project?, config: AndroidConfig) = androidHomeNoThrows(project, config) ?:
|
fun androidHome(project: Project?, config: AndroidConfig) = androidHomeNoThrows(project, config) ?:
|
||||||
throw IllegalArgumentException("Neither androidHome nor \$ANDROID_HOME were defined")
|
throw IllegalArgumentException("Neither androidHome nor \$ANDROID_HOME were defined")
|
||||||
|
|
||||||
|
fun preDexed(project: Project, variant: Variant) =
|
||||||
|
KFiles.joinAndMakeDir(intermediates(project), "pre-dexed", variant.toIntermediateDir())
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,23 @@ import java.io.FileInputStream
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Android plug-in which executes:
|
||||||
|
* library dependencies (android.library.reference.N)
|
||||||
|
* ndk
|
||||||
|
* aidl
|
||||||
|
* renderscript
|
||||||
|
* BuildConfig.java
|
||||||
|
* aapt
|
||||||
|
* compile
|
||||||
|
* obfuscate
|
||||||
|
* dex
|
||||||
|
* png crunch
|
||||||
|
* package resources
|
||||||
|
* package apk
|
||||||
|
* sign
|
||||||
|
* zipalign
|
||||||
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
val executors: KobaltExecutors, val dependencyManager: DependencyManager)
|
val executors: KobaltExecutors, val dependencyManager: DependencyManager)
|
||||||
|
@ -85,12 +102,15 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
private fun apk(project: Project, flavor: String)
|
private fun apk(project: Project, flavor: String)
|
||||||
= KFiles.joinFileAndMakeDir(project.buildDirectory, "outputs", "apk", "${project.name}$flavor.apk")
|
= KFiles.joinFileAndMakeDir(project.buildDirectory, "outputs", "apk", "${project.name}$flavor.apk")
|
||||||
|
|
||||||
|
private val preDexFiles = arrayListOf<String>()
|
||||||
|
|
||||||
@Task(name = "generateR", description = "Generate the R.java file",
|
@Task(name = "generateR", description = "Generate the R.java file",
|
||||||
runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
|
runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
|
||||||
fun taskGenerateRFile(project: Project): TaskResult {
|
fun taskGenerateRFile(project: Project): TaskResult {
|
||||||
|
|
||||||
val resDir = "temporaryBogusResDir"
|
val resDir = "temporaryBogusResDir"
|
||||||
val aarDependencies = explodeAarFiles(project, File(resDir))
|
val aarDependencies = explodeAarFiles(project, File(resDir))
|
||||||
|
preDexFiles.addAll(preDex(project, context.variant, aarDependencies))
|
||||||
val rDirectory = KFiles.joinAndMakeDir(KFiles.generatedSourceDir(project, context.variant, "r"))
|
val rDirectory = KFiles.joinAndMakeDir(KFiles.generatedSourceDir(project, context.variant, "r"))
|
||||||
extraSourceDirectories.add(File(rDirectory))
|
extraSourceDirectories.add(File(rDirectory))
|
||||||
KobaltResourceMerger().run(project, context.variant, configurationFor(project)!!, aarDependencies, rDirectory)
|
KobaltResourceMerger().run(project, context.variant, configurationFor(project)!!, aarDependencies, rDirectory)
|
||||||
|
@ -98,6 +118,33 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
return TaskResult(true)
|
return TaskResult(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predex all the libraries that need to be predexed then return a list of them.
|
||||||
|
*/
|
||||||
|
private fun preDex(project: Project, variant: Variant, aarDependencies: List<File>) : List<String> {
|
||||||
|
log(2, "Predexing")
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
val aarFiles = aarDependencies.map { File(AndroidFiles.aarClassesJar(it.path))}
|
||||||
|
val jarFiles = dependencies(project).map { File(it) }
|
||||||
|
val allDependencies = (aarFiles + jarFiles).toHashSet().filter { it.exists() }
|
||||||
|
|
||||||
|
allDependencies.forEach { dep ->
|
||||||
|
val versionFile = File(dep.path).parentFile
|
||||||
|
val artifactFile = versionFile.parentFile
|
||||||
|
val name = artifactFile.name + "-" + versionFile.name
|
||||||
|
val outputDir = AndroidFiles.preDexed(project, variant)
|
||||||
|
val outputFile = File(outputDir, name + ".jar")
|
||||||
|
if (! outputFile.exists()) {
|
||||||
|
log(2, " Predexing $dep")
|
||||||
|
runDex(project, outputFile.path, dep.path)
|
||||||
|
} else {
|
||||||
|
log(2, " $dep already predexed")
|
||||||
|
}
|
||||||
|
result.add(outputFile.path)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aapt returns 0 even if it fails, so in order to detect whether it failed, we are checking
|
* aapt returns 0 even if it fails, so in order to detect whether it failed, we are checking
|
||||||
* if its error stream contains anything.
|
* if its error stream contains anything.
|
||||||
|
@ -117,6 +164,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
* which will be added to the classpath at compile time via the classpath interceptor.
|
* which will be added to the classpath at compile time via the classpath interceptor.
|
||||||
*/
|
*/
|
||||||
private fun explodeAarFiles(project: Project, resDir: File) : List<File> {
|
private fun explodeAarFiles(project: Project, resDir: File) : List<File> {
|
||||||
|
log(2, "Exploding aars")
|
||||||
val result = arrayListOf<File>()
|
val result = arrayListOf<File>()
|
||||||
project.compileDependencies.filter {
|
project.compileDependencies.filter {
|
||||||
it.jarFile.get().name.endsWith(".aar")
|
it.jarFile.get().name.endsWith(".aar")
|
||||||
|
@ -197,6 +245,32 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
return TaskResult()
|
return TaskResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun dependencies(project: Project) = dependencyManager.calculateDependencies(project, context, projects,
|
||||||
|
project.compileDependencies).map {
|
||||||
|
it.jarFile.get().path
|
||||||
|
}.filterNot {
|
||||||
|
it.contains("android.jar") || it.endsWith(".aar") || it.contains("retrolambda")
|
||||||
|
}.toHashSet().toTypedArray()
|
||||||
|
|
||||||
|
class DexCommand : RunCommand("java") {
|
||||||
|
override fun isSuccess(callSucceeded: Boolean, input: List<String>, error: List<String>) =
|
||||||
|
error.size == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runDex(project: Project, outputJarFile: String, target: String) {
|
||||||
|
// DexProcessBuilder(File(jarFile)).
|
||||||
|
DexCommand().run(listOf(
|
||||||
|
"-cp", KFiles.joinDir(androidHome(project), "build-tools", buildToolsVersion(project), "lib", "dx.jar"),
|
||||||
|
"com.android.dx.command.Main",
|
||||||
|
"--dex",
|
||||||
|
if (KobaltLogger.LOG_LEVEL == 3) "--verbose" else "",
|
||||||
|
"--num-threads=4",
|
||||||
|
"--output", outputJarFile,
|
||||||
|
*(preDexFiles.toTypedArray()),
|
||||||
|
target
|
||||||
|
).filter { it != "" })
|
||||||
|
}
|
||||||
|
|
||||||
@Task(name = TASK_GENERATE_DEX, description = "Generate the dex file", runBefore = arrayOf("assemble"),
|
@Task(name = TASK_GENERATE_DEX, description = "Generate the dex file", runBefore = arrayOf("assemble"),
|
||||||
runAfter = arrayOf("compile"))
|
runAfter = arrayOf("compile"))
|
||||||
fun taskGenerateDex(project: Project): TaskResult {
|
fun taskGenerateDex(project: Project): TaskResult {
|
||||||
|
@ -212,30 +286,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
val classesDex = "classes.dex"
|
val classesDex = "classes.dex"
|
||||||
val outClassesDex = KFiles.joinDir(classesDexDir, classesDex)
|
val outClassesDex = KFiles.joinDir(classesDexDir, classesDex)
|
||||||
|
|
||||||
val javaExecutable = JavaInfo.create(File(SystemProperties.javaBase)).javaExecutable!!
|
runDex(project, outClassesDex, project.classesDir(context))
|
||||||
|
|
||||||
val dependencies = dependencyManager.calculateDependencies(project, context, projects,
|
|
||||||
project.compileDependencies).map {
|
|
||||||
it.jarFile.get().path
|
|
||||||
}.filterNot {
|
|
||||||
it.contains("android.jar") || it.endsWith(".aar")
|
|
||||||
|| it.contains("retrolambda")
|
|
||||||
}.toHashSet().toTypedArray()
|
|
||||||
|
|
||||||
class DexCommand : RunCommand(javaExecutable.absolutePath) {
|
|
||||||
override fun isSuccess(callSucceeded: Boolean, input: List<String>, error: List<String>) =
|
|
||||||
error.size == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
DexCommand().run(listOf(
|
|
||||||
"-cp", KFiles.joinDir(androidHome(project), "build-tools", buildToolsVersion(project), "lib", "dx.jar"),
|
|
||||||
"com.android.dx.command.Main",
|
|
||||||
"--dex", "--verbose", "--num-threads=4",
|
|
||||||
"--output", outClassesDex,
|
|
||||||
*dependencies,
|
|
||||||
// KFiles.joinDir(AndroidFiles.intermediates(project), "dex", context.variant.toIntermediateDir()),
|
|
||||||
project.classesDir(context)
|
|
||||||
))
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add classes.dex to existing .ap_
|
// Add classes.dex to existing .ap_
|
||||||
|
@ -389,7 +440,7 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
||||||
val result = arrayListOf<IClasspathDependency>()
|
val result = arrayListOf<IClasspathDependency>()
|
||||||
dependencies.forEach {
|
dependencies.forEach {
|
||||||
if (it is MavenDependency && (isAar(it.mavenId) || it.mavenId.packaging == "aar")) {
|
if (it is MavenDependency && (isAar(it.mavenId) || it.mavenId.packaging == "aar")) {
|
||||||
val newDep = FileDependency(AndroidFiles.classesJar(project, it.mavenId))
|
val newDep = FileDependency(AndroidFiles.explodedClassesJar(project, it.mavenId))
|
||||||
result.add(newDep)
|
result.add(newDep)
|
||||||
val id = MavenId.create(it.groupId, it.artifactId, "aar", it.version)
|
val id = MavenId.create(it.groupId, it.artifactId, "aar", it.version)
|
||||||
result.add(MavenDependency.create(id))
|
result.add(MavenDependency.create(id))
|
||||||
|
|
|
@ -82,6 +82,8 @@ class KobaltResourceMerger {
|
||||||
val logger = StdLogger(level)
|
val logger = StdLogger(level)
|
||||||
val androidBuilder = createAndroidBuilder(project, config, logger)
|
val androidBuilder = createAndroidBuilder(project, config, logger)
|
||||||
|
|
||||||
|
log(2, "Merging resources")
|
||||||
|
|
||||||
//
|
//
|
||||||
// Assets
|
// Assets
|
||||||
//
|
//
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue