Search in sources :

Example 21 with BundleModuleName

use of com.android.tools.build.bundletool.model.BundleModuleName in project bundletool by google.

the class FusingAndroidManifestMergerTest method mergeFeatureActivitiesIntoBaseManifest.

@Test
@Theory
public void mergeFeatureActivitiesIntoBaseManifest(FusingAndroidManifestMerger.Mode mode) {
    SetMultimap<BundleModuleName, AndroidManifest> manifests = createManifests(androidManifest("com.testapp", withCustomThemeActivity("activity1", BASE_THEME_REF_ID), withCustomThemeActivity("activity2", BASE_THEME_REF_ID), withCustomThemeActivity("activity3", BASE_THEME_REF_ID)), androidManifestForFeature("com.testapp.feature1", withCustomThemeActivity("activity1", FEATURE1_THEME_REF_ID)), androidManifestForFeature("com.testapp.feature2", withCustomThemeActivity("activity3", FEATURE2_THEME_REF_ID)));
    AndroidManifest merged = createMerger(mode).merge(manifests);
    Map<String, Integer> refIdByActivity = Maps.transformValues(merged.getActivitiesByName(), activity -> activity.getAndroidAttribute(THEME_RESOURCE_ID).get().getValueAsRefId());
    assertThat(merged.getPackageName()).isEqualTo("com.testapp");
    assertThat(refIdByActivity).containsExactly("activity1", FEATURE1_THEME_REF_ID, "activity2", BASE_THEME_REF_ID, "activity3", FEATURE2_THEME_REF_ID).inOrder();
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) Test(org.junit.Test) Theory(org.junit.experimental.theories.Theory)

Example 22 with BundleModuleName

use of com.android.tools.build.bundletool.model.BundleModuleName in project bundletool by google.

the class FusingAndroidManifestMergerTest method duplicateManifest_throws.

@Test
public void duplicateManifest_throws() {
    SetMultimap<BundleModuleName, AndroidManifest> manifests = ImmutableSetMultimap.of(BASE_MODULE_NAME, AndroidManifest.create(androidManifest("com.testapp1")), BASE_MODULE_NAME, AndroidManifest.create(androidManifest("com.testapp2")));
    CommandExecutionException exception = assertThrows(CommandExecutionException.class, () -> createMerger(Mode.REPLACE).merge(manifests));
    assertThat(exception).hasMessageThat().isEqualTo("Expected exactly one base module manifest, but found 2.");
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) CommandExecutionException(com.android.tools.build.bundletool.model.exceptions.CommandExecutionException) Test(org.junit.Test)

Example 23 with BundleModuleName

use of com.android.tools.build.bundletool.model.BundleModuleName in project bundletool by google.

the class ApkSerializerManager method serializeApks.

