| /* |
| * 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 |
| } |