blob: 8b9831c4d20c0a946bc70eee4277e461b9abff01 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.android.build.gradle.internal.tasks
import com.android.SdkConstants
import com.android.SdkConstants.FD_ASSETS
import com.android.build.api.component.impl.ComponentPropertiesImpl
import com.android.build.gradle.internal.packaging.JarCreatorFactory
import com.android.build.gradle.internal.scope.InternalArtifactType
import com.android.build.gradle.internal.tasks.factory.VariantTaskCreationAction
import com.android.builder.packaging.JarCreator
import com.android.utils.FileUtils
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskProvider
import java.io.File
import java.io.Serializable
import java.nio.file.Paths
import java.util.function.Predicate
import java.util.zip.Deflater
import javax.inject.Inject
/**
* Task that collects the processed manifest file for the asset pack and the asset files to be
* included and uses a JarCreator to package them together for the base app to include in the
* Android App Bundle.
*/
abstract class AssetPackPreBundleTask : NonIncrementalTask() {
/**
* Where to put the final archive containing all the files for the asset pack, to be included
* in the bundle build task for the base module.
*/
@get:OutputDirectory abstract val outputDir: DirectoryProperty
/**
* The processed manifest file to be included in the app bundle for the asset pack.
*/
@get:InputFiles
@get:PathSensitive(PathSensitivity.NAME_ONLY)
abstract val manifestFiles: DirectoryProperty
/**
* The asset files to be included in the app bundle as the contents of the asset pack.
*/
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val assetsFiles: ConfigurableFileCollection
override fun doTaskAction() {
for (manifestFile: File in manifestFiles.asFileTree.files) {
val assetPackName = manifestFile.parentFile.name
val packDir = outputDir.dir(assetPackName).get()
getWorkerFacadeWithWorkers().use {
it.submit(
AssetPackPreBundleTaskRunnable::class.java,
AssetPackPreBundleTaskRunnable.Params(
packDir = packDir.asFile,
packFile = packDir.file("${assetPackName}.zip").asFile,
assetsFilesPath = assetsFiles.filter{assetPack -> assetPack.absolutePath.contains(
assetPackName + File.separator + "src" + File.separator + "main" + File.separator + "assets")}.asPath,
manifestFile = manifestFile
)
)
}
}
}
class CreationAction(
componentProperties: ComponentPropertiesImpl,
private val assetFileCollection: FileCollection
) : VariantTaskCreationAction<AssetPackPreBundleTask, ComponentPropertiesImpl>(
componentProperties
) {
override val type = AssetPackPreBundleTask::class.java
override val name = computeTaskName("assetPack", "PreBundleTask")
override fun handleProvider(
taskProvider: TaskProvider<AssetPackPreBundleTask>
) {
super.handleProvider(taskProvider)
creationConfig.artifacts.setInitialProvider(
taskProvider,
AssetPackPreBundleTask::outputDir
).on(InternalArtifactType.ASSET_PACK_BUNDLE)
}
override fun configure(
task: AssetPackPreBundleTask
) {
super.configure(task)
creationConfig.artifacts.setTaskInputToFinalProduct(
InternalArtifactType.LINKED_RES_FOR_ASSET_PACK, task.manifestFiles)
task.assetsFiles.from(assetFileCollection)
}
}
}
private class AssetRelocator(private val prefix: String): JarCreator.Relocator {
override fun relocate(entryPath: String) = "$prefix/$entryPath"
}
private class ManifestRelocator : JarCreator.Relocator {
override fun relocate(entryPath: String) = when(entryPath) {
SdkConstants.FN_ANDROID_MANIFEST_XML -> "manifest/" + SdkConstants.FN_ANDROID_MANIFEST_XML
else -> entryPath
}
}
class AssetPackPreBundleTaskRunnable @Inject constructor(private val params: Params) : Runnable {
override fun run() {
params.packDir.mkdirs()
FileUtils.cleanOutputDir(params.packDir)
val jarCreator = JarCreatorFactory.make(jarFile = params.packFile.toPath())
// Disable compression for module zips, since this will only be used in bundletool and it
// will need to uncompress them anyway.
jarCreator.setCompressionLevel(Deflater.NO_COMPRESSION)
jarCreator.use {
if (params.assetsFilesPath.isNotEmpty()) {
it.addDirectory(
Paths.get(params.assetsFilesPath),
null,
null,
AssetRelocator(FD_ASSETS)
)
}
it.addJar(params.manifestFile.toPath(), Predicate { file -> file.endsWith(SdkConstants.FN_ANDROID_MANIFEST_XML) }, ManifestRelocator())
}
}
class Params(
val packDir: File,
val packFile: File,
val assetsFilesPath: String,
val manifestFile: File
) : Serializable
}