Search in sources :

Example 31 with ApkDescription

use of com.android.bundle.Commands.ApkDescription in project bundletool by google.

the class BuildApksPreprocessingTest method localTestingMode_enabled_addsMetadata.

@Test
public void localTestingMode_enabled_addsMetadata() throws Exception {
    AppBundle appBundle = createAppBundleWithBaseAndFeatureModules("feature");
    new AppBundleSerializer().writeToDisk(appBundle, bundlePath);
    BuildApksCommand command = BuildApksCommand.builder().setBundlePath(bundlePath).setOutputFile(outputFilePath).setLocalTestingMode(true).build();
    command.execute();
    try (ZipFile apkSet = new ZipFile(outputFilePath.toFile())) {
        BuildApksResult result = extractTocFromApkSetFile(apkSet, outputDir);
        assertThat(result.hasLocalTestingInfo()).isTrue();
        assertThat(result.getLocalTestingInfo().getEnabled()).isTrue();
        assertThat(result.getLocalTestingInfo().getLocalTestingPath()).isNotEmpty();
        ImmutableList<ApkDescription> apkDescriptions = apkDescriptions(result.getVariantList());
        assertThat(apkDescriptions).isNotEmpty();
        assertThat(apkDescriptions.stream().map(ApkDescription::getPath)).contains("splits/base-master.apk");
        for (ApkDescription apkDescription : apkDescriptions) {
            File apk = extractFromApkSetFile(apkSet, apkDescription.getPath(), outputDir);
            // The local testing metadata is set if and only if the apk is the base master.
            assertThat((apkDescription.hasSplitApkMetadata() && apkDescription.getSplitApkMetadata().getSplitId().isEmpty() && apkDescription.getSplitApkMetadata().getIsMasterSplit()) || apkDescription.hasStandaloneApkMetadata()).isEqualTo(extractAndroidManifest(apk).getMetadataValue(LocalTestingPreprocessor.METADATA_NAME).isPresent());
        }
    }
}
Also used : AppBundle(com.android.tools.build.bundletool.model.AppBundle) ApkDescription(com.android.bundle.Commands.ApkDescription) ZipFile(java.util.zip.ZipFile) BuildApksResult(com.android.bundle.Commands.BuildApksResult) AppBundleSerializer(com.android.tools.build.bundletool.io.AppBundleSerializer) ZipFile(java.util.zip.ZipFile) ApkSetUtils.extractTocFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile) File(java.io.File) ApkSetUtils.extractFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile) Test(org.junit.Test)

Example 32 with ApkDescription

use of com.android.bundle.Commands.ApkDescription in project bundletool by google.

the class BuildApksPreprocessingTest method localTestingMode_disabled_doesNotAddMetadata.

@Test
public void localTestingMode_disabled_doesNotAddMetadata() throws Exception {
    AppBundle appBundle = createAppBundleWithBaseAndFeatureModules("feature");
    new AppBundleSerializer().writeToDisk(appBundle, bundlePath);
    BuildApksCommand command = BuildApksCommand.builder().setBundlePath(bundlePath).setOutputFile(outputFilePath).setLocalTestingMode(false).build();
    command.execute();
    try (ZipFile apkSet = new ZipFile(outputFilePath.toFile())) {
        BuildApksResult result = extractTocFromApkSetFile(apkSet, outputDir);
        assertThat(result.getLocalTestingInfo().getEnabled()).isFalse();
        ImmutableList<ApkDescription> apkDescriptions = apkDescriptions(result.getVariantList());
        assertThat(apkDescriptions).isNotEmpty();
        for (ApkDescription apkDescription : apkDescriptions) {
            File apk = extractFromApkSetFile(apkSet, apkDescription.getPath(), outputDir);
            assertThat(extractAndroidManifest(apk).getMetadataValue(LocalTestingPreprocessor.METADATA_NAME)).isEmpty();
        }
    }
}
Also used : AppBundle(com.android.tools.build.bundletool.model.AppBundle) ApkDescription(com.android.bundle.Commands.ApkDescription) ZipFile(java.util.zip.ZipFile) BuildApksResult(com.android.bundle.Commands.BuildApksResult) AppBundleSerializer(com.android.tools.build.bundletool.io.AppBundleSerializer) ZipFile(java.util.zip.ZipFile) ApkSetUtils.extractTocFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile) File(java.io.File) ApkSetUtils.extractFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile) Test(org.junit.Test)

Example 33 with ApkDescription

use of com.android.bundle.Commands.ApkDescription in project bundletool by google.

the class BuildApksResourcePinningTest method resourceIds_pinnedToMasterSplits.

