기술 자료

Unity Engine


User Manual

Script Reference

Unity Engine


Load content directories

Register a content directory at runtime and access its assets
읽는 시간 6분최근 업데이트: 16시간 전

Each call to
BuildPipeline.BuildContentDirectory
populates the specified output directory with the built content from one or more root assets.
At runtime, a script must call
ContentLoadManager.RegisterContentDirectory
once per content directory to make its content available:
ContentDirectoryHandle handle = ContentLoadManager.RegisterContentDirectory(localPath);
This loads the build manifest for the content directory to populate in-memory data structures. Root assets from the registered content directory become available through the
ContentLoadManager
APIs.
After registering a content directory, you can call
ContentLoadManager.GetRootAssets
to discover what root assets are available inside it.
GetRootAssets<T>
returns the root assets of type
T
from every registered content directory, not only from the most recently registered one. This is how code in a Player build reaches content in a content directory, and how content in one content directory build reaches content in another. To query a single content directory instead, pass the
ContentDirectoryHandle
that
RegisterContentDirectory
returned.
When attempting to load an asset or scene, Unity searches through the loaded content directories in reverse order of their registration, meaning the last registered is the first searched, as in a stack.

Load content directories built outside the Assets folder

If you build content directories into
Assets/StreamingAssets
, Unity imports every file that the content build produces. For a large content build, this wastes time and disk space each time Unity imports the project. To avoid this, build the content directories to a folder outside the
Assets
folder and copy them into the Player build instead. The following example builds into
Builds/ContentDirectories
.
The example has two parts:
  • A runtime helper class that registers content directories by name, in both Play mode and a Player build.
  • An Editor build callback that copies the content directories into the Player build.
The following sections describe the runtime class first, then the Editor build callback that enables it in a Player. The Web platform needs extra handling in both parts. For more information, refer to Preload content directories for the Web platform.

Register content directories by name

The following class registers content directories by name and tracks their handles for cleanup. In Play mode it reads from the build output location. In a Player it reads from the
StreamingAssets
folder, where the build callback copied them. On the Web platform, preloaded files are in the Emscripten virtual file system at
/vfs_streamingassets
.
// Registers content directories by name and unregisters them on shutdown. public class ContentDirectoryManager { // Build output location for the content directories, relative to the // project folder. It's outside the Assets folder, so Unity doesn't // import the built content. public const string ContentBuildsPath = "Builds/ContentDirectories"; readonly List<ContentDirectoryHandle> m_Handles = new List<ContentDirectoryHandle>(); // During Play mode the content directories are read from the build // output location. In a Player they're read from the StreamingAssets // folder, where the Player build copied them. static string contentRootPath { get {#if UNITY_EDITOR return ContentBuildsPath;#elif UNITY_WEBGL // Preloaded StreamingAssets files are in the Emscripten virtual // file system at this fixed path. return "/vfs_streamingassets";#else return Application.streamingAssetsPath;#endif } } public void Register(string directoryName) { string path = contentRootPath + "/" + directoryName; m_Handles.Add(ContentLoadManager.RegisterContentDirectory(path)); } public void UnregisterAll() { for (int i = m_Handles.Count - 1; i >= 0; i--) { ContentLoadManager.UnregisterContentDirectory(m_Handles[i]); } m_Handles.Clear(); } }
Register each content directory by name from a bootstrap scene:
ContentDirectoryManager contentDirectories = new ContentDirectoryManager();contentDirectories.Register("MyContentDirectory");
Call
UnregisterAll
on shutdown, after each asset is released and each scene from the content directories is unloaded.

Copy the content directories into the Player build

