Skip to content

Commit d7332f0

Browse files
author
game-workstore-bot
committed
Package Update 1.9.0
1 parent 3963dbb commit d7332f0

25 files changed

+985
-41
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog for com.google.android.appbundle
22

3+
## [1.9.0] - 2023-03-10
4+
### New Features
5+
- Added support for device tier targeting of assets
6+
- Updated bundletool-all.jar from 1.8.2 to 1.14.0
7+
38
## [1.8.0] - 2022-07-06
49
### Bug Fixes
510
- Fixed issue #172: Unity Cloud Build failure if Android SDK 30+ is not installed

Editor/Scripts/AssetBundleBuilder.cs

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,115 @@ public static Dictionary<string, Dictionary<TextureCompressionFormat, string>> B
117117
outputPath, builds, assetBundleOptions, baseTextureFormat, textureSubtargets);
118118
}
119119

120+
/// <summary>
121+
/// Run one or more AssetBundle builds for the specified device tiers.
122+
/// Notes about the <see cref="outputPath"/> parameter:
123+
/// - If a relative path is provided, the file paths in the returned AssetPackConfig will be relative paths.
124+
/// - If an absolute path is provided, the file paths in the returned object will be absolute paths.
125+
/// - AssetBundle builds for device tiers will be created in siblings of this directory. For
126+
/// example, for outputDirectory "a/b/c" and device tier HIGH, there will be a directory "a/b/c#tier_high".
127+
/// - If allowClearDirectory is false, this directory and any sibling directories must be empty or not exist,
128+
/// otherwise an exception is thrown.
129+
/// </summary>
130+
/// <param name="outputPath">The output directory for AssetBundles. See other notes above.</param>
131+
/// <param name="deliveryMode">A delivery mode to apply to every asset pack in the generated config.</param>
132+
/// <param name="deviceTierToBuilds">A dictionary from Device Tier to asset bundle builds. All device tiers
133+
/// should contains the same asset bundle names.</param>
134+
/// <param name="defaultDeviceTier">
135+
/// Default device tier to be used for standalone APKs. Set to zero if not specified.</param>
136+
/// <param name="assetBundleOptions">Options to pass to <see cref="BuildPipeline"/>.</param>
137+
/// <param name="allowClearDirectory">Allows this method to clear the contents of the output directory.</param>
138+
/// <returns>An <see cref="AssetPackConfig"/> containing file paths to all generated AssetBundles.</returns>
139+
public static AssetPackConfig BuildAssetBundlesDeviceTier(
140+
string outputPath,
141+
AssetPackDeliveryMode deliveryMode,
142+
Dictionary<DeviceTier, AssetBundleBuild[]> deviceTierToBuilds,
143+
DeviceTier defaultDeviceTier = null,
144+
BuildAssetBundleOptions assetBundleOptions = BuildAssetBundleOptions.UncompressedAssetBundle,
145+
bool allowClearDirectory = false)
146+
{
147+
if (defaultDeviceTier == null)
148+
{
149+
defaultDeviceTier = DeviceTier.From(0);
150+
}
151+
152+
if (!deviceTierToBuilds.Keys.Contains(defaultDeviceTier))
153+
{
154+
throw new ArgumentException("Default device tier not present in deviceTierToBuilds.");
155+
}
156+
157+
var nameToDeviceTierToPath = BuildAssetBundlesDeviceTier(outputPath, deviceTierToBuilds,
158+
assetBundleOptions, allowClearDirectory);
159+
var assetPackConfig = new AssetPackConfig();
160+
foreach (var deviceTierToPath in nameToDeviceTierToPath.Values)
161+
{
162+
assetPackConfig.AddAssetBundles(deviceTierToPath, deliveryMode);
163+
}
164+
165+
assetPackConfig.DefaultDeviceTier = defaultDeviceTier;
166+
return assetPackConfig;
167+
}
168+
169+
/// <summary>
170+
/// Run one or more AssetBundle builds for each device tier.
171+
/// </summary>
172+
/// <param name="outputPath">The output directory for base AssetBundles. See the other method for notes.</param>
173+
/// <param name="deviceTierToBuilds">A dictionary from Device Tier to asset bundle builds. All device tiers
174+
/// should contains the same asset bundle names.</param>
175+
/// <param name="assetBundleOptions">Options to pass to <see cref="BuildPipeline"/>.</param>
176+
/// <param name="allowClearDirectory">Allows this method to clear the contents of the output directory.</param>
177+
/// <returns>A dictionary from AssetBundle name to DeviceTier to file outputPath.</returns>
178+
public static Dictionary<string, Dictionary<DeviceTier, string>> BuildAssetBundlesDeviceTier(
179+
string outputPath, Dictionary<DeviceTier, AssetBundleBuild[]> deviceTierToBuilds,
180+
BuildAssetBundleOptions assetBundleOptions,
181+
bool allowClearDirectory)
182+
{
183+
if (deviceTierToBuilds == null || deviceTierToBuilds.Count == 0)
184+
{
185+
throw new ArgumentException("DeviceTierToBuild parameter cannot be null or empty");
186+
}
187+
188+
if (deviceTierToBuilds.Values.Any(builds => builds == null || builds.Length == 0))
189+
{
190+
throw new ArgumentException("AssetBundleBuilds value cannot be null or empty");
191+
}
192+
193+
var assetBundleNames = deviceTierToBuilds.Values.First().Select(build => build.assetBundleName).ToList();
194+
195+
if (deviceTierToBuilds.Values.Any(builds =>
196+
!(builds.Length == assetBundleNames.Count() &&
197+
builds.Select(build => build.assetBundleName).Except(assetBundleNames).ToList().Count == 0)))
198+
{
199+
throw new ArgumentException("AssetBundleBuild names cannot differ across device tiers.");
200+
}
201+
202+
foreach (var assetBundleName in assetBundleNames)
203+
{
204+
if (!AndroidAppBundle.IsValidModuleName(assetBundleName))
205+
{
206+
throw new ArgumentException("Invalid AssetBundle name: " + assetBundleName);
207+
}
208+
}
209+
210+
if (string.IsNullOrEmpty(outputPath))
211+
{
212+
throw new ArgumentNullException("outputPath");
213+
}
214+
215+
CheckDirectory(outputPath, allowClearDirectory);
216+
217+
var tiers = new HashSet<DeviceTier>(deviceTierToBuilds.Keys);
218+
var paths = tiers.Select(tier => outputPath + DeviceTierTargetingTools.GetTargetingSuffix(tier));
219+
foreach (var path in paths)
220+
{
221+
CheckDirectory(path, allowClearDirectory);
222+
}
223+
224+
return BuildAssetBundlesDeviceTierInternal(
225+
outputPath, assetBundleOptions, deviceTierToBuilds, assetBundleNames);
226+
}
227+
228+
120229
// The internal method assumes all parameter preconditions have already been checked.
121230
private static Dictionary<string, Dictionary<TextureCompressionFormat, string>> BuildAssetBundlesInternal(
122231
string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions,
@@ -157,6 +266,45 @@ private static Dictionary<string, Dictionary<TextureCompressionFormat, string>>
157266
}
158267
}
159268