@VisibleForTesting
ImmutableList<Variant> serializeApks(Path outputDirectory, GeneratedApks generatedApks, Optional<DeviceSpec> deviceSpec) {
    validateInput(generatedApks, apkBuildMode);
    // Running with system APK mode generates a fused APK and additional unmatched language splits.
    // To avoid filtering of unmatched language splits we skip device filtering for system mode.
    Predicate<ModuleSplit> deviceFilter = deviceSpec.isPresent() && !apkBuildMode.equals(SYSTEM) ? new ApkMatcher(addDefaultDeviceTierIfNecessary(deviceSpec.get()))::matchesModuleSplitByTargeting : alwaysTrue();
    ImmutableListMultimap<VariantKey, ModuleSplit> splitsByVariant = generatedApks.getAllApksGroupedByOrderedVariants();
    // Assign the variant numbers to each variant present.
    AtomicInteger variantNumberCounter = new AtomicInteger(firstVariantNumber);
    ImmutableMap<VariantKey, Integer> variantNumberByVariantKey = splitsByVariant.keySet().stream().collect(toImmutableMap(identity(), unused -> variantNumberCounter.getAndIncrement()));
    // 1. Remove APKs not matching the device spec.
    // 2. Modify the APKs based on the ApkModifier.
    // 3. Serialize all APKs in parallel.
    // Modifies the APK using APK modifier, then returns a map by extracting the variant
    // of APK first and later clearing out its variant targeting.
    ImmutableListMultimap<VariantKey, ModuleSplit> finalSplitsByVariant = splitsByVariant.entries().stream().filter(keyModuleSplitEntry -> deviceFilter.test(keyModuleSplitEntry.getValue())).collect(groupingBySortedKeys(Entry::getKey, entry -> clearVariantTargeting(modifyApk(entry.getValue(), variantNumberByVariantKey.get(entry.getKey())))));
    // After variant targeting of APKs are cleared, there might be duplicate APKs
    // which are removed and the distinct APKs are then serialized in parallel.
    ImmutableBiMap<ZipPath, ModuleSplit> splitsByRelativePath = finalSplitsByVariant.values().stream().distinct().collect(toImmutableBiMap(apkPathManager::getApkPath, identity()));
    ImmutableMap<ZipPath, ApkDescription> apkDescriptionsByRelativePath = apkSerializer.serialize(outputDirectory, splitsByRelativePath);
    // Build the result proto.
    ImmutableList.Builder<Variant> variants = ImmutableList.builder();
    for (VariantKey variantKey : finalSplitsByVariant.keySet()) {
        Variant.Builder variant = Variant.newBuilder().setVariantNumber(variantNumberByVariantKey.get(variantKey)).setTargeting(variantKey.getVariantTargeting());
        Multimap<BundleModuleName, ModuleSplit> splitsByModuleName = finalSplitsByVariant.get(variantKey).stream().collect(groupingBySortedKeys(ModuleSplit::getModuleName));
        for (BundleModuleName moduleName : splitsByModuleName.keySet()) {
            variant.addApkSet(ApkSet.newBuilder().setModuleMetadata(bundle.getModule(moduleName).getModuleMetadata()).addAllApkDescription(splitsByModuleName.get(moduleName).stream().map(split -> splitsByRelativePath.inverse().get(split)).map(apkDescriptionsByRelativePath::get).collect(toImmutableList())));
        }
        variants.add(variant.build());
    }
    return variants.build();
}
Also used : SYSTEM(com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode.SYSTEM) FirstVariantNumber(com.android.tools.build.bundletool.commands.BuildApksModule.FirstVariantNumber) Variant(com.android.bundle.Commands.Variant) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) DeviceSpec(com.android.bundle.Devices.DeviceSpec) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) Predicates.alwaysTrue(com.google.common.base.Predicates.alwaysTrue) DeliveryType(com.android.bundle.Commands.DeliveryType) Bundletool(com.android.bundle.Config.Bundletool) SdkBundle(com.android.tools.build.bundletool.model.SdkBundle) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AssetModulesConfig(com.android.bundle.Config.AssetModulesConfig) Path(java.nio.file.Path) BundleToolVersion(com.android.tools.build.bundletool.model.version.BundleToolVersion) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) Predicate(java.util.function.Predicate) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ManifestDeliveryElement(com.android.tools.build.bundletool.model.ManifestDeliveryElement) ApkOptimizations(com.android.tools.build.bundletool.optimizations.ApkOptimizations) ApkType(com.android.tools.build.bundletool.model.ApkModifier.ApkDescription.ApkType) InstantMetadata(com.android.bundle.Commands.InstantMetadata) SplitType(com.android.tools.build.bundletool.model.ModuleSplit.SplitType) GeneratedApks(com.android.tools.build.bundletool.model.GeneratedApks) UncheckedIOException(java.io.UncheckedIOException) DefaultTargetingValue(com.android.bundle.Commands.DefaultTargetingValue) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ApkSet(com.android.bundle.Commands.ApkSet) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) BundleConfig(com.android.bundle.Config.BundleConfig) PermanentlyFusedModule(com.android.bundle.Commands.PermanentlyFusedModule) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) Function.identity(java.util.function.Function.identity) Entry(java.util.Map.Entry) Optional(java.util.Optional) Bundle(com.android.tools.build.bundletool.model.Bundle) BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) ZipPath(com.android.tools.build.bundletool.model.ZipPath) OptimizationDimension(com.android.tools.build.bundletool.model.OptimizationDimension) VariantKey(com.android.tools.build.bundletool.model.VariantKey) CollectorUtils.groupingBySortedKeys(com.android.tools.build.bundletool.model.utils.CollectorUtils.groupingBySortedKeys) ApkModifier(com.android.tools.build.bundletool.model.ApkModifier) BuildApksResult(com.android.bundle.Commands.BuildApksResult) Multimap(com.google.common.collect.Multimap) CollectorUtils.groupingByDeterministic(com.android.tools.build.bundletool.model.utils.CollectorUtils.groupingByDeterministic) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) Inject(javax.inject.Inject) ImmutableList(com.google.common.collect.ImmutableList) Collectors.mapping(java.util.stream.Collectors.mapping) SdkVersionInformation(com.android.bundle.Commands.SdkVersionInformation) ApkDescription(com.android.bundle.Commands.ApkDescription) BuildSdkApksResult(com.android.bundle.Commands.BuildSdkApksResult) ApkMatcher(com.android.tools.build.bundletool.device.ApkMatcher) VariantTargeting(com.android.bundle.Targeting.VariantTargeting) SuffixStripping(com.android.bundle.Config.SuffixStripping) Int32Value(com.google.protobuf.Int32Value) AssetSliceSet(com.android.bundle.Commands.AssetSliceSet) IOException(java.io.IOException) AssetModuleMetadata(com.android.bundle.Commands.AssetModuleMetadata) VerboseLogs(com.android.tools.build.bundletool.commands.BuildApksModule.VerboseLogs) AssetModulesInfo(com.android.bundle.Commands.AssetModulesInfo) LocalTestingInfo(com.android.bundle.Commands.LocalTestingInfo) ApkBuildMode(com.android.tools.build.bundletool.commands.BuildApksCommand.ApkBuildMode) GeneratedAssetSlices(com.android.tools.build.bundletool.model.GeneratedAssetSlices) SplitDimension(com.android.bundle.Config.SplitDimension) ImmutableBiMap.toImmutableBiMap(com.google.common.collect.ImmutableBiMap.toImmutableBiMap) VisibleForTesting(com.google.common.annotations.VisibleForTesting) BundleModule(com.android.tools.build.bundletool.model.BundleModule) VariantKey(com.android.tools.build.bundletool.model.VariantKey) ApkDescription(com.android.bundle.Commands.ApkDescription) BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ImmutableList(com.google.common.collect.ImmutableList) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) ZipPath(com.android.tools.build.bundletool.model.ZipPath) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Variant(com.android.bundle.Commands.Variant) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ApkMatcher(com.android.tools.build.bundletool.device.ApkMatcher) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 24 with BundleModuleName

