diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt
index e49019b063b..f5ce9205cb8 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt
@@ -514,6 +514,17 @@ open class KotlinAndroid70GradleIT : KotlinAndroid36GradleIT() {
assertCompiledKotlinSources(project.relativize(affectedSources))
}
}
+
+ @Test
+ fun testNamespaceDSLInsteadOfPackageAttributeInManifest() {
+ val project = Project("AndroidExtensionsProjectAGP7")
+ val options = defaultBuildOptions().copy(incremental = false)
+
+ project.build("assembleDebug", options = options) {
+ assertSuccessful()
+ assertContains("The 'kotlin-android-extensions' Gradle plugin is deprecated")
+ }
+ }
}
open class KotlinAndroid71GradleIT : KotlinAndroid70GradleIT() {
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/build.gradle
new file mode 100644
index 00000000000..46e22f12b3d
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/build.gradle
@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "25.0.2"
+ namespace "com.example.androidextensions"
+
+ defaultConfig {
+ applicationId "com.example.dagger.kotlin"
+ minSdkVersion 14
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/AndroidManifest.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000000..c3f5a36e644
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/MyActivity.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/MyActivity.kt
new file mode 100644
index 00000000000..0b8cb004d46
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/MyActivity.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidextensions
+
+import android.os.Bundle
+import android.app.Activity
+import kotlinx.android.synthetic.main.activity_main.textView
+
+class HomeActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ myUtilFunction()
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ this.textView.setText("Hello, world!")
+ }
+}
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/noLayoutUsages.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/noLayoutUsages.kt
new file mode 100644
index 00000000000..7834a2ddc6d
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/java/com/example/androidextensions/noLayoutUsages.kt
@@ -0,0 +1,3 @@
+package com.example.androidextensions
+
+fun myUtilFunction() = "OK"
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/layout/activity_main.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000000..02b0685b4a4
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/values/strings.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000000..67b44b1a8cd
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ kotlin
+
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/build.gradle
new file mode 100644
index 00000000000..3e1ecc01cc3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/build.gradle
@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ mavenLocal()
+ maven { url 'https://maven.google.com' }
+ mavenCentral()
+ maven { url = uri("https://jcenter.bintray.com/") }
+ }
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.android.tools.build:gradle:$android_tools_version"
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ maven { url 'https://maven.google.com' }
+ mavenCentral()
+ maven { url = uri("https://jcenter.bintray.com/") }
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/gradle.properties
new file mode 100644
index 00000000000..59b261a6689
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/gradle.properties
@@ -0,0 +1 @@
+org.gradle.jvmargs=-XX:MaxPermSize=512m
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/settings.gradle
new file mode 100644
index 00000000000..e7b4def49cb
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsProjectAGP7/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt
index bd257ff9030..ea1e53a593d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt
@@ -116,7 +116,7 @@ class AndroidSubplugin :
val mainSourceSet = sourceSets.getByName("main")
val manifestFile = mainSourceSet.manifest.srcFile
- val applicationPackage = getApplicationPackageFromManifest(manifestFile) ?: run {
+ val applicationPackage = getApplicationPackage(androidExtension, manifestFile) ?: run {
project.logger.warn(
"Application package name is not present in the manifest file (${manifestFile.absolutePath})"
)
@@ -182,7 +182,7 @@ class AndroidSubplugin :
)
val mainSourceSet = androidExtension.sourceSets.getByName("main")
- pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet))
+ pluginOptions += SubpluginOption("package", getApplicationPackage(androidExtension, project, mainSourceSet))
fun addVariant(name: String, resDirectories: FileCollection) {
val optionValue = lazy {
@@ -270,9 +270,9 @@ class AndroidSubplugin :
return project.files(Callable { lazyFiles.value })
}
- private fun getApplicationPackage(project: Project, mainSourceSet: AndroidSourceSet): String {
+ private fun getApplicationPackage(androidExtension: BaseExtension, project: Project, mainSourceSet: AndroidSourceSet): String {
val manifestFile = mainSourceSet.manifest.srcFile
- val applicationPackage = getApplicationPackageFromManifest(manifestFile)
+ val applicationPackage = getApplicationPackage(androidExtension, manifestFile)
if (applicationPackage == null) {
project.logger.warn(
@@ -286,7 +286,34 @@ class AndroidSubplugin :
}
}
- private fun getApplicationPackageFromManifest(manifestFile: File): String? {
+ private fun getApplicationPackage(androidExtension: BaseExtension, manifestFile: File): String? {
+ // Starting AGP 7 the package can be set via the DSL namespace value:
+ //
+ // android {
+ // namespace "com.example"
+ // }
+ //
+ // instead of via the "package" attribute in the manifest file.
+ //
+ // Starting AGP 8, the package *must* be set via the DSL and the manifest file
+ // attribute cannot be used.
+ //
+ // See https://issuetracker.google.com/issues/172361895
+ //
+ // Therefore, we try to get the package from there first. Since we support AGP versions
+ // prior to AGP 7, we need to reflectively find and call it.
+ try {
+ val method = androidExtension.javaClass.getDeclaredMethod("getNamespace")
+ val result = method.invoke(androidExtension)
+ if (result is String && result.isNotEmpty()) {
+ return result
+ }
+ } catch (e: ReflectiveOperationException) {
+ // Ignore and try parsing manifest.
+ }
+
+ // Didn't find the namespace getter, or it was not set. Try parsing the
+ // manifest to find the "package" attribute from there.
try {
return manifestFile.parseXml().documentElement.getAttribute("package")
} catch (e: Exception) {