@Test
public void resourceIds_pinnedToMasterSplits() throws Exception {
    ResourceTable baseResourceTable = new ResourceTableBuilder().addPackage("com.test.app").addStringResource("test_label", "Module title").addFileResourceForMultipleConfigs("drawable", "image", ImmutableMap.of(Configuration.getDefaultInstance(), "res/drawable/image1.jpg", locale("fr"), "res/drawable-fr/image1.jpg")).addFileResourceForMultipleConfigs("drawable", "image2", ImmutableMap.of(Configuration.getDefaultInstance(), "res/drawable/image2.jpg", locale("fr"), "res/drawable-fr/image2.jpg")).build();
    ResourceTable featureResourceTable = new ResourceTableBuilder().addPackage("com.test.app.feature", 0x80).addFileResourceForMultipleConfigs("drawable", "image3", ImmutableMap.of(Configuration.getDefaultInstance(), "res/drawable/image3.jpg", locale("fr"), "res/drawable-fr/image3.jpg")).addFileResourceForMultipleConfigs("drawable", "image4", ImmutableMap.of(Configuration.getDefaultInstance(), "res/drawable/image4.jpg", locale("fr"), "res/drawable-fr/image4.jpg")).build();
    AppBundle appBundle = new AppBundleBuilder().addModule("base", builder -> builder.addFile("dex/classes.dex").addFile("res/drawable/image1.jpg").addFile("res/drawable-fr/image1.jpg").addFile("res/drawable/image2.jpg").addFile("res/drawable-fr/image2.jpg").setManifest(androidManifest("com.test.app", withMinSdkVersion(14))).setResourceTable(baseResourceTable)).addModule("feature", builder -> builder.addFile("res/drawable/image3.jpg").addFile("res/drawable-fr/image3.jpg").addFile("res/drawable/image4.jpg").addFile("res/drawable-fr/image4.jpg").setManifest(androidManifest("com.test.app", withMinSdkVersion(14), withOnDemandDelivery(), withFusingAttribute(true), withTitle("@string/test_label", 0x7f010000))).setResourceTable(featureResourceTable)).setBundleConfig(BundleConfigBuilder.create().addResourcePinnedToMasterSplit(// image1 from "base" module
    0x7f020000).addResourcePinnedToMasterSplit(// image4 from "feature" module
    0x80010001).build()).build();
    TestComponent.useTestModule(this, TestModule.builder().withAppBundle(appBundle).withOutputPath(outputFilePath).build());
    buildApksManager.execute();
    ZipFile apkSetFile = new ZipFile(outputFilePath.toFile());
    BuildApksResult result = extractTocFromApkSetFile(apkSetFile, outputDir);
    // Verifying that standalone APKs contain all entries.
    assertThat(standaloneApkVariants(result)).hasSize(1);
    List<ApkSet> standaloneApkSets = standaloneApkVariants(result).get(0).getApkSetList();
    assertThat(standaloneApkSets).hasSize(1);
    List<ApkDescription> standaloneApkDescription = standaloneApkSets.get(0).getApkDescriptionList();
    assertThat(standaloneApkDescription).hasSize(1);
    File standaloneApkFile = extractFromApkSetFile(apkSetFile, standaloneApkDescription.get(0).getPath(), outputDir);
    try (ZipFile standaloneZip = new ZipFile(standaloneApkFile)) {
        assertThat(filesUnderPath(standaloneZip, ZipPath.create("res"))).containsExactly("res/drawable/image1.jpg", "res/drawable-fr/image1.jpg", "res/drawable/image2.jpg", "res/drawable-fr/image2.jpg", "res/drawable/image3.jpg", "res/drawable-fr/image3.jpg", "res/drawable/image4.jpg", "res/drawable-fr/image4.jpg", "res/xml/splits0.xml");
    }
    // Verifying split APKs.
    assertThat(splitApkVariants(result)).hasSize(1);
    List<ApkSet> splitApkSetList = splitApkVariants(result).get(0).getApkSetList();
    Map<String, ApkSet> modules = Maps.uniqueIndex(splitApkSetList, apkSet -> apkSet.getModuleMetadata().getName());
    assertThat(modules.keySet()).containsExactly("base", "feature");
    List<ApkDescription> baseModuleApks = modules.get("base").getApkDescriptionList();
    assertThat(baseModuleApks).hasSize(2);
    Map<Boolean, ApkDescription> apkBaseMaster = Maps.uniqueIndex(baseModuleApks, apkDescription -> apkDescription.getSplitApkMetadata().getIsMasterSplit());
    ApkDescription baseMaster = apkBaseMaster.get(/* isMasterSplit= */
    true);
    File baseMasterFile = extractFromApkSetFile(apkSetFile, baseMaster.getPath(), outputDir);
    try (ZipFile baseMasterZip = new ZipFile(baseMasterFile)) {
        assertThat(filesUnderPath(baseMasterZip, ZipPath.create("res"))).containsExactly("res/drawable/image1.jpg", "res/drawable-fr/image1.jpg", "res/drawable/image2.jpg", "res/xml/splits0.xml", "res/xml/locales_config.xml");
    }
    ApkDescription baseFr = apkBaseMaster.get(/* isMasterSplit= */
    false);
    File baseFrFile = extractFromApkSetFile(apkSetFile, baseFr.getPath(), outputDir);
    try (ZipFile baseFrZip = new ZipFile(baseFrFile)) {
        assertThat(filesUnderPath(baseFrZip, ZipPath.create("res"))).containsExactly("res/drawable-fr/image2.jpg");
    }
    List<ApkDescription> featureModuleApks = modules.get("feature").getApkDescriptionList();
    assertThat(featureModuleApks).hasSize(2);
    Map<Boolean, ApkDescription> apkFeatureMaster = Maps.uniqueIndex(featureModuleApks, apkDescription -> apkDescription.getSplitApkMetadata().getIsMasterSplit());
    ApkDescription featureMaster = apkFeatureMaster.get(/* isMasterSplit= */
    true);
    File featureMasterFile = extractFromApkSetFile(apkSetFile, featureMaster.getPath(), outputDir);
    try (ZipFile featureMasterZip = new ZipFile(featureMasterFile)) {
        assertThat(filesUnderPath(featureMasterZip, ZipPath.create("res"))).containsExactly("res/drawable/image3.jpg", "res/drawable/image4.jpg", "res/drawable-fr/image4.jpg");
    }
    ApkDescription featureFr = apkFeatureMaster.get(/* isMasterSplit= */
    false);
    File featureFrFile = extractFromApkSetFile(apkSetFile, featureFr.getPath(), outputDir);
    try (ZipFile featureFrZip = new ZipFile(featureFrFile)) {
        assertThat(filesUnderPath(featureFrZip, ZipPath.create("res"))).containsExactly("res/drawable-fr/image3.jpg");
    }
}
Also used : TestModule(com.android.tools.build.bundletool.testing.TestModule) ZipPath(com.android.tools.build.bundletool.model.ZipPath) ResultUtils.standaloneApkVariants(com.android.tools.build.bundletool.model.utils.ResultUtils.standaloneApkVariants) ManifestProtoUtils.androidManifest(com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest) ResourcesTableFactory.locale(com.android.tools.build.bundletool.testing.ResourcesTableFactory.locale) BundleConfigBuilder(com.android.tools.build.bundletool.testing.BundleConfigBuilder) RunWith(org.junit.runner.RunWith) BuildApksResult(com.android.bundle.Commands.BuildApksResult) Component(dagger.Component) Inject(javax.inject.Inject) ApkSetUtils.extractTocFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile) ProtoTruth.assertThat(com.google.common.truth.extensions.proto.ProtoTruth.assertThat) ResourceTableBuilder(com.android.tools.build.bundletool.testing.ResourceTableBuilder) Map(java.util.Map) ApkDescription(com.android.bundle.Commands.ApkDescription) ResultUtils.splitApkVariants(com.android.tools.build.bundletool.model.utils.ResultUtils.splitApkVariants) ManifestProtoUtils.withOnDemandDelivery(com.android.tools.build.bundletool.testing.ManifestProtoUtils.withOnDemandDelivery) ZipFile(java.util.zip.ZipFile) TestUtils.filesUnderPath(com.android.tools.build.bundletool.testing.TestUtils.filesUnderPath) Path(java.nio.file.Path) ResourceTable(com.android.aapt.Resources.ResourceTable) Before(org.junit.Before) ManifestProtoUtils.withTitle(com.android.tools.build.bundletool.testing.ManifestProtoUtils.withTitle) ImmutableMap(com.google.common.collect.ImmutableMap) ManifestProtoUtils.withFusingAttribute(com.android.tools.build.bundletool.testing.ManifestProtoUtils.withFusingAttribute) Test(org.junit.Test) JUnit4(org.junit.runners.JUnit4) Truth.assertThat(com.google.common.truth.Truth.assertThat) Maps(com.google.common.collect.Maps) File(java.io.File) ApkSetUtils.extractFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile) ManifestProtoUtils.withMinSdkVersion(com.android.tools.build.bundletool.testing.ManifestProtoUtils.withMinSdkVersion) ApkSet(com.android.bundle.Commands.ApkSet) List(java.util.List) AppBundleBuilder(com.android.tools.build.bundletool.testing.AppBundleBuilder) Rule(org.junit.Rule) AppBundle(com.android.tools.build.bundletool.model.AppBundle) Configuration(com.android.aapt.ConfigurationOuterClass.Configuration) TemporaryFolder(org.junit.rules.TemporaryFolder) ApkSet(com.android.bundle.Commands.ApkSet) AppBundle(com.android.tools.build.bundletool.model.AppBundle) ApkDescription(com.android.bundle.Commands.ApkDescription) BuildApksResult(com.android.bundle.Commands.BuildApksResult) ResourceTableBuilder(com.android.tools.build.bundletool.testing.ResourceTableBuilder) ZipFile(java.util.zip.ZipFile) AppBundleBuilder(com.android.tools.build.bundletool.testing.AppBundleBuilder) ApkSetUtils.extractTocFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile) ZipFile(java.util.zip.ZipFile) File(java.io.File) ApkSetUtils.extractFromApkSetFile(com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile) ResourceTable(com.android.aapt.Resources.ResourceTable) Test(org.junit.Test)

