Skip to content

Commit

Permalink
add aidl parcelables into aar
Browse files Browse the repository at this point in the history
  • Loading branch information
0xera committed Oct 22, 2024
1 parent c4dae7c commit f0cd6ec
Show file tree
Hide file tree
Showing 18 changed files with 558 additions and 23 deletions.
108 changes: 97 additions & 11 deletions grease/src/main/kotlin/io/deepmedia/tools/grease/GreasePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ import com.android.ide.common.symbols.parseManifest
import com.android.manifmerger.ManifestMerger2
import com.android.manifmerger.ManifestProvider
import com.android.utils.appendCapitalized
import com.github.jengelman.gradle.plugins.shadow.ShadowStats
import com.github.jengelman.gradle.plugins.shadow.relocation.RelocatePathContext
import com.github.jengelman.gradle.plugins.shadow.relocation.Relocator
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Usage
import org.gradle.api.file.Directory
import org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository
import org.gradle.kotlin.dsl.support.unzipTo
Expand Down Expand Up @@ -71,6 +75,7 @@ open class GreasePlugin : Plugin<Project> {
fun configure(variant: Variant, vararg configurations: Configuration) {
configureVariantManifest(target, variant, configurations, log)
configureVariantJniLibs(target, variant, configurations, log)
configureVariantAidlParcelables(target, variant, configurations, log)
configureVariantResources(target, variant, configurations, log)
configureVariantSources(target, variant, configurations, greaseExtension, log)
configureVariantAssets(target, variant, configurations, log)
Expand Down Expand Up @@ -121,7 +126,7 @@ open class GreasePlugin : Plugin<Project> {
target.locateTask(componentConfig.resolveTaskName("process", "Manifest"))?.configure {
val processManifestTask = this as ProcessLibraryManifest

val extraManifests = configurations.artifactsOf(AndroidArtifacts.ArtifactType.MANIFEST)
val extraManifests = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.MANIFEST)
dependsOn(extraManifests)

// After the file is copied we can go on with the actual manifest merging.
Expand Down Expand Up @@ -220,7 +225,7 @@ open class GreasePlugin : Plugin<Project> {

target.locateTask(creationConfig.resolveTaskName("copy", "JniLibsProjectAndLocalJars"))?.configure {
val copyJniTask = this as LibraryJniLibsTask
val extraJniLibs = configurations.artifactsOf(AndroidArtifacts.ArtifactType.JNI)
val extraJniLibs = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.JNI)
dependsOn(extraJniLibs)

fun injectJniLibs() {
Expand Down Expand Up @@ -248,6 +253,37 @@ open class GreasePlugin : Plugin<Project> {
}
}

private fun configureVariantAidlParcelables(
target: Project,
variant: Variant,
configurations: Array<out Configuration>,
logger: Logger
) {
val log = logger.child("configureVariantAidlParcelables")
log.d { "Configuring variant ${variant.name}..." }
val creationConfig = variant.componentCreationConfigOrThrow()
creationConfig.taskContainer.aidlCompileTask?.configure {
val extraAidlFiles = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.AIDL, Usage.JAVA_API)
dependsOn(extraAidlFiles)
fun injectAidlFiles() {
log.d { "Executing for variant ${variant.name} and ${extraAidlFiles.files.size} roots..." }
extraAidlFiles.files.forEach { inputRoot ->
log.d { "Found aidl parcelables files root: $inputRoot" }
val inputFiles = target.fileTree(inputRoot)
target.copy {
from(inputFiles)
into(packagedDir.get())
}
}
}
if (sourceFiles.get().files.isNotEmpty()) {
doLast { injectAidlFiles() }
} else {
injectAidlFiles()
}
}
}

/**
* AARs ship with a file called R.txt which already includes all resource ids from dependencies,
* so we shouldn't probably do nothing about it as it comes for free.
Expand Down Expand Up @@ -321,7 +357,7 @@ open class GreasePlugin : Plugin<Project> {
val resourcesMergingWorkdir = target.greaseBuildDir.get().dir(variant.name).dir("resources")
val mergedResourcesDir = resourcesMergingWorkdir.dir("merged")
val blameDir = resourcesMergingWorkdir.dir("blame")
val extraAndroidRes = configurations.artifactsOf(AndroidArtifacts.ArtifactType.ANDROID_RES)
val extraAndroidRes = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.ANDROID_RES)
dependsOn(extraAndroidRes)

outputs.upToDateWhen { false } // always execute
Expand Down Expand Up @@ -386,6 +422,7 @@ open class GreasePlugin : Plugin<Project> {
val creationConfig = variant.componentCreationConfigOrThrow()

val workdir = target.greaseBuildDir.get().dir(variant.name)
workdir.asFile.deleteRecursively()
val aarExtractWorkdir = workdir.dir("extract").dir("aar")
val jarExtractWorkdir = workdir.dir("extract").dir("jar")
val jarFileName = "classes.jar"
Expand Down Expand Up @@ -414,7 +451,7 @@ open class GreasePlugin : Plugin<Project> {

// There are many options here. PROCESSED_JAR, PROCESSED_AAR, CLASSES, CLASSES_JAR ...
// CLASSES_JAR seems to be the best though it's not clear if it's jetified or not.
val extraJars = configurations.artifactsOf(AndroidArtifacts.ArtifactType.CLASSES_JAR)
val extraJars = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.CLASSES_JAR)
dependsOn(extraJars)
dependsOn(greaseExpandTask)

Expand Down Expand Up @@ -444,7 +481,7 @@ open class GreasePlugin : Plugin<Project> {
ShadowJar::class.java
) {
val compileTask = creationConfig.taskContainer.javacTask
val extraManifests = configurations.artifactsOf(AndroidArtifacts.ArtifactType.MANIFEST)
val extraManifests = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.MANIFEST)
val greaseShadowDir = workdir.dir("shadow")
val bundleAar = bundleLibraryTask?.get() as BundleAar

Expand Down Expand Up @@ -475,8 +512,8 @@ open class GreasePlugin : Plugin<Project> {

val relocationPrefix = greaseExtension.prefix.get()
if (relocationPrefix.isNotEmpty()) {
greaseProcessTask.get().outputs.files
.asSequence()
val sequence = greaseProcessTask.get().outputs.files.asSequence() + aarExtractWorkdir.dir("aidl").asFile
sequence
.flatMap { inputFile -> inputFile.packageNames }
.distinct()
.map { packageName -> packageName to "${relocationPrefix}.$packageName" }
Expand All @@ -502,13 +539,20 @@ open class GreasePlugin : Plugin<Project> {
into(aarExtractWorkdir)
}

replacePackagesInFile(
replacePackagesInManifest(
aarExtractWorkdir.file("AndroidManifest.xml").asFile,
greaseShadowDir.file("AndroidManifest.xml").asFile,
relocators,
target,
)

relocateAidlFiles(
aarExtractWorkdir.dir("aidl"),
greaseShadowDir.dir("aidl"),
relocators,
target,
)

val oldArchive = bundleAar.archiveFile.get().asFile
val archiveParent = oldArchive.parentFile
val archiveName = oldArchive.name
Expand Down Expand Up @@ -544,7 +588,7 @@ open class GreasePlugin : Plugin<Project> {
}
}

private fun replacePackagesInFile(
private fun replacePackagesInManifest(
input: File,
output: File,
relocators: List<Relocator>,
Expand Down Expand Up @@ -573,6 +617,48 @@ open class GreasePlugin : Plugin<Project> {
}
}


private fun relocateAidlFiles(
inputDir: Directory,
outputDir: Directory,
relocators: List<Relocator>,
target: Project,
) {
if (inputDir.asFileTree.isEmpty) return

inputDir.asFileTree.forEach { file ->
val relocatePathContext = RelocatePathContext().apply {
stats = ShadowStats()
}
val reader = file.bufferedReader()
val relocatedPath = relocators
.filterNot { it is RClassRelocator }
.fold(file.toRelativeString(inputDir.asFile)) { acc, relocator ->
relocator.relocatePath(relocatePathContext.apply { path = acc })
}
val writer = outputDir.asFile.file(relocatedPath).bufferedWriter()
reader.useLines { strings ->
strings
.map { string ->
relocators
.filterNot { it is RClassRelocator }
.fold(string) { acc, relocator ->
relocator.applyToSourceContent(acc)
}
}.forEach {
writer.write(it)
writer.newLine()
}
}
writer.close()
}
inputDir.asFile.deleteRecursively()
target.copy {
from(outputDir)
into(inputDir)
}
}

/**
* Interesting tasks:
* 1. generate<>Assets: See [MutableTaskContainer].
Expand All @@ -592,7 +678,7 @@ open class GreasePlugin : Plugin<Project> {
log.d { "Configuring variant ${variant.name}..." }
val creationConfig = variant.componentCreationConfigOrThrow()
creationConfig.taskContainer.mergeAssetsTask.configure {
val extraAssets = configurations.artifactsOf(AndroidArtifacts.ArtifactType.ASSETS)
val extraAssets = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.ASSETS)
dependsOn(extraAssets)
fun injectAssets() {
log.d { "Executing for variant ${variant.name} and ${extraAssets.files.size} roots..." }
Expand Down Expand Up @@ -650,7 +736,7 @@ open class GreasePlugin : Plugin<Project> {
// UNFILTERED_PROGUARD_RULES, FILTERED_PROGUARD_RULES, AAPT_PROGUARD_RULES, ...
// UNFILTERED_PROGUARD_RULES is output of the AarTransform. FILTERED_PROGUARD_RULES
// is processed by another transform and is probably what we want in the end.
val extraInputs = configurations.artifactsOf(AndroidArtifacts.ArtifactType.FILTERED_PROGUARD_RULES)
val extraInputs = configurations.artifactsOf(target, AndroidArtifacts.ArtifactType.FILTERED_PROGUARD_RULES)
dependsOn(extraInputs)

mergeFileTask.inputs.files(extraInputs + mergeFileTask.inputFiles.files)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import java.util.function.Consumer

internal fun Configuration.artifactsOf(type: AndroidArtifacts.ArtifactType): FileCollection = incoming.artifactView {
internal fun Configuration.artifactsOf(project: Project, type: AndroidArtifacts.ArtifactType, usageAttr: String = Usage.JAVA_RUNTIME): FileCollection = incoming.artifactView {
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, usageAttr))
attribute(AndroidArtifacts.ARTIFACT_TYPE, type.type)
}
}.files

internal fun Array<out Configuration>.artifactsOf(type: AndroidArtifacts.ArtifactType): FileCollection = map {
internal fun Array<out Configuration>.artifactsOf(project: Project, type: AndroidArtifacts.ArtifactType, usageAttr: String = Usage.JAVA_RUNTIME): FileCollection = map {
it.incoming.artifactView {
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, usageAttr))
attribute(AndroidArtifacts.ARTIFACT_TYPE, type.type)
}
}.files as FileCollectionInternal
Expand Down Expand Up @@ -72,11 +74,7 @@ private fun Project.createGrease(name: String, isTransitive: Boolean): Configura
val configuration = configurations.create(greasifiedName)
configuration.isTransitive = isTransitive
configuration.attributes {
// This should make sure that we don't pull in compileOnly dependencies that should not be in
// the final bundle. The other usage, JAVA_API, would only include exposed dependencies,
// so drop everything marked as implementation() in the original library. Not good.
// (Still, we currently put in A LOT OF STUFF, like org.jetbrains.annotations ... Not sure how to avoid this.)
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, Usage.JAVA_API))
}
configurations.configureEach {
val other = this
Expand Down
2 changes: 1 addition & 1 deletion grease/src/main/kotlin/io/deepmedia/tools/grease/files.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ val JarFile.packageNames: Set<String>
}.toSet()

val File.packageNames: Set<String>
get() = listFilesRecursive("class").mapNotNull { file ->
get() = (listFilesRecursive("class") + listFilesRecursive("aidl")).mapNotNull { file ->
if (file.name != "module-info.class") {
val cleanedPath = file.path.removePrefix(this.path).removePrefix("/")
cleanedPath
Expand Down
Binary file added tests/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions tests/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit f0cd6ec

Please sign in to comment.