use of com.android.tools.build.bundletool.model.BundleModuleName in project bundletool by google.

the class BundleModuleMerger method mergeAndroidManifest.

private static void mergeAndroidManifest(Version bundletoolVersion, ImmutableSet<BundleModule> bundleModulesToFuse, BundleModule.Builder mergedBaseModule) {
    HashMultimap<BundleModuleName, AndroidManifest> manifests = bundleModulesToFuse.stream().collect(toMultimap(BundleModule::getName, BundleModule::getAndroidManifest, HashMultimap::create));
    AndroidManifestMerger manifestMerger = FUSE_APPLICATION_ELEMENTS_FROM_FEATURE_MANIFESTS.enabledForVersion(bundletoolVersion) ? fusingMergerApplicationElements() : fusingMergerOnlyReplaceActivities();
    AndroidManifest mergedManifest = manifestMerger.merge(manifests);
    mergedManifest = mergedManifest.toEditor().setFusedModuleNames(bundleModulesToFuse.stream().map(module -> module.getName().getName()).collect(toImmutableList())).save();
    mergedBaseModule.setAndroidManifest(mergedManifest);
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest)

Example 25 with BundleModuleName

use of com.android.tools.build.bundletool.model.BundleModuleName in project bundletool by google.

the class ModuleSplitsToShardMerger method mergeSingleShard.

/**
 * Gets a list of splits, and merges them into a single standalone APK (aka shard).
 *
 * <p>Allows to customize split type {@code mergedSplitType} of merged shard and Android manifest
 * merger {@code manifestMerger}.
 */
