private string CreateBaseModules(IList <DirectoryInfo> moduleDirectoryList, CreateBundleOptions options, DirectoryInfo workingDirectory, out IList <string> bundleMetadata) { // Create base module directory. bundleMetadata = new List <string>(); var baseDirectory = workingDirectory.CreateSubdirectory(AndroidAppBundle.BaseModuleName); var baseErrorMessage = CreateBaseModule(baseDirectory, out bundleMetadata); if (baseErrorMessage != null) { // Already displayed the error. return(baseErrorMessage); } moduleDirectoryList.Add(baseDirectory); if (options.AssetPackConfig.SplitBaseModuleAssets) { // Move assets from base module directory to the separate module's directory. var splitBaseDirectory = workingDirectory.CreateSubdirectory(AndroidAppBundle.BaseAssetsModuleName); var splitBaseErrorMessage = CreateSplitBaseModule(baseDirectory, splitBaseDirectory); if (splitBaseErrorMessage != null) { // Already displayed the error. return(splitBaseErrorMessage); } moduleDirectoryList.Add(splitBaseDirectory); } return(null); }
/// <summary> /// Asynchronously builds an AAB at the specified path. /// </summary> /// <param name="aabFilePath">The AAB output file path.</param> /// <param name="assetPackConfig">Asset packs to include in the AAB.</param> /// <param name="onSuccess"> /// Callback that fires with the final aab file location, when the bundle creation succeeds. /// </param> public void CreateBundleAsync(CreateBundleOptions options, PostBuildCallback onSuccess) { // Copy the AssetPackConfig before leaving the main thread in case the original is modified later. options.AssetPackConfig = SerializationHelper.DeepCopy(options.AssetPackConfig); _createBundleAsyncOnSuccess = onSuccess; StartCreateBundleAsync(() => { try { CreateBundle(options); } catch (ThreadAbortException ex) { if (!_canceled) { // Unexpected ThreadAbortException. DisplayBuildError("Exception", ex.ToString()); } } catch (Exception ex) { // Catch and display exceptions since they may otherwise be undetected on a background thread. DisplayBuildError("Exception", ex.ToString()); } }); }
/// <summary> /// Synchronously builds an Android Player and then produces a final AAB synchronously or asynchronously, /// as specified. /// </summary> /// <param name="androidBuildOptions">Options indicating how to build the AAB, including asset packs.</param> /// <returns>An async task that provides an AndroidBuildReport.</returns> public async Task <AndroidBuildReport> CreateBundleWithTask(AndroidBuildOptions androidBuildOptions) { var taskCompletionSource = new TaskCompletionSource <AndroidBuildReport>(); var androidBuildResult = BuildAndroidPlayer(androidBuildOptions.BuildPlayerOptions); if (androidBuildResult.Cancelled) { taskCompletionSource.SetCanceled(); return(await taskCompletionSource.Task); } var androidBuildReport = new AndroidBuildReport(androidBuildResult.Report); if (androidBuildResult.ErrorMessage != null) { taskCompletionSource.SetException( new AndroidBuildException(androidBuildResult.ErrorMessage, androidBuildReport)); return(await taskCompletionSource.Task); } var createBundleOptions = new CreateBundleOptions { AabFilePath = androidBuildOptions.BuildPlayerOptions.locationPathName, AssetPackConfig = androidBuildOptions.AssetPackConfig ?? new AssetPackConfig(), CompressionOptions = androidBuildOptions.CompressionOptions }; if (androidBuildOptions.ForceSingleThreadedBuild || Application.isBatchMode) { CreateBundleInternal( taskCompletionSource, () => CreateBundle(createBundleOptions), androidBuildReport, androidBuildReport); } else { // Copy the AssetPackConfig while still on the main thread in case the original is modified later. createBundleOptions.AssetPackConfig = SerializationHelper.DeepCopy(createBundleOptions.AssetPackConfig); StartCreateBundleAsync(() => { CreateBundleInternal( taskCompletionSource, () => CreateBundle(createBundleOptions), androidBuildReport, androidBuildReport); }); } return(await taskCompletionSource.Task); }
/// <summary> /// Synchronously builds an AAB given the specified options and existing Android Player on disk. /// </summary> /// <returns>An error message if there was an error, or null if successful.</returns> public string CreateBundle(CreateBundleOptions options) { if (_buildStatus != BuildStatus.Running) { throw new Exception("Unexpected call to CreateBundle() with status: " + _buildStatus); } var moduleDirectoryList = new List <DirectoryInfo>(); var workingDirectory = new DirectoryInfo(_workingDirectoryPath); var error = CreateAssetModules(moduleDirectoryList, options.AssetPackConfig, workingDirectory); if (error != null) { return(error); } IList <string> bundleMetadata; error = CreateBaseModules(moduleDirectoryList, options, workingDirectory, out bundleMetadata); if (error != null) { return(error); } error = CreateBundle(moduleDirectoryList, options, bundleMetadata); if (error != null) { return(error); } Debug.LogFormat("Finished building app bundle: {0}", options.AabFilePath); _finishedAabFilePath = options.AabFilePath; _buildStatus = BuildStatus.Succeeding; return(null); }
private BundletoolHelper.BuildBundleConfigParams CreateBuildBundleConfigParams(CreateBundleOptions options) { var configParams = new BundletoolHelper.BuildBundleConfigParams { defaultTcfSuffix = TextureTargetingTools.GetBundleToolTextureCompressionFormatName( options.AssetPackConfig.DefaultTextureCompressionFormat), minSdkVersion = _minSdkVersion, compressionOptions = options.CompressionOptions ?? new CompressionOptions(), containsInstallTimeAssetPack = options.AssetPackConfig.SplitBaseModuleAssets }; var assetPacks = options.AssetPackConfig.DeliveredAssetPacks; foreach (var entry in assetPacks) { var assetPackName = entry.Key; var assetPack = entry.Value; configParams.enableTcfTargeting |= assetPack.CompressionFormatToAssetBundleFilePath != null; configParams.enableTcfTargeting |= assetPack.CompressionFormatToAssetPackDirectoryPath != null; configParams.containsInstallTimeAssetPack |= assetPack.DeliveryMode == AssetPackDeliveryMode.InstallTime; } configParams.containsInstallTimeAssetPack |= options.AssetPackConfig.SplitBaseModuleAssets; return(configParams); }
private string CreateBundle(List <DirectoryInfo> moduleDirectoryList, CreateBundleOptions options, IList <string> bundleMetadata = null) { // Create a ZIP file for each module directory. var moduleFiles = new List <string>(); var numModules = moduleDirectoryList.Count; for (var i = 0; i < numModules; i++) { if (numModules == 1) { DisplayProgress("Processing base module", ProgressProcessModules); } else { DisplayProgress( string.Format("Processing module {0} of {1}", i + 1, numModules), Mathf.Lerp(ProgressProcessModules, ProgressRunBundletool, (float)i / numModules)); } var moduleDirectoryInfo = moduleDirectoryList[i]; var destinationDirectoryInfo = GetDestinationSubdirectory(moduleDirectoryInfo); // Create ZIP file path, for example /path/to/files/base becomes /path/to/files/base/base.zip var zipFilePath = Path.Combine(moduleDirectoryInfo.FullName, moduleDirectoryInfo.Name + ".zip"); var zipErrorMessage = _zipUtils.CreateZipFile(zipFilePath, destinationDirectoryInfo.FullName, "."); if (zipErrorMessage != null) { return(DisplayBuildError("Zip creation", zipErrorMessage)); } moduleFiles.Add(zipFilePath); } if (bundleMetadata == null) { bundleMetadata = new List <string>(); } DisplayProgress("Running bundletool", ProgressRunBundletool); var configParams = CreateBuildBundleConfigParams(options); var buildBundleErrorMessage = _bundletool.BuildBundle(options.AabFilePath, moduleFiles, bundleMetadata, configParams); if (buildBundleErrorMessage != null) { return(DisplayBuildError("Bundletool", buildBundleErrorMessage)); } // Only sign the .aab if a custom keystore is configured. if (_jarSigner.UseCustomKeystore) { DisplayProgress("Signing bundle", 0.9f); var signingErrorMessage = _jarSigner.Sign(options.AabFilePath); if (signingErrorMessage != null) { Debug.LogError("Failed to sign"); return(DisplayBuildError("Signing", signingErrorMessage)); } } else { Debug.LogFormat("Skipped signing since a Custom Keystore isn't configured in Android Player Settings"); } MoveSymbolsZipFile(options.AabFilePath); return(null); }