269+
private static Dictionary<string, Dictionary<DeviceTier, string>> BuildAssetBundlesDeviceTierInternal(
270+
string outputPath, BuildAssetBundleOptions assetBundleOptions,
271+
Dictionary<DeviceTier, AssetBundleBuild[]> deviceTierToBuilds, IEnumerable<string> assetBundleNames)
272+
{
273+
// Use a dictionary to capture the generated AssetBundles' file names.
274+
var nameToDeviceTierToPath = assetBundleNames.ToDictionary(
275+
bundleName => bundleName, _ => new Dictionary<DeviceTier, string>());
276+
foreach (var deviceTier in deviceTierToBuilds.Keys)
277+
{
278+
var tierBuilds = deviceTierToBuilds[deviceTier];
279+
// Build AssetBundles in the the base format's directory.
280+
BuildAssetBundles(outputPath, tierBuilds, assetBundleOptions);
281+
282+
// Then move the files to a new directory with the device tier suffix.
283+
var outputPathWithSuffix = outputPath + DeviceTierTargetingTools.GetTargetingSuffix(deviceTier);
284+
Directory.Move(outputPath, outputPathWithSuffix);
285+
286+
UpdateDictionaryDeviceTier(nameToDeviceTierToPath, outputPathWithSuffix, deviceTier);
287+
}
288+
289+
return nameToDeviceTierToPath;
290+
}
291+
292+
private static void UpdateDictionaryDeviceTier(
293+
Dictionary<string, Dictionary<DeviceTier, string>> nameToDeviceTierToPath,
294+
string outputPath, DeviceTier deviceTier)
295+
{
296+
foreach (var entry in nameToDeviceTierToPath)
297+
{
298+
var filePath = Path.Combine(outputPath, entry.Key);
299+
entry.Value[deviceTier] = filePath;
300+
if (!File.Exists(filePath))
301+
{
302+
throw new InvalidOperationException(string.Format("Missing AssetBundle file: " + filePath));
303+
}
304+
}
305+
}
306+
307+
160308
private static void BuildAssetBundles(
161309
string outputPath, AssetBundleBuild[] builds, BuildAssetBundleOptions assetBundleOptions)
162310
{
@@ -226,4 +374,4 @@ private static void CheckDirectory(string path, bool allowClearDirectory)
226374
directoryInfo.Delete( /* recursive= */ true);
227375
}
228376
}
229-
}
377+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Collections.Generic;
17+
18+
namespace Google.Android.AppBundle.Editor
19+
{
20+
/// <summary>
21+
/// Options that configure the behavior of an asset-only app bundle build.
22+
/// </summary>
23+
public class AssetOnlyBuildOptions
24+
{
25+
/// <summary>
26+
/// Constructor.
27+
/// </summary>
28+
/// <param name="assetPackConfig">AssetPackConfig specifying which asset packs to include in the build.</param>>
29+
/// <exception cref="ArgumentException">Thrown if the AssetPackConfig contains install-time packs.</exception>
30+
public AssetOnlyBuildOptions(AssetPackConfig assetPackConfig)
31+
{
32+
foreach (var keyValue in assetPackConfig.AssetPacks)
33+
{
34+
var deliveryMode = keyValue.Value.DeliveryMode;
35+
if (deliveryMode == AssetPackDeliveryMode.InstallTime)
36+
{
37+
throw new ArgumentException(
38+
"AssetPackConfig contains install-time asset packs which are not supported in asset-only app bundles.");
39+
}
40+
}
41+
42+
AssetPackConfig = assetPackConfig;
43+
}
44+
45+
/// <summary>
46+
/// Returns the AssetPackConfig to use for the build, or null.
47+
/// </summary>
48+
public AssetPackConfig AssetPackConfig { get; private set; }
49+
50+
/// <summary>
51+
/// The version codes identifying which app versions should be served these asset packs.
52+
/// </summary>
53+
public IList<long> AppVersions { get; set; }
54+
55+
/// <summary>
56+
/// A string that uniquely identifies this asset-only bundle.
57+
/// </summary>
58+
public string AssetVersionTag { get; set; }
59+
60+
/// <summary>
61+
/// The path where the asset only bundle will be built.
62+
/// </summary>
63+
public string LocationPathName { get; set; }
64+
65+
/// <summary>
66+
/// If true, forces the entire build to run on the main thread, potentially freezing the Editor UI during some
67+
/// build steps. This setting doesn't affect batch mode builds, which always run on the main thread.
68+
/// </summary>
69+
public bool ForceSingleThreadedBuild { get; set; }
70+
}
71+
}

Editor/Scripts/AssetOnlyBuildOptions.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)