mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-27 08:38:13 -07:00
Remove the Android plug-in from the core.
It's now in its own project.
This commit is contained in:
parent
05d4571a9a
commit
643c85f1a4
9 changed files with 1 additions and 1035 deletions
|
@ -115,8 +115,7 @@ val kobaltApp = kotlinProject(kobaltPluginApi, wrapper) {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Used by the plugins
|
// Used by the plugins
|
||||||
compile("com.android.tools.build:builder:2.0.0-alpha3",
|
compile("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.0-beta-3595",
|
||||||
"org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.0-beta-3595",
|
|
||||||
"org.jetbrains.dokka:dokka-fatjar:0.9.3")
|
"org.jetbrains.dokka:dokka-fatjar:0.9.3")
|
||||||
|
|
||||||
// Used by the main app
|
// Used by the main app
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.beust.kobalt.api.Project
|
|
||||||
import com.beust.kobalt.misc.RunCommand
|
|
||||||
import com.beust.kobalt.misc.log
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
open class AndroidCommand(project: Project, androidHome: String, command: String, cwd: File = File(project.directory))
|
|
||||||
: RunCommand(command) {
|
|
||||||
init {
|
|
||||||
env.put("ANDROID_HOME", androidHome)
|
|
||||||
directory = cwd
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun call(args: List<String>) = run(args,
|
|
||||||
successCallback = { output ->
|
|
||||||
log(1, "$command succeeded:")
|
|
||||||
output.forEach {
|
|
||||||
log(1, " $it")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
errorCallback = { output ->
|
|
||||||
with(StringBuilder()) {
|
|
||||||
append("Error running $command:")
|
|
||||||
output.forEach {
|
|
||||||
append(" $it")
|
|
||||||
}
|
|
||||||
error(this.toString())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.beust.kobalt.Variant
|
|
||||||
import com.beust.kobalt.api.KobaltContext
|
|
||||||
import com.beust.kobalt.api.Project
|
|
||||||
import com.beust.kobalt.maven.MavenId
|
|
||||||
import com.beust.kobalt.misc.KFiles
|
|
||||||
|
|
||||||
class AndroidFiles {
|
|
||||||
companion object {
|
|
||||||
fun intermediates(project: Project) = KFiles.joinDir(project.directory, project.buildDirectory,
|
|
||||||
"intermediates")
|
|
||||||
|
|
||||||
fun manifest(project: Project, context: KobaltContext) =
|
|
||||||
KFiles.joinDir(project.directory, "src", "main", "AndroidManifest.xml")
|
|
||||||
|
|
||||||
fun mergedManifest(project: Project, variant: Variant) : String {
|
|
||||||
val dir = KFiles.joinAndMakeDir(intermediates(project), "manifests", "full", variant.toIntermediateDir())
|
|
||||||
return KFiles.joinDir(dir, "AndroidManifest.xml")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergedResourcesNoVariant(project: Project) =
|
|
||||||
KFiles.joinAndMakeDir(AndroidFiles.intermediates(project), "res", "merged")
|
|
||||||
|
|
||||||
fun mergedResources(project: Project, variant: Variant) =
|
|
||||||
KFiles.joinAndMakeDir(mergedResourcesNoVariant(project), variant.toIntermediateDir())
|
|
||||||
|
|
||||||
fun exploded(project: Project, mavenId: MavenId) = KFiles.joinAndMakeDir(
|
|
||||||
intermediates(project), "exploded-aar", mavenId.groupId, mavenId.artifactId, mavenId.version!!)
|
|
||||||
|
|
||||||
fun explodedManifest(project: Project, mavenId: MavenId) =
|
|
||||||
KFiles.joinDir(exploded(project, mavenId), "AndroidManifest.xml")
|
|
||||||
|
|
||||||
fun aarClassesJar(dir: String) = KFiles.joinDir(dir, "classes.jar")
|
|
||||||
|
|
||||||
fun explodedClassesJar(project: Project, mavenId: MavenId) = aarClassesJar(
|
|
||||||
KFiles.joinDir(exploded(project, mavenId)))
|
|
||||||
|
|
||||||
fun classesDir(project: Project, variant: Variant): String =
|
|
||||||
KFiles.joinDir(project.directory, project.buildDirectory, variant.toIntermediateDir(), "classes")
|
|
||||||
|
|
||||||
fun temporaryApk(project: Project, flavor: String)
|
|
||||||
= KFiles.joinFileAndMakeDir(AndroidFiles.intermediates(project), "res", "resources$flavor.ap_")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the android home define on the project if any, otherwise use the environment variable.
|
|
||||||
*/
|
|
||||||
fun androidHomeNoThrows(project: Project?, config: AndroidConfig?): String? {
|
|
||||||
var result = System.getenv("ANDROID_HOME")
|
|
||||||
if (project != null && config?.androidHome != null) {
|
|
||||||
result = config?.androidHome
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun androidHome(project: Project?, config: AndroidConfig) = androidHomeNoThrows(project, config) ?:
|
|
||||||
throw IllegalArgumentException("Neither androidHome nor \$ANDROID_HOME were defined")
|
|
||||||
|
|
||||||
fun preDexed(project: Project, variant: Variant) =
|
|
||||||
KFiles.joinAndMakeDir(intermediates(project), "pre-dexed", variant.toIntermediateDir())
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import java.io.InputStream
|
|
||||||
import javax.xml.bind.JAXBContext
|
|
||||||
import javax.xml.bind.annotation.XmlAttribute
|
|
||||||
import javax.xml.bind.annotation.XmlElement
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse AndroidManifest.xml and expose its content.
|
|
||||||
*/
|
|
||||||
class AndroidManifest(val ins: InputStream) {
|
|
||||||
companion object {
|
|
||||||
const val NAMESPACE = "http://schemas.android.com/apk/res/android"
|
|
||||||
}
|
|
||||||
|
|
||||||
val manifest: AndroidManifestXml by lazy {
|
|
||||||
val jaxbContext = JAXBContext.newInstance(AndroidManifestXml::class.java)
|
|
||||||
jaxbContext.createUnmarshaller().unmarshal(ins) as AndroidManifestXml
|
|
||||||
}
|
|
||||||
|
|
||||||
val pkg by lazy {
|
|
||||||
manifest.pkg
|
|
||||||
}
|
|
||||||
|
|
||||||
val mainActivity: String? by lazy {
|
|
||||||
fun isLaunch(act: ActivityXml) : Boolean {
|
|
||||||
val r = act.intentFilters.filter { inf: IntentFilter ->
|
|
||||||
inf.action?.name == "android.intent.action.MAIN" &&
|
|
||||||
inf.category?.name == "android.intent.category.LAUNCHER"
|
|
||||||
}
|
|
||||||
return r.size > 0
|
|
||||||
}
|
|
||||||
val act = manifest.application?.activities?.filter { isLaunch(it) }
|
|
||||||
if (act != null && act.size > 0) {
|
|
||||||
act.get(0).name?.let { n ->
|
|
||||||
if (n.startsWith(".")) pkg + "." + n.substring(1) else n
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@XmlRootElement(name = "manifest")
|
|
||||||
class AndroidManifestXml {
|
|
||||||
@XmlAttribute(name = "package") @JvmField
|
|
||||||
val pkg: String? = null
|
|
||||||
var application: ApplicationXml? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class ApplicationXml {
|
|
||||||
@XmlElement(name = "activity") @JvmField
|
|
||||||
var activities: List<ActivityXml> = arrayListOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActivityXml {
|
|
||||||
@XmlAttribute(namespace = AndroidManifest.NAMESPACE, name = "name") @JvmField
|
|
||||||
var name: String? = null
|
|
||||||
|
|
||||||
@XmlElement(name = "intent-filter") @JvmField
|
|
||||||
var intentFilters: List<IntentFilter> = arrayListOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
class IntentFilter {
|
|
||||||
var action: ActionXml? = null
|
|
||||||
var category: CategoryXml? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActionXml {
|
|
||||||
@XmlAttribute(namespace = AndroidManifest.NAMESPACE, name = "name") @JvmField
|
|
||||||
var name: String? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
class CategoryXml {
|
|
||||||
@XmlAttribute(namespace = AndroidManifest.NAMESPACE, name = "name") @JvmField
|
|
||||||
var name: String? = null
|
|
||||||
}
|
|
|
@ -1,535 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.beust.kobalt.*
|
|
||||||
import com.beust.kobalt.api.*
|
|
||||||
import com.beust.kobalt.api.annotation.Directive
|
|
||||||
import com.beust.kobalt.api.annotation.IncrementalTask
|
|
||||||
import com.beust.kobalt.api.annotation.Task
|
|
||||||
import com.beust.kobalt.maven.DependencyManager
|
|
||||||
import com.beust.kobalt.maven.MavenId
|
|
||||||
import com.beust.kobalt.maven.Md5
|
|
||||||
import com.beust.kobalt.maven.dependency.FileDependency
|
|
||||||
import com.beust.kobalt.maven.dependency.MavenDependency
|
|
||||||
import com.beust.kobalt.misc.*
|
|
||||||
import com.beust.kobalt.plugin.java.JavaCompiler
|
|
||||||
import com.google.common.collect.HashMultimap
|
|
||||||
import com.google.inject.Inject
|
|
||||||
import com.google.inject.Singleton
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.nio.file.Path
|
|
||||||
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
|
|
||||||
public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler,
|
|
||||||
val executors: KobaltExecutors, val dependencyManager: DependencyManager, val taskContributor : TaskContributor)
|
|
||||||
: ConfigPlugin<AndroidConfig>(), IClasspathContributor, IRepoContributor, ICompilerFlagContributor,
|
|
||||||
ICompilerInterceptor, IBuildDirectoryIncerceptor, IRunnerContributor, IClasspathInterceptor,
|
|
||||||
ISourceDirectoryContributor, IBuildConfigFieldContributor, ITaskContributor, IMavenIdInterceptor {
|
|
||||||
companion object {
|
|
||||||
const val PLUGIN_NAME = "Android"
|
|
||||||
const val TASK_GENERATE_DEX = "generateDex"
|
|
||||||
const val TASK_SIGN_APK = "signApk"
|
|
||||||
const val TASK_INSTALL= "install"
|
|
||||||
}
|
|
||||||
|
|
||||||
override val name = PLUGIN_NAME
|
|
||||||
|
|
||||||
fun isAndroid(project: Project) = configurationFor(project) != null
|
|
||||||
|
|
||||||
override fun apply(project: Project, context: KobaltContext) {
|
|
||||||
super.apply(project, context)
|
|
||||||
if (accept(project)) {
|
|
||||||
project.compileDependencies.add(FileDependency(androidJar(project).toString()))
|
|
||||||
|
|
||||||
taskContributor.addVariantTasks(this, project, context, "generateR", runBefore = listOf("compile"),
|
|
||||||
runTask = { taskGenerateRFile(project) })
|
|
||||||
taskContributor.addIncrementalVariantTasks(this, project, context, "generateDex",
|
|
||||||
runAfter = listOf ("compile"),
|
|
||||||
runBefore = listOf("assemble"),
|
|
||||||
runTask = { taskGenerateDex(project) })
|
|
||||||
taskContributor.addVariantTasks(this, project, context, "signApk", runAfter = listOf("generateDex"),
|
|
||||||
runBefore = listOf("assemble"),
|
|
||||||
runTask = { taskSignApk(project) })
|
|
||||||
taskContributor.addVariantTasks(this, project, context, "install", runAfter = listOf("signApk"),
|
|
||||||
runTask = { taskInstall(project) })
|
|
||||||
taskContributor.addVariantTasks(this, project, context, "proguard", runBefore = listOf("install"),
|
|
||||||
runAfter = listOf("compile"),
|
|
||||||
runTask = { taskProguard(project) })
|
|
||||||
}
|
|
||||||
context.pluginInfo.classpathContributors.add(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun accept(project: Project) = isAndroid(project)
|
|
||||||
|
|
||||||
fun compileSdkVersion(project: Project) = configurationFor(project)?.compileSdkVersion
|
|
||||||
|
|
||||||
fun buildToolsVersion(project: Project): String {
|
|
||||||
val version = configurationFor(project)?.buildToolsVersion
|
|
||||||
if (OperatingSystem.current().isWindows() && version == "21.1.2")
|
|
||||||
return "build-tools-$version"
|
|
||||||
else
|
|
||||||
return version as String
|
|
||||||
}
|
|
||||||
|
|
||||||
fun androidHome(project: Project?) = AndroidFiles.androidHome(project, configurationFor(project)!!)
|
|
||||||
|
|
||||||
fun androidJar(project: Project): Path =
|
|
||||||
Paths.get(androidHome(project), "platforms", "android-${compileSdkVersion(project)}", "android.jar")
|
|
||||||
|
|
||||||
private fun aapt(project: Project) = "${androidHome(project)}/build-tools/${buildToolsVersion(project)}/aapt"
|
|
||||||
|
|
||||||
private fun adb(project: Project) = "${androidHome(project)}/platform-tools/adb"
|
|
||||||
|
|
||||||
private fun apk(project: Project, flavor: String)
|
|
||||||
= KFiles.joinFileAndMakeDir(project.buildDirectory, "outputs", "apk", "${project.name}$flavor.apk")
|
|
||||||
|
|
||||||
private val preDexFiles = arrayListOf<String>()
|
|
||||||
|
|
||||||
@Task(name = "generateR", description = "Generate the R.java file",
|
|
||||||
runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
|
|
||||||
fun taskGenerateRFile(project: Project): TaskResult {
|
|
||||||
|
|
||||||
val aarDependencies = explodeAarFiles(project)
|
|
||||||
preDexFiles.addAll(preDex(project, context.variant, aarDependencies))
|
|
||||||
val rDirectory = KFiles.joinAndMakeDir(KFiles.generatedSourceDir(project, context.variant, "r"))
|
|
||||||
extraSourceDirectories.add(File(rDirectory))
|
|
||||||
KobaltResourceMerger().run(project, context.variant, configurationFor(project)!!, aarDependencies, rDirectory)
|
|
||||||
|
|
||||||
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
|
|
||||||
* if its error stream contains anything.
|
|
||||||
*/
|
|
||||||
inner class AaptCommand(project: Project, aapt: String, val aaptCommand: String,
|
|
||||||
cwd: File = File(".")) : AndroidCommand(project, androidHome(project), aapt) {
|
|
||||||
init {
|
|
||||||
directory = cwd
|
|
||||||
useErrorStreamAsErrorIndicator = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun call(args: List<String>) = super.run(arrayListOf(aaptCommand) + args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract all the .aar files found in the dependencies and add their android.jar to classpathEntries,
|
|
||||||
* which will be added to the classpath at compile time via the classpath interceptor.
|
|
||||||
*/
|
|
||||||
private fun explodeAarFiles(project: Project) : List<File> {
|
|
||||||
log(2, "Exploding aars")
|
|
||||||
val result = arrayListOf<File>()
|
|
||||||
project.compileDependencies.filter {
|
|
||||||
it.jarFile.get().name.endsWith(".aar")
|
|
||||||
}.forEach {
|
|
||||||
val mavenId = MavenId.create(it.id)
|
|
||||||
val destDir = File(AndroidFiles.exploded(project, mavenId))
|
|
||||||
if (!File(AndroidFiles.explodedManifest(project, mavenId)).exists()) {
|
|
||||||
log(2, " Exploding ${it.jarFile.get()} to $destDir")
|
|
||||||
JarUtils.extractJarFile(it.jarFile.get(), destDir)
|
|
||||||
} else {
|
|
||||||
log(2, " $destDir already exists, not extracting again")
|
|
||||||
}
|
|
||||||
val classesJar = AndroidFiles.explodedClassesJar(project, mavenId)
|
|
||||||
|
|
||||||
// Add the classses.jar of this .aar to the classpath entries (which are returned via IClasspathContributor)
|
|
||||||
classpathEntries.put(project.name, FileDependency(classesJar))
|
|
||||||
// Also add all the jar files found in the libs/ directory
|
|
||||||
File(destDir, "libs").let { libsDir ->
|
|
||||||
if (libsDir.exists()) {
|
|
||||||
libsDir.listFiles().filter { it.name.endsWith(".jar") }.forEach {
|
|
||||||
classpathEntries.put(project.name, FileDependency(it.absolutePath))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.add(destDir)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements ICompilerFlagContributor
|
|
||||||
* Make sure we compile and generate 1.6 sources unless the build file defined those (which can
|
|
||||||
* happen if the developer is using RetroLambda for example).
|
|
||||||
*/
|
|
||||||
override fun flagsFor(project: Project, context: KobaltContext, currentFlags: List<String>) : List<String> {
|
|
||||||
if (isAndroid(project)) {
|
|
||||||
var found = currentFlags.any { it == "-source" || it == "-target" }
|
|
||||||
val result = arrayListOf<String>().apply { addAll(currentFlags) }
|
|
||||||
if (! found) {
|
|
||||||
result.add("-source")
|
|
||||||
result.add("1.6")
|
|
||||||
result.add("-target")
|
|
||||||
result.add("1.6")
|
|
||||||
result.add("-nowarn")
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Task(name = "proguard", description = "Run Proguard, if enabled", runBefore = arrayOf(TASK_GENERATE_DEX),
|
|
||||||
runAfter = arrayOf("compile"))
|
|
||||||
fun taskProguard(project: Project): TaskResult {
|
|
||||||
val config = configurationFor(project)
|
|
||||||
if (config != null) {
|
|
||||||
val buildType = context.variant.buildType
|
|
||||||
if (buildType.minifyEnabled) {
|
|
||||||
log(1, "minifyEnabled is true, running Proguard")
|
|
||||||
val classesDir = project.classesDir(context)
|
|
||||||
val proguardHome = KFiles.joinDir(androidHome(project), "tools", "proguard")
|
|
||||||
val proguardCommand = KFiles.joinDir(proguardHome, "bin", "proguard.sh")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 inputChecksum(classDirectory: String) = Md5.toMd5Directories(listOf(File(classDirectory)))
|
|
||||||
|
|
||||||
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 != "" })
|
|
||||||
}
|
|
||||||
|
|
||||||
@IncrementalTask(name = TASK_GENERATE_DEX, description = "Generate the dex file", runBefore = arrayOf("assemble"),
|
|
||||||
runAfter = arrayOf("compile"))
|
|
||||||
fun taskGenerateDex(project: Project): IncrementalTaskInfo {
|
|
||||||
File(project.classesDir(context)).mkdirs()
|
|
||||||
return IncrementalTaskInfo(
|
|
||||||
inputChecksum = inputChecksum(project.classesDir(context)),
|
|
||||||
outputChecksum = "1",
|
|
||||||
task = { project -> doTaskGenerateDex(project) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun doTaskGenerateDex(project: Project): TaskResult {
|
|
||||||
//
|
|
||||||
// Call dx to generate classes.dex
|
|
||||||
//
|
|
||||||
val buildToolsDir = buildToolsVersion(project)
|
|
||||||
val dx = "${androidHome(project)}/build-tools/$buildToolsDir/dx" +
|
|
||||||
if (OperatingSystem.current().isWindows()) ".bat" else ""
|
|
||||||
val classesDexDir = KFiles.joinDir(AndroidFiles.intermediates(project), "dex",
|
|
||||||
context.variant.toIntermediateDir())
|
|
||||||
File(classesDexDir).mkdirs()
|
|
||||||
val classesDex = "classes.dex"
|
|
||||||
val outClassesDex = KFiles.joinDir(classesDexDir, classesDex)
|
|
||||||
|
|
||||||
runDex(project, outClassesDex, project.classesDir(context))
|
|
||||||
|
|
||||||
//
|
|
||||||
// Add classes.dex to existing .ap_
|
|
||||||
// Because aapt doesn't handle directory moving, we need to cd to classes.dex's directory so
|
|
||||||
// that classes.dex ends up in the root directory of the .ap_.
|
|
||||||
//
|
|
||||||
AaptCommand(project, aapt(project), "add").apply {
|
|
||||||
directory = File(outClassesDex).parentFile
|
|
||||||
}.call(listOf("-v", KFiles.joinDir(
|
|
||||||
File(AndroidFiles.temporaryApk(project, context.variant.shortArchiveName)).absolutePath), classesDex))
|
|
||||||
|
|
||||||
return TaskResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val DEFAULT_DEBUG_SIGNING_CONFIG = SigningConfig(
|
|
||||||
SigningConfig.DEFAULT_STORE_FILE,
|
|
||||||
SigningConfig.DEFAULT_STORE_PASSWORD,
|
|
||||||
SigningConfig.DEFAULT_KEY_ALIAS,
|
|
||||||
SigningConfig.DEFAULT_KEY_PASSWORD)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sign the apk
|
|
||||||
* Mac:
|
|
||||||
* jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android -signedjar a.apk a.ap_
|
|
||||||
* androiddebugkey
|
|
||||||
*/
|
|
||||||
@Task(name = TASK_SIGN_APK, description = "Sign the apk file", runAfter = arrayOf(TASK_GENERATE_DEX),
|
|
||||||
runBefore = arrayOf("assemble"))
|
|
||||||
fun taskSignApk(project: Project): TaskResult {
|
|
||||||
val apk = apk(project, context.variant.shortArchiveName)
|
|
||||||
val temporaryApk = AndroidFiles.temporaryApk(project, context.variant.shortArchiveName)
|
|
||||||
val buildType = context.variant.buildType.name
|
|
||||||
|
|
||||||
val config = configurationFor(project)
|
|
||||||
var signingConfig = config!!.signingConfigs[buildType]
|
|
||||||
|
|
||||||
if (signingConfig == null && buildType != "debug") {
|
|
||||||
warn("No signingConfig found for product type \"$buildType\", using the \"debug\" signConfig")
|
|
||||||
}
|
|
||||||
|
|
||||||
signingConfig = DEFAULT_DEBUG_SIGNING_CONFIG
|
|
||||||
|
|
||||||
val success = RunCommand("jarsigner").apply {
|
|
||||||
// useInputStreamAsErrorIndicator = true
|
|
||||||
}.run(listOf(
|
|
||||||
"-keystore", signingConfig.storeFile,
|
|
||||||
"-storepass", signingConfig.storePassword,
|
|
||||||
"-keypass", signingConfig.keyPassword,
|
|
||||||
"-signedjar", apk,
|
|
||||||
temporaryApk,
|
|
||||||
signingConfig.keyAlias
|
|
||||||
))
|
|
||||||
log(1, "Created $apk")
|
|
||||||
|
|
||||||
return TaskResult(success == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Task(name = TASK_INSTALL, description = "Install the apk file", runAfter = arrayOf(TASK_GENERATE_DEX, "assemble"))
|
|
||||||
fun taskInstall(project: Project): TaskResult {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adb has weird ways of signaling errors, that's the best I've found so far.
|
|
||||||
*/
|
|
||||||
class AdbInstall : RunCommand(adb(project)) {
|
|
||||||
override fun isSuccess(callSucceeded: Boolean, input: List<String>, error: List<String>)
|
|
||||||
= input.filter { it.contains("Success")}.size > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
val apk = apk(project, context.variant.shortArchiveName)
|
|
||||||
val result = AdbInstall().useErrorStreamAsErrorIndicator(true).run(
|
|
||||||
args = listOf("install", "-r", apk))
|
|
||||||
log(1, "Installed $apk")
|
|
||||||
return TaskResult(result == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val classpathEntries = HashMultimap.create<String, IClasspathDependency>()
|
|
||||||
|
|
||||||
// IClasspathContributor
|
|
||||||
override fun entriesFor(project: Project?): Collection<IClasspathDependency> {
|
|
||||||
return if (project != null) {
|
|
||||||
classpathEntries.get(project.name) ?: emptyList()
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IRepoContributor
|
|
||||||
override fun reposFor(project: Project?): List<HostConfig> {
|
|
||||||
val config = configurationFor(project)
|
|
||||||
var home = AndroidFiles.androidHomeNoThrows(project, config)
|
|
||||||
|
|
||||||
return if (home != null) {
|
|
||||||
val path = Paths.get(KFiles.joinDir(home, "extras", "android", "m2repository"))
|
|
||||||
listOf(HostConfig(path.toUri().toString()))
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IBuildDirectoryInterceptor
|
|
||||||
override fun intercept(project: Project, context: KobaltContext, buildDirectory: String): String {
|
|
||||||
if (isAndroid(project)) {
|
|
||||||
val result = KFiles.joinDir(AndroidFiles.intermediates(project), "classes",
|
|
||||||
context.variant.toIntermediateDir())
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
return buildDirectory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ICompilerInterceptor
|
|
||||||
override fun intercept(project: Project, context: KobaltContext, actionInfo: CompilerActionInfo)
|
|
||||||
: CompilerActionInfo {
|
|
||||||
val result: CompilerActionInfo =
|
|
||||||
if (isAndroid(project)) {
|
|
||||||
val newOutputDir = KFiles.joinDir("kobaltBuild", "intermediates", "classes",
|
|
||||||
context.variant.toIntermediateDir())
|
|
||||||
actionInfo.copy(outputDir = File(newOutputDir))
|
|
||||||
} else {
|
|
||||||
actionInfo
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// IRunContributor
|
|
||||||
override fun affinity(project: Project, context: KobaltContext): Int {
|
|
||||||
val manifest = AndroidFiles.manifest(project, context)
|
|
||||||
return if (File(manifest).exists()) IAffinity.DEFAULT_POSITIVE_AFFINITY else 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(project: Project, context: KobaltContext, classpath: List<IClasspathDependency>): TaskResult {
|
|
||||||
AndroidFiles.mergedManifest(project, context.variant).let { manifestPath ->
|
|
||||||
FileInputStream(File(manifestPath)).use { ins ->
|
|
||||||
// adb shell am start -n com.package.name/com.package.name.ActivityName
|
|
||||||
val manifest = AndroidManifest(ins)
|
|
||||||
RunCommand(adb(project)).useErrorStreamAsErrorIndicator(false).run(args = listOf(
|
|
||||||
"shell", "am", "start", "-n", manifest.pkg + "/" + manifest.mainActivity))
|
|
||||||
return TaskResult()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isAar(id: MavenId) = id.groupId == "com.android.support" && id.artifactId != "support-annotations"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For each com.android.support dependency or aar packaging, add a classpath dependency that points to the
|
|
||||||
* classes.jar inside that (exploded) aar.
|
|
||||||
*/
|
|
||||||
// IClasspathInterceptor
|
|
||||||
override fun intercept(project: Project, dependencies: List<IClasspathDependency>): List<IClasspathDependency> {
|
|
||||||
val result = arrayListOf<IClasspathDependency>()
|
|
||||||
dependencies.forEach {
|
|
||||||
if (it is MavenDependency && (isAar(it.mavenId) || it.mavenId.packaging == "aar")) {
|
|
||||||
val newDep = FileDependency(AndroidFiles.explodedClassesJar(project, it.mavenId))
|
|
||||||
result.add(newDep)
|
|
||||||
val id = MavenId.create(it.groupId, it.artifactId, "aar", it.version)
|
|
||||||
result.add(MavenDependency.create(id))
|
|
||||||
} else {
|
|
||||||
result.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMavenIdInterceptor
|
|
||||||
override fun intercept(mavenId: MavenId) : MavenId =
|
|
||||||
if (isAar(mavenId)) {
|
|
||||||
val version = mavenId.version ?: ""
|
|
||||||
MavenId.createNoInterceptors("${mavenId.groupId}:${mavenId.artifactId}:$version@aar")
|
|
||||||
} else {
|
|
||||||
mavenId
|
|
||||||
}
|
|
||||||
|
|
||||||
private val extraSourceDirectories = arrayListOf<File>()
|
|
||||||
|
|
||||||
// ISourceDirectoryContributor
|
|
||||||
override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List<File> = extraSourceDirectories
|
|
||||||
|
|
||||||
// IBuildConfigFieldContributor
|
|
||||||
override fun fieldsFor(project: Project, context: KobaltContext): List<BuildConfigField> {
|
|
||||||
val result = arrayListOf<BuildConfigField>()
|
|
||||||
configurationFor(project)?.let { config ->
|
|
||||||
result.add(BuildConfigField("String", "VERSION_NAME", "\"${config.defaultConfig.versionName}\""))
|
|
||||||
result.add(BuildConfigField("int", "VERSION_CODE", "${config.defaultConfig.versionCode}"))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
//ITaskContributor
|
|
||||||
override fun tasksFor(context: KobaltContext): List<DynamicTask> = taskContributor.dynamicTasks
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultConfig(var minSdkVersion: Int? = null,
|
|
||||||
val maxSdkVersion: String? = null,
|
|
||||||
var targetSdkVersion: String? = null,
|
|
||||||
var versionCode: Int? = null,
|
|
||||||
var versionName: String? = null) {
|
|
||||||
var buildConfig : BuildConfig? = BuildConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
class AndroidConfig(val project: Project,
|
|
||||||
var compileSdkVersion : String? = null,
|
|
||||||
var buildToolsVersion: String? = null,
|
|
||||||
var applicationId: String? = null,
|
|
||||||
val androidHome: String? = null) {
|
|
||||||
|
|
||||||
val signingConfigs = hashMapOf<String, SigningConfig>()
|
|
||||||
|
|
||||||
fun addSigningConfig(name: String, project: Project, signingConfig: SigningConfig) {
|
|
||||||
signingConfigs.put(name, signingConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultConfig: DefaultConfig = DefaultConfig()
|
|
||||||
|
|
||||||
fun defaultConfig(init: DefaultConfig.() -> Unit) {
|
|
||||||
defaultConfig = DefaultConfig().apply { init() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive
|
|
||||||
fun Project.android(init: AndroidConfig.() -> Unit) : AndroidConfig = let { project ->
|
|
||||||
return AndroidConfig(project).apply {
|
|
||||||
init()
|
|
||||||
(Kobalt.findPlugin(AndroidPlugin.PLUGIN_NAME) as AndroidPlugin).addConfiguration(project, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SigningConfig(var storeFile: String = SigningConfig.DEFAULT_STORE_FILE,
|
|
||||||
var storePassword: String = SigningConfig.DEFAULT_STORE_PASSWORD,
|
|
||||||
var keyAlias: String = SigningConfig.DEFAULT_KEY_ALIAS,
|
|
||||||
var keyPassword: String = SigningConfig.DEFAULT_KEY_ALIAS) {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DEFAULT_STORE_FILE = homeDir(".android", "debug.keystore")
|
|
||||||
val DEFAULT_STORE_PASSWORD = "android"
|
|
||||||
val DEFAULT_KEY_ALIAS = "androiddebugkey"
|
|
||||||
val DEFAULT_KEY_PASSWORD = "android"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive
|
|
||||||
fun AndroidConfig.signingConfig(name: String, init: SigningConfig.() -> Unit) : SigningConfig = let { androidConfig ->
|
|
||||||
SigningConfig().apply {
|
|
||||||
init()
|
|
||||||
androidConfig.addSigningConfig(name, project, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.android.io.FileWrapper
|
|
||||||
import com.android.xml.AndroidManifest
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage the main application id for the app: values from androidConfig{} have precedence over values
|
|
||||||
* found in the manifest.
|
|
||||||
*/
|
|
||||||
class AppInfo(val androidManifest: File, val config: AndroidConfig) {
|
|
||||||
val abstractManifest = FileWrapper(androidManifest)
|
|
||||||
|
|
||||||
val versionCode : Int
|
|
||||||
get() = config.defaultConfig.versionCode ?: AndroidManifest.getVersionCode(abstractManifest)
|
|
||||||
|
|
||||||
val versionName : String
|
|
||||||
get() = config.defaultConfig.versionName ?: versionCode.toString()
|
|
||||||
|
|
||||||
val minSdkVersion: Int
|
|
||||||
get() = config.defaultConfig.minSdkVersion ?: (AndroidManifest.getMinSdkVersion(abstractManifest) as Int)
|
|
||||||
|
|
||||||
val maxSdkVersion: Int?
|
|
||||||
get() = config.defaultConfig.maxSdkVersion?.toInt()
|
|
||||||
|
|
||||||
val targetSdkVersion: String?
|
|
||||||
get() = config.defaultConfig.targetSdkVersion
|
|
||||||
?: AndroidManifest.getTargetSdkVersion(abstractManifest)?.toString()
|
|
||||||
}
|
|
|
@ -1,283 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.android.builder.core.AaptPackageProcessBuilder
|
|
||||||
import com.android.builder.core.AndroidBuilder
|
|
||||||
import com.android.builder.core.ErrorReporter
|
|
||||||
import com.android.builder.core.LibraryRequest
|
|
||||||
import com.android.builder.dependency.ManifestDependency
|
|
||||||
import com.android.builder.dependency.SymbolFileProvider
|
|
||||||
import com.android.builder.model.AaptOptions
|
|
||||||
import com.android.builder.model.SyncIssue
|
|
||||||
import com.android.builder.sdk.DefaultSdkLoader
|
|
||||||
import com.android.builder.sdk.SdkLoader
|
|
||||||
import com.android.ide.common.blame.Message
|
|
||||||
import com.android.ide.common.internal.ExecutorSingleton
|
|
||||||
import com.android.ide.common.process.*
|
|
||||||
import com.android.ide.common.res2.*
|
|
||||||
import com.android.manifmerger.ManifestMerger2
|
|
||||||
import com.android.sdklib.AndroidTargetHash
|
|
||||||
import com.android.sdklib.SdkManager
|
|
||||||
import com.android.utils.ILogger
|
|
||||||
import com.android.utils.StdLogger
|
|
||||||
import com.beust.kobalt.Variant
|
|
||||||
import com.beust.kobalt.api.IClasspathDependency
|
|
||||||
import com.beust.kobalt.api.Project
|
|
||||||
import com.beust.kobalt.maven.dependency.MavenDependency
|
|
||||||
import com.beust.kobalt.misc.KFiles
|
|
||||||
import com.beust.kobalt.misc.KobaltLogger
|
|
||||||
import com.beust.kobalt.misc.log
|
|
||||||
import com.beust.kobalt.misc.logWrap
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class KobaltProcessResult : ProcessResult {
|
|
||||||
override fun getExitValue(): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun assertNormalExitValue(): ProcessResult? {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun rethrowFailure(): ProcessResult? {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KobaltJavaProcessExecutor : JavaProcessExecutor {
|
|
||||||
override fun execute(javaProcessInfo: JavaProcessInfo?, processOutputHandler: ProcessOutputHandler?)
|
|
||||||
: ProcessResult? {
|
|
||||||
log(1, "Executing " + javaProcessInfo!!)
|
|
||||||
return KobaltProcessResult()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KobaltProcessOutputHandler : BaseProcessOutputHandler() {
|
|
||||||
override fun handleOutput(processOutput: ProcessOutput) =
|
|
||||||
log(3, "AndroidBuild output" + processOutput.standardOutput)
|
|
||||||
}
|
|
||||||
|
|
||||||
class KobaltErrorReporter : ErrorReporter(ErrorReporter.EvaluationMode.STANDARD) {
|
|
||||||
override fun handleSyncError(data: String?, type: Int, msg: String?): SyncIssue? {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun receiveMessage(message: Message?) {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProjectLayout {
|
|
||||||
val mergeBlame: File? = null
|
|
||||||
val publicText: File? = null
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class KobaltResourceMerger {
|
|
||||||
fun run(project: Project, variant: Variant, config: AndroidConfig, aarDependencies: List<File>,
|
|
||||||
rDirectory: String) {
|
|
||||||
val level = when(KobaltLogger.LOG_LEVEL) {
|
|
||||||
3 -> StdLogger.Level.VERBOSE
|
|
||||||
2 -> StdLogger.Level.WARNING
|
|
||||||
else -> StdLogger.Level.ERROR
|
|
||||||
}
|
|
||||||
val logger = StdLogger(level)
|
|
||||||
val androidBuilder = createAndroidBuilder(project, config, logger)
|
|
||||||
|
|
||||||
log(2, "Merging resources")
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assets
|
|
||||||
//
|
|
||||||
processAssets(project, variant, androidBuilder, aarDependencies)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Manifests
|
|
||||||
//
|
|
||||||
val appInfo = processManifests(project, variant, androidBuilder, config)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Resources
|
|
||||||
//
|
|
||||||
KobaltProcessOutputHandler().let {
|
|
||||||
processResources(project, variant, androidBuilder, aarDependencies, logger, it, appInfo.minSdkVersion)
|
|
||||||
mergeResources(project, variant, androidBuilder, aarDependencies, rDirectory, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createAndroidBuilder(project: Project, config: AndroidConfig, logger: ILogger): AndroidBuilder {
|
|
||||||
val processExecutor = DefaultProcessExecutor(logger)
|
|
||||||
val javaProcessExecutor = KobaltJavaProcessExecutor()
|
|
||||||
val androidHome = File(AndroidFiles.androidHome(project, config))
|
|
||||||
val sdkLoader : SdkLoader = DefaultSdkLoader.getLoader(androidHome)
|
|
||||||
val result = AndroidBuilder(project.name, "kobalt-android-plugin",
|
|
||||||
processExecutor,
|
|
||||||
javaProcessExecutor,
|
|
||||||
KobaltErrorReporter(),
|
|
||||||
logger,
|
|
||||||
false /* verbose */)
|
|
||||||
|
|
||||||
val libraryRequests = arrayListOf<LibraryRequest>()
|
|
||||||
val sdk = sdkLoader.getSdkInfo(logger)
|
|
||||||
val sdkManager = SdkManager.createManager(androidHome.absolutePath, logger)
|
|
||||||
val maxPlatformTarget = sdkManager.targets.filter { it.isPlatform }.last()
|
|
||||||
val maxPlatformTargetHash = AndroidTargetHash.getPlatformHashString(maxPlatformTarget.version)
|
|
||||||
|
|
||||||
result.setTargetInfo(sdk,
|
|
||||||
sdkLoader.getTargetInfo(maxPlatformTargetHash, maxPlatformTarget.buildToolInfo.revision, logger),
|
|
||||||
libraryRequests)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createLibraryDependencies(project: Project, dependencies: List<IClasspathDependency>)
|
|
||||||
: List<ManifestDependency> {
|
|
||||||
val result = arrayListOf<ManifestDependency>()
|
|
||||||
dependencies.filter {
|
|
||||||
it is MavenDependency && it.jarFile.get().path.endsWith(".aar")
|
|
||||||
}.forEach {
|
|
||||||
val dep = it as MavenDependency
|
|
||||||
result.add(object: ManifestDependency {
|
|
||||||
override fun getManifest(): File? {
|
|
||||||
return File(AndroidFiles.explodedManifest(project, dep.mavenId))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getName() = it.jarFile.get().path
|
|
||||||
|
|
||||||
override fun getManifestDependencies(): List<ManifestDependency> {
|
|
||||||
return createLibraryDependencies(project, it.directDependencies())
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
it.directDependencies()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processAssets(project: Project, variant: Variant, androidBuilder: AndroidBuilder,
|
|
||||||
aarDependencies: List<File>) {
|
|
||||||
logWrap(2, " Processing assets...", "done") {
|
|
||||||
val intermediates = File(
|
|
||||||
KFiles.joinDir(AndroidFiles.intermediates(project), "assets", variant.toIntermediateDir()))
|
|
||||||
aarDependencies.forEach {
|
|
||||||
val assetDir = File(it, "assets")
|
|
||||||
if (assetDir.exists()) {
|
|
||||||
KFiles.copyRecursively(assetDir, intermediates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processManifests(project: Project, variant: Variant, androidBuilder: AndroidBuilder,
|
|
||||||
config: AndroidConfig): AppInfo {
|
|
||||||
val mainManifest = File("src/main/AndroidManifest.xml")
|
|
||||||
val appInfo = AppInfo(mainManifest, config)
|
|
||||||
logWrap(2, " Processing manifests...", "done") {
|
|
||||||
val manifestOverlays = variant.allDirectories(project).map {
|
|
||||||
File("src/$it/AndroidManifest.xml")
|
|
||||||
}.filter {
|
|
||||||
it.exists()
|
|
||||||
}
|
|
||||||
val libraries = createLibraryDependencies(project, project.compileDependencies)
|
|
||||||
val outManifest = AndroidFiles.mergedManifest(project, variant)
|
|
||||||
val outAaptSafeManifestLocation = KFiles.joinDir(project.directory, project.buildDirectory, "generatedSafeAapt")
|
|
||||||
val reportFile = File(KFiles.joinDir(project.directory, project.buildDirectory, "manifest-merger-report.txt"))
|
|
||||||
androidBuilder.mergeManifests(mainManifest, manifestOverlays, libraries,
|
|
||||||
null /* package override */,
|
|
||||||
appInfo.versionCode,
|
|
||||||
appInfo.versionName,
|
|
||||||
appInfo.minSdkVersion.toString(),
|
|
||||||
appInfo.targetSdkVersion,
|
|
||||||
appInfo.maxSdkVersion,
|
|
||||||
outManifest,
|
|
||||||
outAaptSafeManifestLocation,
|
|
||||||
// TODO: support aar too
|
|
||||||
ManifestMerger2.MergeType.APPLICATION,
|
|
||||||
emptyMap() /* placeHolders */,
|
|
||||||
reportFile)
|
|
||||||
}
|
|
||||||
return appInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processResources(project: Project, variant: Variant, androidBuilder: AndroidBuilder,
|
|
||||||
aarDependencies: List<File>, logger: ILogger, processOutputHandler: KobaltProcessOutputHandler,
|
|
||||||
minSdk: Int) {
|
|
||||||
logWrap(2, " Processing resources...", "done") {
|
|
||||||
val layout = ProjectLayout()
|
|
||||||
val preprocessor = NoOpResourcePreprocessor()
|
|
||||||
val outputDir = AndroidFiles.mergedResources(project, variant)
|
|
||||||
val resourceMerger = ResourceMerger(minSdk)
|
|
||||||
val fullVariantDir = File(variant.toCamelcaseDir())
|
|
||||||
val srcList = listOf("main", variant.productFlavor.name, variant.buildType.name, fullVariantDir.path)
|
|
||||||
.map { "src" + File.separator + it }
|
|
||||||
|
|
||||||
// TODO: figure out why the badSrcList is bad. All this information should be coming from the Variant
|
|
||||||
val badSrcList = variant.resDirectories(project).map { it.path }
|
|
||||||
val goodAarList = aarDependencies.map { it.path + File.separator }
|
|
||||||
(goodAarList + srcList).map { it + File.separator + "res" }.forEach { path ->
|
|
||||||
with(ResourceSet(path)) {
|
|
||||||
addSource(File(path))
|
|
||||||
loadFromFiles(logger)
|
|
||||||
setGeneratedSet(GeneratedResourceSet(this))
|
|
||||||
resourceMerger.addDataSet(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val writer = MergedResourceWriter(File(outputDir),
|
|
||||||
androidBuilder.getAaptCruncher(processOutputHandler),
|
|
||||||
false /* don't crunch */,
|
|
||||||
false /* don't process 9patch */,
|
|
||||||
layout.publicText,
|
|
||||||
layout.mergeBlame,
|
|
||||||
preprocessor)
|
|
||||||
resourceMerger.mergeData(writer, true)
|
|
||||||
ExecutorSingleton.getExecutor().shutdown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mergeResources(project: Project, variant: Variant, androidBuilder: AndroidBuilder,
|
|
||||||
aarDependencies: List<File>, rDirectory: String,
|
|
||||||
processOutputHandler: KobaltProcessOutputHandler) {
|
|
||||||
logWrap(2, " Merging resources...", "done") {
|
|
||||||
|
|
||||||
val aaptOptions = object : AaptOptions {
|
|
||||||
override fun getAdditionalParameters() = emptyList<String>()
|
|
||||||
override fun getFailOnMissingConfigEntry() = false
|
|
||||||
override fun getIgnoreAssets() = null
|
|
||||||
override fun getNoCompress() = null
|
|
||||||
}
|
|
||||||
|
|
||||||
val aaptCommand = AaptPackageProcessBuilder(File(AndroidFiles.mergedManifest(project, variant)),
|
|
||||||
aaptOptions)
|
|
||||||
|
|
||||||
fun toSymbolFileProvider(aarDirectory: File) = object : SymbolFileProvider {
|
|
||||||
override fun getManifest() = File(aarDirectory, "AndroidManifest.xml")
|
|
||||||
override fun isOptional() = false
|
|
||||||
override fun getSymbolFile() = File(aarDirectory, "R.txt")
|
|
||||||
}
|
|
||||||
|
|
||||||
val variantDir = variant.toIntermediateDir()
|
|
||||||
val generated = KFiles.joinAndMakeDir(project.directory, project.buildDirectory, "symbols")
|
|
||||||
with(aaptCommand) {
|
|
||||||
setSourceOutputDir(rDirectory)
|
|
||||||
val libraries = aarDependencies.map { toSymbolFileProvider(it) }
|
|
||||||
setLibraries(libraries)
|
|
||||||
val r = libraries[0].symbolFile
|
|
||||||
setResFolder(File(AndroidFiles.mergedResources(project, variant)))
|
|
||||||
setAssetsFolder(File(KFiles.joinAndMakeDir(AndroidFiles.intermediates(project), "assets", variantDir)))
|
|
||||||
aaptCommand.setResPackageOutput(AndroidFiles.temporaryApk(project, variant.shortArchiveName))
|
|
||||||
aaptCommand.setSymbolOutputDir(generated)
|
|
||||||
|
|
||||||
// aaptCommand.setSourceOutputDir(generated)
|
|
||||||
// aaptCommand.setPackageForR(pkg)
|
|
||||||
// aaptCommand.setProguardOutput(proguardTxt)
|
|
||||||
// aaptCommand.setType(if (lib) VariantType.LIBRARY else VariantType.DEFAULT)
|
|
||||||
// aaptCommand.setDebuggable(debug)
|
|
||||||
}
|
|
||||||
|
|
||||||
androidBuilder.processResources(aaptCommand, true, processOutputHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dex(project: Project) {
|
|
||||||
// androidBuilder.createMainDexList()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package com.beust.kobalt.plugin.android
|
|
||||||
|
|
||||||
import com.beust.kobalt.misc.KFiles
|
|
||||||
|
|
||||||
class Proguard(val androidHome: String) {
|
|
||||||
val proguardHome = KFiles.joinDir(androidHome, "tools", "proguard")
|
|
||||||
val proguardCommand = KFiles.joinDir(proguardHome, "bin", "proguard.sh")
|
|
||||||
|
|
||||||
fun getDefaultProguardFile(name: String) = KFiles.joinDir(proguardHome, name)
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@
|
||||||
<!-- Classes within this tag are instantiated and the introspected by Kobalt. Whenever they -->
|
<!-- Classes within this tag are instantiated and the introspected by Kobalt. Whenever they -->
|
||||||
<!-- are found to implement one of IPluginActor's interfaces, they are added as such -->
|
<!-- are found to implement one of IPluginActor's interfaces, they are added as such -->
|
||||||
<class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name>
|
<class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name>
|
||||||
<class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
|
|
||||||
<class-name>com.beust.kobalt.plugin.application.ApplicationPlugin</class-name>
|
<class-name>com.beust.kobalt.plugin.application.ApplicationPlugin</class-name>
|
||||||
<class-name>com.beust.kobalt.plugin.KobaltPlugin</class-name>
|
<class-name>com.beust.kobalt.plugin.KobaltPlugin</class-name>
|
||||||
<class-name>com.beust.kobalt.plugin.kotlin.KotlinPlugin</class-name>
|
<class-name>com.beust.kobalt.plugin.kotlin.KotlinPlugin</class-name>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue