| // Copyright 2017 The Bazel Authors. All rights reserved. |
| // |
| // 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.google.devtools.build.android; |
| |
| import static java.util.stream.Collectors.toSet; |
| |
| import com.android.builder.core.VariantConfiguration; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.util.concurrent.ListenableFuture; |
| import com.google.common.util.concurrent.ListeningExecutorService; |
| import com.google.devtools.build.android.ResourceShrinkerAction.Options; |
| import com.google.devtools.build.android.aapt2.Aapt2ConfigOptions; |
| import com.google.devtools.build.android.aapt2.CompiledResources; |
| import com.google.devtools.build.android.aapt2.ResourceCompiler; |
| import com.google.devtools.build.android.aapt2.ResourceLinker; |
| import com.google.devtools.build.android.aapt2.StaticLibrary; |
| import com.google.devtools.common.options.OptionsParser; |
| import com.google.devtools.common.options.ShellQuotedParamsFilePreProcessor; |
| import java.io.Closeable; |
| import java.io.File; |
| import java.nio.file.FileSystems; |
| import java.nio.file.Path; |
| import java.util.concurrent.ExecutionException; |
| import java.util.function.Function; |
| |
| /** |
| * An action to perform resource shrinking using the Gradle resource shrinker. |
| * |
| * <pre> |
| * Example Usage: |
| * java/com/google/build/android/ResourceShrinkerAction |
| * --aapt2 path to sdk/aapt2 |
| * --annotationJar path to sdk/annotationJar |
| * --androidJar path to sdk/androidJar |
| * --shrunkJar path to proguard dead code removal jar |
| * --resources path to processed resources zip |
| * --rTxt path to processed resources R.txt |
| * --primaryManifest path to processed resources AndroidManifest.xml |
| * --dependencyManifest path to dependency library manifest (repeated flag) |
| * --shrunkResourceApk path to write shrunk ap_ |
| * --shrunkResources path to write shrunk resources zip |
| * </pre> |
| */ |
| public class Aapt2ResourceShrinkingAction { |
| |
| public static void main(String[] args) throws Exception { |
| final Profiler profiler = LoggingProfiler.createAndStart("shrink").startTask("flags"); |
| // Parse arguments. |
| OptionsParser optionsParser = |
| OptionsParser.newOptionsParser(Options.class, Aapt2ConfigOptions.class); |
| optionsParser.enableParamsFileSupport( |
| new ShellQuotedParamsFilePreProcessor(FileSystems.getDefault())); |
| optionsParser.parseAndExitUponError(args); |
| Aapt2ConfigOptions aapt2ConfigOptions = optionsParser.getOptions(Aapt2ConfigOptions.class); |
| Options options = optionsParser.getOptions(Options.class); |
| options.dependencyManifests = |
| Converters.concatLists(options.dependencyManifests, options.deprecatedDependencyManifests); |
| profiler.recordEndOf("flags").startTask("setup"); |
| |
| final ListeningExecutorService executorService = ExecutorServiceCloser.createDefaultService(); |
| try (ScopedTemporaryDirectory scopedTmp = |
| new ScopedTemporaryDirectory("android_resources_tmp"); |
| Closeable closer = ExecutorServiceCloser.createWith(executorService)) { |
| |
| Path workingResourcesDirectory = scopedTmp.subDirectoryOf("resources"); |
| final ResourceCompiler resourceCompiler = |
| ResourceCompiler.create( |
| executorService, |
| workingResourcesDirectory, |
| aapt2ConfigOptions.aapt2, |
| aapt2ConfigOptions.buildToolsVersion); |
| profiler.recordEndOf("setup").startTask("compile"); |
| |
| final ResourcesZip resourcesZip = |
| ResourcesZip.createFrom( |
| options.resourcesZip, scopedTmp.subDirectoryOf("merged-resources")); |
| final CompiledResources compiled = |
| resourcesZip |
| .shrink( |
| options |
| .dependencyManifests |
| .stream() |
| .map(Path::toFile) |
| .map(manifestToPackageUsing(executorService)) |
| .map(futureToString()) |
| .collect(toSet()), |
| options.rTxt, |
| options.shrunkJar, |
| options.primaryManifest, |
| options.proguardMapping, |
| options.log, |
| scopedTmp.subDirectoryOf("shrunk-resources")) |
| .writeArchiveTo(options.shrunkResources, false) |
| .compile(resourceCompiler, workingResourcesDirectory); |
| profiler.recordEndOf("compile"); |
| |
| ResourceLinker.create(aapt2ConfigOptions.aapt2, scopedTmp.subDirectoryOf("linking")) |
| .profileUsing(profiler) |
| .dependencies(ImmutableList.of(StaticLibrary.from(aapt2ConfigOptions.androidJar))) |
| .link(compiled) |
| .copyPackageTo(options.shrunkApk) |
| .copyRTxtTo(options.rTxtOutput); |
| profiler.recordEndOf("shrink"); |
| } |
| } |
| |
| static Function<File, ListenableFuture<String>> manifestToPackageUsing( |
| ListeningExecutorService executor) { |
| return f -> executor.submit(() -> VariantConfiguration.getManifestPackage(f)); |
| } |
| |
| static Function<ListenableFuture<String>, String> futureToString() { |
| return f -> { |
| try { |
| return f.get(); |
| } catch (InterruptedException | ExecutionException e) { |
| throw new RuntimeException(e); |
| } |
| }; |
| } |
| } |