diff options
author | corysmith <corysmith@google.com> | 2017-08-23 15:24:31 +0200 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2017-08-23 15:46:23 +0200 |
commit | e516a101bb615f064d6622a5d4add541617b8c1f (patch) | |
tree | 93b6a3989b048a1cd35d9c1b37f411f77ec556bc /src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java | |
parent | 296cb428546a7e966065b03137eca362efb9f34c (diff) |
Adds compile action for aapt2: Aapt2ResourcePackagingAction
Adds a ManifestContainer interface to centralize the types that provide manifests.
Adds PackagedResources to represent a linked dexless resource apk
RELNOTES: None
PiperOrigin-RevId: 166193049
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java')
-rw-r--r-- | src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java | 190 |
1 files changed, 171 insertions, 19 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java b/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java index eb17f2dc9f..fa9edc3044 100644 --- a/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java +++ b/src/tools/android/java/com/google/devtools/build/android/aapt2/ResourceLinker.java @@ -15,18 +15,43 @@ package com.google.devtools.build.android.aapt2; import com.android.builder.core.VariantType; import com.android.repository.Revision; +import com.google.common.base.Joiner; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.io.ByteStreams; import com.google.devtools.build.android.AaptCommandBuilder; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.zip.ZipFile; /** Performs linking of {@link CompiledResources} using aapt2. */ public class ResourceLinker { + /** Represents errors thrown during linking. */ + public static class LinkError extends RuntimeException { + public LinkError(Throwable e) { + super(e); + } + } + + private static final Logger logger = Logger.getLogger(ResourceLinker.class.getName()); + private final Path aapt2; - private List<StaticLibrary> libraries; - private Revision buildToolsVersion; private final Path workingDirectory; + private List<StaticLibrary> linkAgainst = ImmutableList.of(); + private Revision buildToolsVersion; + private String density; + private Path androidJar; + private List<String> uncompressedExtensions = ImmutableList.of(); + private List<String> resourceConfigs = ImmutableList.of(); + private Path baseApk; + private List<StaticLibrary> include; private ResourceLinker(Path aapt2, Path workingDirectory) { this.aapt2 = aapt2; @@ -37,9 +62,15 @@ public class ResourceLinker { return new ResourceLinker(aapt2, workingDirectory); } - /** Dependent static libraries to be linked to. */ - public ResourceLinker dependencies(List<StaticLibrary> libraries) { - this.libraries = libraries; + /** Dependent static to be linked against. */ + public ResourceLinker dependencies(List<StaticLibrary> linkAgainst) { + this.linkAgainst = linkAgainst; + return this; + } + + /** Dependent static libraries to be included in the binary. */ + public ResourceLinker include(List<StaticLibrary> include) { + this.include = include; return this; } @@ -48,26 +79,147 @@ public class ResourceLinker { return this; } + public ResourceLinker baseApkToLinkAgainst(Path baseApk) { + this.baseApk = baseApk; + return this; + } + + public ResourceLinker filterToDensity(List<String> densitiesToFilter) { + if (densitiesToFilter.size() > 1) { + throw new UnsupportedOperationException("Multiple densities not yet supported with aapt2"); + } + if (densitiesToFilter.size() > 0) { + density = Iterables.getOnlyElement(densitiesToFilter); + } + return this; + } + /** * Statically links the {@link CompiledResources} with the dependencies to produce a {@link * StaticLibrary}. * * @throws IOException */ - public StaticLibrary linkStatically(CompiledResources resources) throws IOException { + public StaticLibrary linkStatically(CompiledResources resources) { final Path outPath = workingDirectory.resolve("lib.ap_"); - new AaptCommandBuilder(aapt2) - .forBuildToolsVersion(buildToolsVersion) - .forVariantType(VariantType.LIBRARY) - .add("link") - .add("--manifest", resources.asManifest()) - .add("--static-lib") - .add("--output-text-symbols", workingDirectory) - .add("-o", outPath) - .add("--auto-add-overlay") - .addRepeated("-I", StaticLibrary.toPathStrings(libraries)) - .add("-R", resources.asZip()) - .execute(String.format("Linking %s", resources)); - return StaticLibrary.from(outPath); + Path rTxt = workingDirectory.resolve("R.txt"); + + try { + logger.fine( + new AaptCommandBuilder(aapt2) + .forBuildToolsVersion(buildToolsVersion) + .forVariantType(VariantType.LIBRARY) + .add("link") + .add("--manifest", resources.getManifest()) + .add("--static-lib") + .add("--no-static-lib-packages") + .whenVersionIsAtLeast(new Revision(23)) + .thenAdd("--no-version-vectors") + .addRepeated("-R", unzipCompiledResources(resources.getZip())) + .addRepeated("-I", StaticLibrary.toPathStrings(linkAgainst)) + .add("--auto-add-overlay") + .add("-o", outPath) + .add("--java", workingDirectory.resolve("java")) // java needed to create R.txt + .add("--output-text-symbols", rTxt) + .execute(String.format("Statically linking %s", resources))); + return StaticLibrary.from(outPath, rTxt); + } catch (IOException e) { + throw new LinkError(e); + } + } + + public PackagedResources link(CompiledResources compiled) { + final Path outPath = workingDirectory.resolve("bin.ap_"); + Path rTxt = workingDirectory.resolve("R.txt"); + Path proguardConfig = workingDirectory.resolve("proguard.cfg"); + Path mainDexProguard = workingDirectory.resolve("proguard.maindex.cfg"); + Path javaSourceDirectory = workingDirectory.resolve("java"); + + try { + logger.fine( + new AaptCommandBuilder(aapt2) + .forBuildToolsVersion(buildToolsVersion) + .forVariantType(VariantType.DEFAULT) + .add("link") + .whenVersionIsAtLeast(new Revision(23)) + .thenAdd("--no-version-vectors") + .add("--no-static-lib-packages") + .when(Level.FINE.equals(logger.getLevel())) + .thenAdd("-v") + .add("--manifest", compiled.getManifest()) + .add("--auto-add-overlay") + .addRepeated("-A", compiled.getAssetsStrings()) + .addRepeated("-I", StaticLibrary.toPathStrings(linkAgainst)) + .addRepeated("-R", StaticLibrary.toPathStrings(include)) + .addRepeated("-R", unzipCompiledResources(compiled.getZip())) + // Never compress apks. + .add("-0", "apk") + // Add custom no-compress extensions. + .addRepeated("-0", uncompressedExtensions) + .addRepeated("-A", StaticLibrary.toAssetPaths(include)) + .when(density != null) + .thenAdd("--preferred-density", density) + // Filter by resource configuration type. + .when(!resourceConfigs.isEmpty()) + .thenAdd("-c", Joiner.on(',').join(resourceConfigs)) + .add("--output-text-symbols", rTxt) + .add("--java", javaSourceDirectory) + .add("--proguard", proguardConfig) + .add("--proguard-main-dex", mainDexProguard) + .add("-o", outPath) + .execute(String.format("Linking %s", compiled.getManifest()))); + return PackagedResources.of( + outPath, rTxt, proguardConfig, mainDexProguard, javaSourceDirectory); + } catch (IOException e) { + throw new LinkError(e); + } + } + + private List<String> unzipCompiledResources(Path resourceZip) throws IOException { + final ZipFile zipFile = new ZipFile(resourceZip.toFile()); + return zipFile + .stream() + .map( + entry -> { + final Path resolve = workingDirectory.resolve(entry.getName()); + try { + Files.createDirectories(resolve.getParent()); + return Files.write(resolve, ByteStreams.toByteArray(zipFile.getInputStream(entry))); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .map(Path::toString) + .collect(Collectors.toList()); + } + + public ResourceLinker storeUncompressed(List<String> uncompressedExtensions) { + this.uncompressedExtensions = uncompressedExtensions; + return this; + } + + public ResourceLinker includeOnlyConfigs(List<String> resourceConfigs) { + this.resourceConfigs = resourceConfigs; + return this; + } + + public ResourceLinker using(Path androidJar) { + this.androidJar = androidJar; + return this; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("aapt2", aapt2) + .add("linkAgainst", linkAgainst) + .add("buildToolsVersion", buildToolsVersion) + .add("workingDirectory", workingDirectory) + .add("density", density) + .add("androidJar", androidJar) + .add("uncompressedExtensions", uncompressedExtensions) + .add("resourceConfigs", resourceConfigs) + .add("baseApk", baseApk) + .toString(); } } |