public ModuleSplit mergeSingleShard(ImmutableCollection<ModuleSplit> splitsOfShard, Map<ImmutableSet<ModuleEntry>, ImmutableList<Path>> mergedDexCache, SplitType mergedSplitType, AndroidManifestMerger manifestMerger) {
    ListMultimap<BundleModuleName, ModuleEntry> dexFilesToMergeByModule = ArrayListMultimap.create();
    // If multiple splits were generated from one module, we'll see the same manifest multiple
    // times. The multimap filters out identical (module name, manifest) pairs by contract.
    // All splits of a module should have the same manifest, so the following multimap should
    // associate just one value with each key. This is checked explicitly for the base module
    // because the manifest merger requires *single* base manifest.
    SetMultimap<BundleModuleName, AndroidManifest> androidManifestsToMergeByModule = HashMultimap.create();
    Map<ZipPath, ModuleEntry> mergedEntriesByPath = new HashMap<>();
    Optional<ResourceTable> mergedResourceTable = Optional.empty();
    Map<String, TargetedAssetsDirectory> mergedAssetsConfig = new HashMap<>();
    ApkTargeting mergedSplitTargeting = ApkTargeting.getDefaultInstance();
    for (ModuleSplit split : splitsOfShard) {
        // Resource tables and Split targetings can be merged for each split individually as we go.
        mergedResourceTable = mergeResourceTables(mergedResourceTable, split);
        mergedSplitTargeting = mergeSplitTargetings(mergedSplitTargeting, split);
        // Android manifests need to be merged later, globally for all splits.
        androidManifestsToMergeByModule.put(split.getModuleName(), split.getAndroidManifest());
        for (ModuleEntry entry : split.getEntries()) {
            if (entry.getPath().startsWith(DEX_DIRECTORY)) {
                // Dex files need to be merged later, globally for all splits.
                dexFilesToMergeByModule.put(split.getModuleName(), entry);
            } else {
                mergeEntries(mergedEntriesByPath, split, entry);
            }
        }
        split.getAssetsConfig().ifPresent(assetsConfig -> {
            mergeTargetedAssetsDirectories(mergedAssetsConfig, assetsConfig.getDirectoryList());
        });
    }
    AndroidManifest mergedAndroidManifest = manifestMerger.merge(androidManifestsToMergeByModule);
    Collection<ModuleEntry> mergedDexFiles = mergeDexFilesAndCache(dexFilesToMergeByModule, mergedAndroidManifest, mergedDexCache);
    // Record names of the modules this shard was fused from.
    ImmutableList<String> fusedModuleNames = getUniqueModuleNames(splitsOfShard);
    if (mergedSplitType.equals(SplitType.STANDALONE)) {
        mergedAndroidManifest = mergedAndroidManifest.toEditor().setFusedModuleNames(fusedModuleNames).save();
    }
    // Construct the final shard.
    return buildShard(mergedEntriesByPath.values(), mergedDexFiles, mergedSplitTargeting, mergedAndroidManifest, mergedResourceTable, mergedAssetsConfig, mergedSplitType);
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) TargetedAssetsDirectory(com.android.bundle.Files.TargetedAssetsDirectory) ApkTargeting(com.android.bundle.Targeting.ApkTargeting) HashMap(java.util.HashMap) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) ZipPath(com.android.tools.build.bundletool.model.ZipPath) ResourceTable(com.android.aapt.Resources.ResourceTable)

Aggregations

BundleModuleName (com.android.tools.build.bundletool.model.BundleModuleName)26 AndroidManifest (com.android.tools.build.bundletool.model.AndroidManifest)19 Test (org.junit.Test)14 ZipPath (com.android.tools.build.bundletool.model.ZipPath)6 BundleModule (com.android.tools.build.bundletool.model.BundleModule)5 ModuleSplit (com.android.tools.build.bundletool.model.ModuleSplit)5 ImmutableList (com.google.common.collect.ImmutableList)5 AppBundle (com.android.tools.build.bundletool.model.AppBundle)4 ModuleEntry (com.android.tools.build.bundletool.model.ModuleEntry)4 HashMap (java.util.HashMap)4 BundleConfig (com.android.bundle.Config.BundleConfig)3 VariantTargeting (com.android.bundle.Targeting.VariantTargeting)3 CommandExecutionException (com.android.tools.build.bundletool.model.exceptions.CommandExecutionException)3 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)3 ResourceTable (com.android.aapt.Resources.ResourceTable)2 DeviceSpec (com.android.bundle.Devices.DeviceSpec)2 TargetedAssetsDirectory (com.android.bundle.Files.TargetedAssetsDirectory)2 Predicates.not (com.google.common.base.Predicates.not)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 ImmutableMap.toImmutableMap (com.google.common.collect.ImmutableMap.toImmutableMap)2