Example 34 with ApkDescription

use of com.android.bundle.Commands.ApkDescription in project bundletool by google.

the class ModuleSplitSerializer method serialize.

/**
 * Serializes module splits on disk under {@code outputDirectory}.
 *
 * <p>Returns {@link ApkDescription} for each serialized split keyed by relative path of module
 * split.
 */
public ImmutableMap<ZipPath, ApkDescription> serialize(Path outputDirectory, ImmutableMap<ZipPath, ModuleSplit> splitsByRelativePath) {
    // Prepare original splits by:
    // * signing embedded APKs
    // * injecting manifest and resource table as module entries.
    ImmutableList<ModuleSplit> preparedSplits = splitsByRelativePath.values().stream().map(apkSigner::signEmbeddedApks).map(ModuleSplitSerializer::injectManifestAndResourceTableAsEntries).collect(toImmutableList());
    try (SerializationFilesManager filesManager = new SerializationFilesManager()) {
        // Convert module splits to binary format and apply uncompressed globs specified in
        // BundleConfig. We do it in this order because as specified in documentation the matching
        // for uncompressed globs is done against paths in final APKs.
        ImmutableList<ModuleSplit> binarySplits = aapt2ResourceConverter.convert(preparedSplits, filesManager).stream().map(this::applyUncompressedGlobsAndUncompressedNativeLibraries).collect(toImmutableList());
        // Build a pack from entries which may be compressed inside final APKs. 'May be
        // compressed' means that for these entries we will decide later should they be compressed
        // or not based on whether we gain enough savings from compression.
        ModuleEntriesPack maybeCompressedEntriesPack = buildCompressedEntriesPack(filesManager.getCompressedResourceEntriesPackPath(), filesManager.getCompressedEntriesPackPath(), binarySplits);
        // Build a pack with entries that are uncompressed in final APKs: force uncompressed entries
        // + entries that have very low compression ratio.
        ModuleEntriesPack uncompressedEntriesPack = buildUncompressedEntriesPack(filesManager.getUncompressedEntriesPackPath(), binarySplits, maybeCompressedEntriesPack);
        // Now content of all binary apks is already moved to compressed/uncompressed packs. Delete
        // them to free space.
        filesManager.closeAndRemoveBinaryApks();
        // Merge two packs together, so we have all entries for final APKs inside one pack. If the
        // same entry is in both packs we prefer uncompressed one, because it means this entry
        // has very low compression ratio, it makes no sense to put it in compressed form.
        ModuleEntriesPack allEntriesPack = maybeCompressedEntriesPack.mergeWith(uncompressedEntriesPack);
        // Serialize and sign final APKs.
        ImmutableList<ListenableFuture<ApkDescription>> apkDescriptions = Streams.zip(splitsByRelativePath.keySet().stream(), binarySplits.stream(), (relativePath, split) -> executorService.submit(() -> serializeAndSignSplit(outputDirectory, relativePath, split, allEntriesPack, uncompressedEntriesPack))).collect(toImmutableList());
        return ConcurrencyUtils.waitForAll(apkDescriptions).stream().collect(toImmutableMap(apk -> ZipPath.create(apk.getPath()), identity()));
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}
Also used : PathMatcher(com.android.tools.build.bundletool.model.utils.PathMatcher) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) ZipPath(com.android.tools.build.bundletool.model.ZipPath) ApkListener(com.android.tools.build.bundletool.model.ApkListener) Inject(javax.inject.Inject) ApkSerializerHelper.toApkEntryPath(com.android.tools.build.bundletool.io.ApkSerializerHelper.toApkEntryPath) ImmutableList(com.google.common.collect.ImmutableList) ApkDescription(com.android.bundle.Commands.ApkDescription) ZipArchive(com.android.zipflinger.ZipArchive) Version(com.android.tools.build.bundletool.model.version.Version) ByteSource(com.google.common.io.ByteSource) Path(java.nio.file.Path) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) ApkSerializerHelper.requiresAapt2Conversion(com.android.tools.build.bundletool.io.ApkSerializerHelper.requiresAapt2Conversion) IOException(java.io.IOException) Deflater(java.util.zip.Deflater) VerboseLogs(com.android.tools.build.bundletool.commands.BuildApksModule.VerboseLogs) Streams(com.google.common.collect.Streams) Entry(com.android.zipflinger.Entry) ZipSource(com.android.zipflinger.ZipSource) SpecialModuleEntry(com.android.tools.build.bundletool.model.BundleModule.SpecialModuleEntry) UncheckedIOException(java.io.UncheckedIOException) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) BundleConfig(com.android.bundle.Config.BundleConfig) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) NO_DEFAULT_UNCOMPRESS_EXTENSIONS(com.android.tools.build.bundletool.model.version.VersionGuardedFeature.NO_DEFAULT_UNCOMPRESS_EXTENSIONS) Function.identity(java.util.function.Function.identity) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) Comparator(java.util.Comparator) FileUtils(com.android.tools.build.bundletool.model.utils.files.FileUtils) ListeningExecutorService(com.google.common.util.concurrent.ListeningExecutorService) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException)