BuildPlayerProcessor.PrepareForBuild
runs before a Player build. The following build callback uses it to add the content directories to the build with
BuildPlayerContext.AddAdditionalPathToStreamingAssets
, which copies files into the
StreamingAssets
folder of the Player without importing them into the project. For a Web build, it also writes the preload manifest.
// Copies the built content directories into the Player build. class ContentDirectoryDeployment : BuildPlayerProcessor { // A Web build preloads the files listed by every manifest in this // folder into its virtual file system. const string k_WebPreloadFolder = "Library/PlayerDataCache/WebGLPreloadedStreamingAssets"; const string k_WebPreloadManifest = k_WebPreloadFolder + "/content-directories.manifest"; public override void PrepareForBuild( BuildPlayerContext buildPlayerContext) { string buildsPath = ContentDirectoryManager.ContentBuildsPath; // Skip if no content directories exist. This allows other builds // in the same project to proceed without content directories. if (!Directory.Exists(buildsPath)) return; string[] directories = Directory.GetDirectories(buildsPath); if (directories.Length == 0) return; // Unity copies the contents of buildsPath into the root of the // StreamingAssets folder, so each content directory keeps its own // folder name. buildPlayerContext.AddAdditionalPathToStreamingAssets(buildsPath); // Preserve the types used by the content so that managed code // stripping does not remove them. foreach (string directory in directories) { if (BuildHistory.TryGetBuildSummaryForOutputPath( directory, out BuildReportSummary summary)) { if (BuildHistory.TryGetBuildReportDirectory( summary.BuildSessionGUID, out string reportDirectory)) { buildPlayerContext.AddPreviousBuildReportDirectory( reportDirectory); } } } if (buildPlayerContext.BuildPlayerOptions.target == BuildTarget.WebGL) { WriteWebPreloadManifest(buildsPath, directories); } else if (File.Exists(k_WebPreloadManifest)) { // Remove the manifest from an earlier Web build, so that it // can't preload files in a later one. File.Delete(k_WebPreloadManifest); } } // The Web platform serves the StreamingAssets folder over HTTP, which // a browser can't read synchronously. RegisterContentDirectory needs // synchronous access, so list each file for the build to preload. static void WriteWebPreloadManifest(string buildsPath, string[] directories) { Directory.CreateDirectory(k_WebPreloadFolder); using (StreamWriter writer = new StreamWriter(k_WebPreloadManifest, false)) { foreach (string directory in directories) { string[] files = Directory.GetFiles( directory, "*", SearchOption.AllDirectories); string directoryName = Path.GetFileName(directory); foreach (string file in files) { string relativePath = directoryName + "/" + Path.GetRelativePath(directory, file); writer.WriteLine(relativePath.Replace('\\', '/')); } } } } }
Because
AddAdditionalPathToStreamingAssets
copies the contents of the folder you pass it, each content directory keeps its own folder name at the root of
StreamingAssets
. Build the content directories before you build the Player, so that the callback finds them.
The example also looks up each content directory's build history folder using
BuildHistory.TryGetBuildSummaryForOutputPath
and passes it to
AddPreviousBuildReportDirectory
, which preserves the types used by the content during managed code stripping. For more information, refer to How code stripping affects content.

Preload content directories for the Web platform

RegisterContentDirectory
requires synchronous file access, and a browser can't read from the network synchronously. A Web build instead preloads specific files from the
StreamingAssets
folder into its virtual file system, which makes them available synchronously at runtime.
To select the files to preload, write a manifest file with the
.manifest
extension to
Library/PlayerDataCache/WebGLPreloadedStreamingAssets
, with one path per line relative to the
StreamingAssets
folder. The build reads every manifest in that folder, so several packages can each contribute one. The
WriteWebPreloadManifest
method in the previous example lists every file in every content directory.
Write the manifest from
PrepareForBuild
, as the previous example does, so that the Player build finds it. A build callback that runs after the build, such as
IPostprocessBuildWithReport
, is too late, because a Web build decides whether to pack each file into its virtual file system while it assembles the build.
중요
Library/PlayerDataCache
is an internal Editor build cache, and this manifest location isn't a supported API. Also delete the manifest when you no longer need the files preloaded, because a stale manifest keeps files in the virtual file system.

Unload a content directory

To clean up resources, call
ContentLoadManager.UnregisterContentDirectory
once per content directory after
Loadable.Release
has been called on each loaded asset, and after each scene has been unloaded (for example, via
SceneManager.UnloadSceneAsync
). Unity logs an error if
UnregisterContentDirectory
is called while any files are open.

Additional resources