1 /* 2 * Copyright 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.build 18 19 import com.android.build.api.dsl.ConsumerKeepRules 20 import com.android.build.api.dsl.LibraryBuildType 21 import java.io.File 22 import org.gradle.api.DefaultTask 23 import org.gradle.api.Project 24 import org.gradle.api.file.ConfigurableFileCollection 25 import org.gradle.api.file.DirectoryProperty 26 import org.gradle.api.file.RegularFileProperty 27 import org.gradle.api.plugins.JavaPluginExtension 28 import org.gradle.api.provider.Property 29 import org.gradle.api.tasks.Input 30 import org.gradle.api.tasks.InputFile 31 import org.gradle.api.tasks.InputFiles 32 import org.gradle.api.tasks.OutputDirectory 33 import org.gradle.api.tasks.PathSensitive 34 import org.gradle.api.tasks.PathSensitivity 35 import org.gradle.api.tasks.TaskAction 36 import org.gradle.work.DisableCachingByDefault 37 38 /** 39 * Add a blank consumer proguard rules file to the JAR if the library has not set up an explicit set 40 * of rules. 41 */ setUpBlankProguardFileForJarIfNeedednull42internal fun Project.setUpBlankProguardFileForJarIfNeeded(javaExtension: JavaPluginExtension) { 43 if (project.multiplatformExtension != null) return // skip KMP projects 44 val mainSources = javaExtension.sourceSets.getByName("main") 45 val provider = 46 tasks.register("emptyProguardFileCopy", BlankProguardFileGenerator::class.java) { 47 it.blankProguardFile.set(blankProguardRules()) 48 it.outputDirectory.set(layout.buildDirectory.dir("blankProguard")) 49 it.nonGeneratedResources.from(mainSources.resources.sourceDirectories) 50 // unique name like "androidx-arch-core-core-common" 51 it.libraryName.set("androidx${project.path.replace(":", "-")}") 52 } 53 mainSources.output.dir(provider.flatMap { it.outputDirectory }) 54 } 55 56 /** 57 * Add a blank consumer proguard rules file to the AAR if the library has not set up an explicit set 58 * of rules. 59 */ setUpBlankProguardFileForAarIfNeedednull60internal fun Project.setUpBlankProguardFileForAarIfNeeded(buildType: LibraryBuildType) { 61 if (buildType.consumerProguardFiles.isEmpty()) { 62 buildType.consumerProguardFiles.add(blankProguardRules()) 63 } 64 } 65 66 /** 67 * Add a blank consumer proguard rules file to the AAR if the library has not set up an explicit set 68 * of rules. 69 */ 70 @Suppress("UnstableApiUsage") // b/393137152 setUpBlankProguardFileForKmpAarIfNeedednull71internal fun Project.setUpBlankProguardFileForKmpAarIfNeeded(consumerKeepRules: ConsumerKeepRules) { 72 if (consumerKeepRules.files.isEmpty()) { 73 file(project.blankProguardRules()) 74 consumerKeepRules.publish = true 75 } 76 } 77 78 @DisableCachingByDefault 79 abstract class BlankProguardFileGenerator : DefaultTask() { 80 @get:[InputFile PathSensitive(PathSensitivity.NONE)] 81 abstract val blankProguardFile: RegularFileProperty 82 83 @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)] 84 abstract val nonGeneratedResources: ConfigurableFileCollection 85 86 @get:Input abstract val libraryName: Property<String> 87 88 @get:OutputDirectory abstract val outputDirectory: DirectoryProperty 89 90 @TaskAction copyEmptyFilenull91 fun copyEmptyFile() { 92 outputDirectory.get().asFile.deleteRecursively() 93 val hasExplicitProguardFile = 94 nonGeneratedResources.any { File(it, "META-INF/proguard").exists() } 95 // Check if the library already contains explicit proguard file 96 if (hasExplicitProguardFile) return 97 blankProguardFile 98 .get() 99 .asFile 100 .copyTo( 101 File(outputDirectory.get().asFile, "META-INF/proguard/${libraryName.get()}.pro") 102 ) 103 } 104 } 105 Projectnull106private fun Project.blankProguardRules(): File = 107 project.getSupportRootFolder().resolve("buildSrc/blank-proguard-rules/proguard-rules.pro") 108