Android Extensions: Allow to access library project resources in Gradle setup (#KT-22430)
This commit is contained in:
+8
-1
@@ -335,7 +335,14 @@ fun getSomething() = 10
|
||||
val options = defaultBuildOptions().copy(incremental = false)
|
||||
|
||||
project.build("assemble", options = options) {
|
||||
assertSuccessful()
|
||||
if (isLegacyAndroidGradleVersion(androidGradlePluginVersion)) {
|
||||
// Library dependencies are not supported in older versions of Android Gradle plugin (< 3.0)
|
||||
assertFailed()
|
||||
assertContains("Unresolved reference: layout_in_library")
|
||||
assertContains("Unresolved reference: text_view")
|
||||
} else {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -41,4 +41,5 @@ androidExtensions {
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile project(":library")
|
||||
}
|
||||
|
||||
+2
@@ -3,11 +3,13 @@ package org.example.manyvariants
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.layout_in_library.text_view
|
||||
|
||||
class MainActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
viewMain
|
||||
text_view
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "25.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.library" />
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Library</string>
|
||||
</resources>
|
||||
+1
-1
@@ -1 +1 @@
|
||||
include ':app'
|
||||
include ':app', ':library'
|
||||
+64
-44
@@ -28,7 +28,6 @@ import org.gradle.api.UnknownDomainObjectException
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.w3c.dom.Document
|
||||
import java.io.File
|
||||
@@ -160,74 +159,95 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
||||
val pluginOptions = arrayListOf<SubpluginOption>()
|
||||
|
||||
pluginOptions += SubpluginOption("experimental", "true")
|
||||
pluginOptions += SubpluginOption("defaultCacheImplementation",
|
||||
androidExtensionsExtension.defaultCacheImplementation.optionName)
|
||||
pluginOptions += SubpluginOption("defaultCacheImplementation", androidExtensionsExtension.defaultCacheImplementation.optionName)
|
||||
|
||||
val mainSourceSet = androidExtension.sourceSets.getByName("main")
|
||||
pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet))
|
||||
|
||||
val enabledVariants = getVariantComponentNames(variantData)
|
||||
val allResDirectories = mutableMapOf<String, List<File>>()
|
||||
|
||||
androidProjectHandler.forEachVariant(project) { variant ->
|
||||
val variantName = androidProjectHandler.getVariantName(variant)
|
||||
if (androidProjectHandler.getTestedVariantData(variant) != null) {
|
||||
return@forEachVariant
|
||||
}
|
||||
|
||||
allResDirectories[variantName] = androidProjectHandler.getResDirectories(variant)
|
||||
}
|
||||
|
||||
fun addVariant(name: String, resDirectories: List<File>) {
|
||||
val optionValue = buildString {
|
||||
append(name)
|
||||
append(';')
|
||||
append(name).append(';')
|
||||
resDirectories.joinTo(this, separator = ";") { it.canonicalPath }
|
||||
}
|
||||
pluginOptions += CompositeSubpluginOption("variant", optionValue, listOf(
|
||||
|
||||
pluginOptions += CompositeSubpluginOption(
|
||||
"variant", optionValue, listOf(
|
||||
SubpluginOption("variantName", name),
|
||||
// use INTERNAL option kind since the resources are tracked as sources (see below)
|
||||
FilesSubpluginOption("resDirs", resDirectories)))
|
||||
FilesSubpluginOption("resDirs", resDirectories)
|
||||
)
|
||||
)
|
||||
|
||||
kotlinCompile.source(project.files(getLayoutDirectories(resDirectories)))
|
||||
}
|
||||
|
||||
fun addSourceSetAsVariant(name: String) {
|
||||
val sourceSet = androidExtension.sourceSets.findByName(name) ?: return
|
||||
val srcDirs = sourceSet.res.srcDirs.toList()
|
||||
if (srcDirs.isNotEmpty()) {
|
||||
addVariant(sourceSet.name, srcDirs)
|
||||
}
|
||||
}
|
||||
val actualResDirectories = allResDirectories.filterKeys { it in enabledVariants }
|
||||
val localProjectResDirs = actualResDirectories.values
|
||||
.flatMap { it }
|
||||
.filter { it.isProjectLibraryResDirectory() || it.isPackageResDirectory() }
|
||||
|
||||
val resDirectoriesForAllVariants = mutableListOf<List<File>>()
|
||||
val commonResDirectories = getCommonResDirectories(allResDirectories.values) + localProjectResDirs
|
||||
addVariant("main", commonResDirectories.distinct().sorted())
|
||||
|
||||
androidProjectHandler.forEachVariant(project) { variant ->
|
||||
if (androidProjectHandler.getTestedVariantData(variant) != null) return@forEachVariant
|
||||
resDirectoriesForAllVariants += androidProjectHandler.getResDirectories(variant)
|
||||
}
|
||||
for (sourceSetName in enabledVariants) {
|
||||
val srcDirs = androidExtension.sourceSets.findByName(sourceSetName)
|
||||
?.res?.srcDirs?.toList()?.takeIf { it.isNotEmpty() } ?: continue
|
||||
|
||||
val commonResDirectories = getCommonResDirectories(resDirectoriesForAllVariants)
|
||||
|
||||
addVariant("main", commonResDirectories.toList())
|
||||
|
||||
getVariantComponentNames(variantData)?.let { (variantName, flavorName, buildTypeName) ->
|
||||
addSourceSetAsVariant(buildTypeName)
|
||||
|
||||
if (flavorName.isNotEmpty()) {
|
||||
addSourceSetAsVariant(flavorName)
|
||||
}
|
||||
|
||||
if (buildTypeName != variantName && buildTypeName != flavorName) {
|
||||
addSourceSetAsVariant(variantName)
|
||||
}
|
||||
addVariant(sourceSetName, (srcDirs - commonResDirectories).sorted())
|
||||
}
|
||||
|
||||
return wrapPluginOptions(pluginOptions, "configuration")
|
||||
}
|
||||
|
||||
// Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData
|
||||
private fun getVariantComponentNames(flavorData: Any?): VariantComponentNames? = when(flavorData) {
|
||||
is KaptVariantData<*> -> getVariantComponentNames(flavorData.variantData)
|
||||
is TestVariantData -> getVariantComponentNames(flavorData.testedVariantData)
|
||||
is TestVariant -> getVariantComponentNames(flavorData.testedVariant)
|
||||
is BaseVariant -> VariantComponentNames(flavorData.name, flavorData.flavorName, flavorData.buildType.name)
|
||||
is BaseVariantData<*> -> VariantComponentNames(flavorData.name, flavorData.variantConfiguration.flavorName,
|
||||
flavorData.variantConfiguration.buildType.name)
|
||||
else -> null
|
||||
private fun File.isPackageResDirectory(): Boolean {
|
||||
val packagedResDir = parentFile ?: return false
|
||||
val intermediatesDir = packagedResDir.parentFile ?: return false
|
||||
val buildDir = intermediatesDir.parentFile ?: return false
|
||||
|
||||
return packagedResDir.name == "packaged_res" && intermediatesDir.name == "intermediates" && buildDir.name == "build"
|
||||
}
|
||||
|
||||
private data class VariantComponentNames(val variantName: String, val flavorName: String, val buildTypeName: String)
|
||||
private fun File.isProjectLibraryResDirectory(): Boolean {
|
||||
if (name != "res") {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getCommonResDirectories(resDirectories: List<List<File>>): Set<File> {
|
||||
val bundlesDir = parentFile?.parentFile ?: return false
|
||||
val intermediatesDir = bundlesDir.parentFile ?: return false
|
||||
val buildDir = intermediatesDir.parentFile ?: return false
|
||||
|
||||
return bundlesDir.name == "bundles" && intermediatesDir.name == "intermediates" && buildDir.name == "build"
|
||||
}
|
||||
|
||||
// Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData
|
||||
private fun getVariantComponentNames(variantData: Any?): List<String> = when(variantData) {
|
||||
is KaptVariantData<*> -> getVariantComponentNames(variantData.variantData)
|
||||
is TestVariantData -> getVariantComponentNames(variantData.testedVariantData)
|
||||
is TestVariant -> getVariantComponentNames(variantData.testedVariant)
|
||||
is BaseVariant -> listOfNotNull(variantData.name, variantData.flavorName, variantData.buildType.name).distinct()
|
||||
is BaseVariantData<*> -> {
|
||||
listOfNotNull(
|
||||
variantData.name,
|
||||
variantData.variantConfiguration.flavorName,
|
||||
variantData.variantConfiguration.buildType.name
|
||||
).distinct()
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
private fun getCommonResDirectories(resDirectories: Iterable<Iterable<File>>): Set<File> {
|
||||
var common = resDirectories.firstOrNull()?.toSet() ?: return emptySet()
|
||||
|
||||
for (resDirs in resDirectories.drop(1)) {
|
||||
|
||||
+1
-1
@@ -473,12 +473,12 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
|
||||
protected val logger = Logging.getLogger(this.javaClass)
|
||||
|
||||
abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit
|
||||
abstract fun getVariantName(variant: V): String
|
||||
abstract fun getTestedVariantData(variantData: V): V?
|
||||
abstract fun getResDirectories(variantData: V): List<File>
|
||||
|
||||
protected abstract fun getSourceProviders(variantData: V): Iterable<SourceProvider>
|
||||
protected abstract fun getAllJavaSources(variantData: V): Iterable<File>
|
||||
protected abstract fun getVariantName(variant: V): String
|
||||
protected abstract fun getJavaTask(variantData: V): AbstractCompile?
|
||||
protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit
|
||||
|
||||
|
||||
Reference in New Issue
Block a user