/// <summary> /// Builds an Android App Bundle at the specified location containing the specified modules, with optional /// targeting done by texture compression format. /// </summary> /// <param name="outputFile">The output Android App Bundle (AAB) file.</param> /// <param name="moduleFiles">The modules to build inside the bundle.</param> /// <param name="metadataFiles">Metadata files to include in the bundle.</param> /// <param name="buildBundleConfigParams">Contains parameters needed to generate JSON for --config.</param> /// <returns>An error message if there was a problem running bundletool, or null if successful.</returns> public virtual string BuildBundle(string outputFile, IEnumerable <string> moduleFiles, IEnumerable <string> metadataFiles, BuildBundleConfigParams buildBundleConfigParams) { var bundleConfigJsonFile = Path.Combine(Path.GetTempPath(), "BundleConfig.json"); var bundleConfig = MakeConfig(buildBundleConfigParams, _streamingAssetsPath); var bundleConfigJsonText = CleanDisabledSuffixStripping(JsonUtility.ToJson(bundleConfig)); File.WriteAllText(bundleConfigJsonFile, bundleConfigJsonText); var metadataArgumentBuilder = new StringBuilder(); foreach (var metadataFile in metadataFiles) { metadataArgumentBuilder.AppendFormat(" --metadata-file={0}", metadataFile); } // TODO(b/128882014): fix bundletool support for quoted paths around moduleFiles. return(Run( "build-bundle --config={0} --modules={1} --output={2}{3}", CommandLine.QuotePath(bundleConfigJsonFile), string.Join(",", moduleFiles.ToArray()), CommandLine.QuotePath(outputFile), metadataArgumentBuilder.ToString())); }
/// <summary> /// BundleTool config optimized for Unity-based apps. /// </summary> public static BundletoolConfig.Config MakeConfig( BuildBundleConfigParams configParams, string streamingAssetsPath) { var config = new BundletoolConfig.Config(); // APK download size is smaller when native libraries are uncompressed. uncompressNativeLibraries sets // android:extractNativeLibs="false" in the manifest, which also reduces on-disk for Android 6.0+ devices. // However, apps built with older Unity versions will crash when android:extractNativeLibs="false", so // we must set it to false. #if UNITY_2017_2_OR_NEWER config.optimizations.uncompressNativeLibraries.enabled = true; #elif PLAY_INSTANT config.optimizations.uncompressNativeLibraries.enabled = false; // For instant builds we mark the "lib" folder as uncompressed to get a download size reduction at the // expense of slightly increased on-disk size. config.compression.uncompressedGlob.Add("lib/**"); #else config.optimizations.uncompressNativeLibraries.enabled = false; #endif config.compression.uncompressedGlob.AddRange(UnityUncompressedGlob); config.compression.uncompressedGlob.AddRange(GetStreamingAssetsFilePaths(streamingAssetsPath)); var dimensions = config.optimizations.splitsConfig.splitDimension; // Split on ABI so only one set of native libraries (armeabi-v7a, arm64-v8a, or x86) is sent to a device. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Abi, negate = false }); // Do not split on LANGUAGE since Unity games don't store localized strings in the typical Android manner. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Language, negate = true }); // Do not split on SCREEN_DENSITY since Unity games don't have per-density resources other than app icons. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.ScreenDensity, negate = true }); if (configParams.enableTcfTargeting) { dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.TextureCompressionFormat, negate = false, suffixStripping = { enabled = true, defaultSuffix = configParams.defaultTcfSuffix } }); } // Bundletool requires the below standaloneConfig when supporting install-time asset packs for pre-Lollipop. if (configParams.containsInstallTimeAssetPack && configParams.minSdkVersion < AndroidSdkVersions.AndroidApiLevel21) { config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Abi, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Language, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.ScreenDensity, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.TextureCompressionFormat, negate = true }); config.optimizations.standaloneConfig.strip64BitLibraries = true; } return(config); }
/// <summary> /// BundleTool config optimized for Unity-based apps. /// </summary> public static BundletoolConfig.Config MakeConfig( BuildBundleConfigParams configParams, string streamingAssetsPath) { var config = new BundletoolConfig.Config(); // APK download size is smaller when native libraries are uncompressed. uncompressNativeLibraries sets // android:extractNativeLibs="false" in the manifest, which also reduces on-disk for Android 6.0+ devices. config.optimizations.uncompressNativeLibraries.enabled = true; config.compression.uncompressedGlob.AddRange(UnityUncompressedGlob); var compressionOptions = configParams.compressionOptions; if (compressionOptions.UncompressedGlobs != null) { config.compression.uncompressedGlob.AddRange(compressionOptions.UncompressedGlobs); } if (!compressionOptions.CompressStreamingAssets) { config.compression.uncompressedGlob.AddRange(GetStreamingAssetsFileGlobs(streamingAssetsPath)); } if (compressionOptions.CompressInstallTimeAssetPacks) { config.compression.installTimeAssetModuleDefaultCompression = BundletoolConfig.Compressed; } var dimensions = config.optimizations.splitsConfig.splitDimension; // Split on ABI so only one set of native libraries (armeabi-v7a, arm64-v8a, or x86) is sent to a device. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Abi, negate = false }); // Do not split on LANGUAGE since Unity games don't store localized strings in the typical Android manner. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Language, negate = true }); // Do not split on SCREEN_DENSITY since Unity games don't have per-density resources other than app icons. dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.ScreenDensity, negate = true }); if (configParams.enableTcfTargeting) { dimensions.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.TextureCompressionFormat, negate = false, suffixStripping = { enabled = true, defaultSuffix = configParams.defaultTcfSuffix } }); } // Bundletool requires the below standaloneConfig when supporting install-time asset packs for pre-Lollipop. if (configParams.containsInstallTimeAssetPack && TextureTargetingTools.IsSdkVersionPreLollipop(configParams.minSdkVersion)) { config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Abi, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.Language, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.ScreenDensity, negate = true }); config.optimizations.standaloneConfig.splitDimension.Add(new BundletoolConfig.SplitDimension { value = BundletoolConfig.TextureCompressionFormat, negate = true }); config.optimizations.standaloneConfig.strip64BitLibraries = true; } return(config); }