Example 35 with ApkDescription

use of com.android.bundle.Commands.ApkDescription in project bundletool by google.

the class ModuleSplitSerializer method serializeAndSignSplit.

private ApkDescription serializeAndSignSplit(Path outputDirectory, ZipPath apkRelativePath, ModuleSplit split, ModuleEntriesPack allEntriesPack, ModuleEntriesPack uncompressedEntriesPack) {
    Path outputPath = outputDirectory.resolve(apkRelativePath.toString());
    ApkDescription apkDescription = ApkDescriptionHelper.createApkDescription(apkRelativePath, split);
    serializeSplit(outputPath, split, allEntriesPack, uncompressedEntriesPack);
    apkSigner.signApk(outputPath, split);
    notifyApkSerialized(apkDescription, split.getSplitType());
    return apkDescription;
}
Also used : ZipPath(com.android.tools.build.bundletool.model.ZipPath) ApkSerializerHelper.toApkEntryPath(com.android.tools.build.bundletool.io.ApkSerializerHelper.toApkEntryPath) Path(java.nio.file.Path) ApkDescription(com.android.bundle.Commands.ApkDescription)

Aggregations

ApkDescription (com.android.bundle.Commands.ApkDescription)62 ZipFile (java.util.zip.ZipFile)57 Test (org.junit.Test)56 BuildApksResult (com.android.bundle.Commands.BuildApksResult)54 ApkSetUtils.extractFromApkSetFile (com.android.tools.build.bundletool.testing.ApkSetUtils.extractFromApkSetFile)54 File (java.io.File)54 Variant (com.android.bundle.Commands.Variant)52 AppBundle (com.android.tools.build.bundletool.model.AppBundle)51 AppBundleBuilder (com.android.tools.build.bundletool.testing.AppBundleBuilder)51 ApkSetUtils.extractTocFromApkSetFile (com.android.tools.build.bundletool.testing.ApkSetUtils.extractTocFromApkSetFile)50 Path (java.nio.file.Path)49 AndroidManifest (com.android.tools.build.bundletool.model.AndroidManifest)48 ZipPath (com.android.tools.build.bundletool.model.ZipPath)48 CodeRelatedFile (com.android.bundle.CodeTransparencyOuterClass.CodeRelatedFile)47 ApkSet (com.android.bundle.Commands.ApkSet)47 ApkSetUtils.parseTocFromFile (com.android.tools.build.bundletool.testing.ApkSetUtils.parseTocFromFile)47 ResourceTableBuilder (com.android.tools.build.bundletool.testing.ResourceTableBuilder)47 TestUtils.extractAndroidManifest (com.android.tools.build.bundletool.testing.TestUtils.extractAndroidManifest)47 ApkVerifier (com.android.apksig.ApkVerifier)46 BundleConfigBuilder (com.android.tools.build.bundletool.testing.BundleConfigBuilder)46