TIL: Creating AssetBundles from the command line

I saw a few post of people asking about building asset bundles from the command line with Unity. I needed to do this because I have a large number of Unity project that reference each other’s scripts through the package manager, but the assets (scenes, prefabs, etc) are not included in the packages. So, if I want to rebuild all of the asset bundles for every project, I have to open each project and build bundles there. I have about 20 project like this, so this get very tedious. I also can’t use an editor script alone to do this because the assets (and their metadata) are in different projects.

Fortunately, Unity has a cli batch mode, which allows us to run Unity from the command line and do some basic things. Unity - Manual: Unity Editor command line arguments
In particular, using -projectPath, -batchmode, and -executeMethod lets me launch Unity from the command line and execute a method of my choice. In turn, I can create a new class and method specifically for building asset bundles.

public class AssetBundlesBuilder
{
    public static void BuildBundles()
    {
        string[] args = Environment.GetCommandLineArgs();
        string path = "";
        string target = "";
        for (int i = 0; i < args.Length; i++)
        {
            if(args[i] == "-path")
            {
                path = args[i + 1];
            }
            if(args[i] == "-target")
            {
                target = args[i + 1];
            }
        }
        path += "/assetbundles";
        Directory.CreateDirectory(path + "/windows");
        Directory.CreateDirectory(path + "/android");
        Directory.CreateDirectory(path + "/ios");

        if (target == "all" || target == "")
        {
            BuildPipeline.BuildAssetBundles(path + "/windows", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);
            BuildPipeline.BuildAssetBundles(path + "/android", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
            BuildPipeline.BuildAssetBundles(path + "/ios", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.iOS);
        }
        else if (target == "windows")
        {
            BuildPipeline.BuildAssetBundles(path + "/windows", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);
        }
        else if (target == "android")
        {
            BuildPipeline.BuildAssetBundles(path + "/android", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
        }
        else if (target == "ios")
        {
            BuildPipeline.BuildAssetBundles(path + "/ios", BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.iOS);
        }
        else
        {
            throw new Exception("Invalid Build Target");
        }

        if (Application.isBatchMode)
        {
            EditorApplication.Exit(0);
        }
    }
}

This is the code for building asset bundles for the 3 platforms I support. It needs to exist in an Editor folder in each project that needs to build bundles. I use chunk-based compression, but that isn’t required in general. The code above looks for a couple command line arguments: -path and -target. -path specifies an output path for the finished bundles. -target is expected to be one of “windows”, “android”, “ios”, or “all” and determines which platform to build for. If -target isn’t supplied, it will default to building bundles for all platforms.

To get bundles from the command line, I call it like so:
"<path-to-unity>Unity.exe" -projectPath "<path>" -batchmode -executeMethod AssetBundlesBuilder.BuildBundles -path "<outputPath>" -target all
That line, combined with the AssetBundlesBuilder, makes all of the bundles for 1 project.
-nographics seemed to make this not work, and I don’t know why. I’m guessing that the building process needs graphics for building shaders and such, not sure. Likewise, including -quit did not seem to be needed. Not including both of those works fine.

Now I said I have about 20 projects that need this done, and at this point we’ve solved it for one project. All of my projects are fortunately located in the same folder, like so

ParentFolder
--Project1Root
----Assets
----...
--Project2Root
----Assets
----...
--...

So, a little batch script later and now I can build all bundles for all project, automatically, without the worry that I might lose track of where I was or accidentally skip over a project, or just one project for one platform.

Here’s the batch file:

@echo off

echo "Building bundles to %cd%\Bundles"
for /d %%i in (*) do (
  if exist "%%i\Assets" (
    echo %%~dpni
    start "" /wait "C:\Program Files\Unity\Hub\Editor\2021.3.19f1\Editor\Unity.exe" -projectPath "%%~dpni" -batchmode -executeMethod AssetBundlesBuilder.BuildBundles -path "%cd%\Bundles"
  )
)

pause

cmd uses some truly arcane syntax, but I was able to piece that together. This batch file is placed in the parent folder, beside the root folders for the projects. The script only builds the bundles one project at a time because starting 20 instances of Unity at the same time and telling them all to build bundles simultaneously would make my computer very sad.

Hope someone finds this useful. Thank you for coming to my Ted Talk.

@WallaceT_MFM in case you need to call methods that take in arguments (instead of reading them yourself), check out my (free) GitHub project UCmd.

Also, available on the asset store.