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)
|
val options = defaultBuildOptions().copy(incremental = false)
|
||||||
|
|
||||||
project.build("assemble", options = options) {
|
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 {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
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.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
import kotlinx.android.synthetic.main.layout_in_library.text_view
|
||||||
|
|
||||||
class MainActivity : Activity() {
|
class MainActivity : Activity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle) {
|
override fun onCreate(savedInstanceState: Bundle) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
viewMain
|
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.SourceSet
|
||||||
import org.gradle.api.tasks.compile.AbstractCompile
|
import org.gradle.api.tasks.compile.AbstractCompile
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -160,74 +159,95 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
|||||||
val pluginOptions = arrayListOf<SubpluginOption>()
|
val pluginOptions = arrayListOf<SubpluginOption>()
|
||||||
|
|
||||||
pluginOptions += SubpluginOption("experimental", "true")
|
pluginOptions += SubpluginOption("experimental", "true")
|
||||||
pluginOptions += SubpluginOption("defaultCacheImplementation",
|
pluginOptions += SubpluginOption("defaultCacheImplementation", androidExtensionsExtension.defaultCacheImplementation.optionName)
|
||||||
androidExtensionsExtension.defaultCacheImplementation.optionName)
|
|
||||||
|
|
||||||
val mainSourceSet = androidExtension.sourceSets.getByName("main")
|
val mainSourceSet = androidExtension.sourceSets.getByName("main")
|
||||||
pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet))
|
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>) {
|
fun addVariant(name: String, resDirectories: List<File>) {
|
||||||
val optionValue = buildString {
|
val optionValue = buildString {
|
||||||
append(name)
|
append(name).append(';')
|
||||||
append(';')
|
|
||||||
resDirectories.joinTo(this, separator = ";") { it.canonicalPath }
|
resDirectories.joinTo(this, separator = ";") { it.canonicalPath }
|
||||||
}
|
}
|
||||||
pluginOptions += CompositeSubpluginOption("variant", optionValue, listOf(
|
|
||||||
|
pluginOptions += CompositeSubpluginOption(
|
||||||
|
"variant", optionValue, listOf(
|
||||||
SubpluginOption("variantName", name),
|
SubpluginOption("variantName", name),
|
||||||
// use INTERNAL option kind since the resources are tracked as sources (see below)
|
// 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)))
|
kotlinCompile.source(project.files(getLayoutDirectories(resDirectories)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addSourceSetAsVariant(name: String) {
|
val actualResDirectories = allResDirectories.filterKeys { it in enabledVariants }
|
||||||
val sourceSet = androidExtension.sourceSets.findByName(name) ?: return
|
val localProjectResDirs = actualResDirectories.values
|
||||||
val srcDirs = sourceSet.res.srcDirs.toList()
|
.flatMap { it }
|
||||||
if (srcDirs.isNotEmpty()) {
|
.filter { it.isProjectLibraryResDirectory() || it.isPackageResDirectory() }
|
||||||
addVariant(sourceSet.name, srcDirs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val resDirectoriesForAllVariants = mutableListOf<List<File>>()
|
val commonResDirectories = getCommonResDirectories(allResDirectories.values) + localProjectResDirs
|
||||||
|
addVariant("main", commonResDirectories.distinct().sorted())
|
||||||
|
|
||||||
androidProjectHandler.forEachVariant(project) { variant ->
|
for (sourceSetName in enabledVariants) {
|
||||||
if (androidProjectHandler.getTestedVariantData(variant) != null) return@forEachVariant
|
val srcDirs = androidExtension.sourceSets.findByName(sourceSetName)
|
||||||
resDirectoriesForAllVariants += androidProjectHandler.getResDirectories(variant)
|
?.res?.srcDirs?.toList()?.takeIf { it.isNotEmpty() } ?: continue
|
||||||
}
|
|
||||||
|
|
||||||
val commonResDirectories = getCommonResDirectories(resDirectoriesForAllVariants)
|
addVariant(sourceSetName, (srcDirs - commonResDirectories).sorted())
|
||||||
|
|
||||||
addVariant("main", commonResDirectories.toList())
|
|
||||||
|
|
||||||
getVariantComponentNames(variantData)?.let { (variantName, flavorName, buildTypeName) ->
|
|
||||||
addSourceSetAsVariant(buildTypeName)
|
|
||||||
|
|
||||||
if (flavorName.isNotEmpty()) {
|
|
||||||
addSourceSetAsVariant(flavorName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildTypeName != variantName && buildTypeName != flavorName) {
|
|
||||||
addSourceSetAsVariant(variantName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapPluginOptions(pluginOptions, "configuration")
|
return wrapPluginOptions(pluginOptions, "configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData
|
private fun File.isPackageResDirectory(): Boolean {
|
||||||
private fun getVariantComponentNames(flavorData: Any?): VariantComponentNames? = when(flavorData) {
|
val packagedResDir = parentFile ?: return false
|
||||||
is KaptVariantData<*> -> getVariantComponentNames(flavorData.variantData)
|
val intermediatesDir = packagedResDir.parentFile ?: return false
|
||||||
is TestVariantData -> getVariantComponentNames(flavorData.testedVariantData)
|
val buildDir = intermediatesDir.parentFile ?: return false
|
||||||
is TestVariant -> getVariantComponentNames(flavorData.testedVariant)
|
|
||||||
is BaseVariant -> VariantComponentNames(flavorData.name, flavorData.flavorName, flavorData.buildType.name)
|
return packagedResDir.name == "packaged_res" && intermediatesDir.name == "intermediates" && buildDir.name == "build"
|
||||||
is BaseVariantData<*> -> VariantComponentNames(flavorData.name, flavorData.variantConfiguration.flavorName,
|
|
||||||
flavorData.variantConfiguration.buildType.name)
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
var common = resDirectories.firstOrNull()?.toSet() ?: return emptySet()
|
||||||
|
|
||||||
for (resDirs in resDirectories.drop(1)) {
|
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)
|
protected val logger = Logging.getLogger(this.javaClass)
|
||||||
|
|
||||||
abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit
|
abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit
|
||||||
|
abstract fun getVariantName(variant: V): String
|
||||||
abstract fun getTestedVariantData(variantData: V): V?
|
abstract fun getTestedVariantData(variantData: V): V?
|
||||||
abstract fun getResDirectories(variantData: V): List<File>
|
abstract fun getResDirectories(variantData: V): List<File>
|
||||||
|
|
||||||
protected abstract fun getSourceProviders(variantData: V): Iterable<SourceProvider>
|
protected abstract fun getSourceProviders(variantData: V): Iterable<SourceProvider>
|
||||||
protected abstract fun getAllJavaSources(variantData: V): Iterable<File>
|
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 getJavaTask(variantData: V): AbstractCompile?
|
||||||
protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit
|
protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user