Unity5打包assetbundle

Unity5打包assetbundle

using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public class AssetBundleExporterGUI
{
    private static readonly string BUNDLE_PATH_ART = System.Environment.CurrentDirectory +
		"/../../../../../starts-art/Assetbundles/";
    private static readonly string BUNDLE_PATH_GAME = System.Environment.CurrentDirectory +
        "/../../../../../starts-game-assets/trunk/assetbundles/";
    
    private const string IOS_BUNDLE_PATH = "ios/";
    private const string ANDROID_BUNDLE_PATH = "android/";
    private const string WEBPLAYER_BUNDLE_PATH = "webplayer/";
    
    private const string ASSETBUNDLE_EXT = ".assetbundle";
    
    private const string PREFAB_PATH = "Assets/_prefabs/{0}.prefab";
    
    // This is our one-and-only dependency bundle. Any downloaded bundle can reference this,
    // which means any assets within it won't be duplicated in any dependent bundle.
    private static string PREFAB_EXT = ".prefab";
    private static string SHARED_PREFAB = "gui_shared";
    private static string SHARED_PREFAB_PATH = "Assets/_prefabs/" + SHARED_PREFAB;

    private const string SHARED_BUNDLE = "gui_shared";
    
    // These are the bundles that do not have any dependency. These bundles are intended to be
    // loaded on-demand on the client because they can contain textures that we do not want to
    // have always loaded in memory.
    //
    // IMPORTANT: None of these bundles should be in GUI_PRELOADED_SCREENS in AssetConstants.cs
    // located in the starts client codebase. If you are adding a new independent bundle, please
    // ensure this or communicate this to the dev implementing it.
    //
    // Bundles come in two categories:
    //   1. always-loaded, does not contain its own textures, depends on gui_shared
    //   2. loaded on-demand, does not depend on gui_shared
    // All of the following are true:
    //   "If a bundle is always loaded, then it's dependent on gui_shared"
    //   "If a bundle is not always loaded, then it's not dependent on gui_shared"
    //   "If a bundle is dependent on gui_shared, then it's always loaded"
    //   "If a bundle is not dependent on gui_shared, then it's not always loaded"
    // We have 1 exception:
    //   gui_hud depends on gui_shared and also has a few textures
    //
    private static readonly string[] independentBundles = new string[]
    {
        // The shared bundle doesn't depend on itself.
        SHARED_BUNDLE,
        
        "gui_xxxxxxxxx",
        
    };
    
    private const string HUD_BUNDLE = "gui_hud";
    
    private static string selectedPath;
    
    [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - Android", false, 1)]
    public static void ExportSelectionAndroid()
    {
        ExportSelectionTarget(BuildTarget.Android);
    }
    
    [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - iOS", false, 2)]
    public static void ExportSelectionIOS()
    {
        ExportSelectionTarget(BuildTarget.iOS);
    }
    
    [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - WebPlayer", false, 3)]
    public static void ExportSelectionWebPlayer()
    {
        ExportSelectionTarget(BuildTarget.WebPlayer);
    }
    
    // Useful for when you only want to export to a single target and no others.
    private static void ExportSelectionTarget(BuildTarget target)
    {
        if (!Start())
        {
            return;
        }
        
        /*UnityEngine.Object[] prefabs;
        List<string> dependencies;
        if (!GetSelectedPrefabs(out prefabs, out dependencies))
        {
            return;
        }*/
        UnityEngine.Object[] prefabs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);

        if (!ExportPrefabs(prefabs, target))
        {
            return;
        }
        
        Success();
    }
    
    // Useful for when you want all targets.  It makes sure to order the targets smartly.
    [MenuItem("Assets/StaRTS/Build Selected AssetBundle(s) - All Platforms", false, 4)]
    public static void ExportSelectionAll()
    {
        if (!Start())
        {
            return;
        }
        
        /*UnityEngine.Object[] prefabs;
        List<string> dependencies;
        if (!GetSelectedPrefabs(out prefabs, out dependencies))
        {
            return;
        }*/
        
        List<BuildTarget> targets = new List<BuildTarget>();
        targets.Add(BuildTarget.Android);
        targets.Add(BuildTarget.iOS);
        targets.Add(BuildTarget.WebPlayer);
        
        // Ensure that the current build target is the first target in the
        // list to minimize the amount of asset re-importing that is done.
        // Whichever was used last will be used first in the subsequent export
        for (int i = 0; i < targets.Count; i++)
        {
            if (targets[i] == EditorUserBuildSettings.activeBuildTarget)
            {
                if (i != 0)
                {
                    targets.Insert(0, targets[i]);
                    targets.RemoveAt(i + 1);
                }
                break;
            }
        }

        UnityEngine.Object[] prefabs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);

        for (int i = 0; i < targets.Count; i++)
        {
            if (!ExportPrefabs(prefabs, targets[i]))
            {
                return;
            }
        }
        
        Success();
    }
    
    static private bool GetSelectedPrefabs(out UnityEngine.Object[] prefabs, out List<string> dependencies)
    {
        dependencies = new List<string>();
        
        // Begin() already ensured this was non-empty.
        UnityEngine.Object[] selection = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
        
        // Store prefab objects in a new array for multiple target
        // exports. When the editor re-imports assets for a new target,
        // the selection is lost.
        prefabs = new UnityEngine.Object[selection.Length];
        for (int i = 0; i < selection.Length; i++)
        {
            string bundleName = selection[i].name;
            
            
            List<string> deps = new List<string>();
            deps.Add(SHARED_BUNDLE);
            for (int j = 0, jlen = independentBundles.Length; j < jlen; j++)
            {
                if (bundleName == independentBundles[j])
                {
                    deps.Clear();
                    break;
                }
            }
            
            if (i == 0)
            {
                dependencies.AddRange(deps);
            }
            else
            {
                bool matches = deps.Count == dependencies.Count;
                if (matches)
                {
                    for (int j = 0; j < deps.Count; j++)
                    {
                        if (dependencies[j].IndexOf(deps[j]) < 0)
                        {
                            matches = false;
                            break;
                        }
                    }
                }

                if (!matches)
                {
                    // We require that all bundles to be built have the same dependencies.
                    Error("The selected bundles don't have the same dependencies.\n" +
                          "Try building self-contained bundles separately " +
                          "from those that depend on the shared bundle.");
                    return false;
                }
            }
            
            prefabs[i] = selection[i];
        }
        
        return true;
    }
    
    private static bool ExportPrefabs(
        UnityEngine.Object[] prefabs, BuildTarget target)
    {
        Debug.Log("Exporting bundles for " + target);
        
        EditorUserBuildSettings.SwitchActiveBuildTarget(target);
        SetPathAndExportBundle(prefabs, target);
        return true;
    }
    
    // Returns true if the given prefab has no textures of its own,
    // outside of the given dependency prefab.
    // If returns false, assetNames will be set to a newline-separated list of offending assets.
    private static bool IsValidDependency(UnityEngine.Object prefab, UnityEngine.Object dependencyPrefab,
                                          out string assetNames)
    {
        bool valid = true;
        assetNames = null;
        
        string[] prefabPaths = new string[] { string.Format(PREFAB_PATH, prefab.name) };
        string[] prefabAssets = AssetDatabase.GetDependencies(prefabPaths);
        
        string[] dependencyPaths = new string[]
        { string.Format(PREFAB_PATH, dependencyPrefab.name) };
        string[] dependencyAssets = AssetDatabase.GetDependencies(dependencyPaths);
        
        // If everything in the prefab is also in the dependency bundle, then none of it will
        // actually get bundled with the prefab, and that's the goal.
        for (int i = 0, iCount = prefabAssets.Length; i < iCount; i++)
        {
            string assetName = prefabAssets[i];
            
            // These are the legal asset types.  Anything else is considered illegal to have in an
            // depdendent bundle that isn't also inside the depdendency bundle.
            // NOTE: Mainly we want to check .png, .ttf, .prefab, .shader, but rather than only
            // checking those, it's safer to do the reverse: allow known legal assets to be skipped.
            // That way, any new type of asset that we find will not be skipped and either it's a
            // proper dependency, or it'll cause the error to pop, and we'll consider what to do
            // about it.  Either fix the asset, or add the new extension to our "legal" list.
            if (assetName == prefabPaths[0] || // Ignore the root object.
                assetName.EndsWith(".cs") ||   // Scripts only have references bundled.
                assetName.EndsWith(".mat") ||  // Materials are lightweight, they reference shaders
                // and textures, which themselves are prevented.
                assetName.EndsWith(".controller") ||
                assetName.EndsWith(".anim") ||
                assetName.EndsWith(".fbx"))
            {
                continue;
            }
            
            bool found = false;
            for (int j = 0, jCount = dependencyAssets.Length; j < jCount; j++)
            {
                if (assetName == dependencyAssets[j])
                {
                    found = true;
                    break;
                }
            }
            
            if (!found)
            {
                valid = false;
                assetNames = assetNames == null ? assetName : assetNames + "\n" + assetName;
            }
        }
        
        return valid;
    }
    
    private static bool Start()
    {
        UnityEngine.Object[] selection = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);
        if (selection.Length < 1)
        {
            Debug.Log("No prefabs were selected to bundle!");
            return false;
        }
        
        return AskForExportPath();
    }
    
    private static void Success()
    {
		EditorUtility.DisplayDialog("Export complete!", string.Empty , "OK", string.Empty );
    }
    
    private static void Error(string error)
    {
        Debug.LogError(error);
		EditorUtility.DisplayDialog("Error", error, "OK", string.Empty);
    }
    
    private static bool AskForExportPath()
    {
        int option = EditorUtility.DisplayDialogComplex(
            "Where would you like the bundles saved?",
            "Choose starts-art to export the bundle for an engineer to grab " +
            "for integration. Choose starts-game-assets to test the bundle " +
            "locally and potentially commit to production.",
            "starts-art",
            "Other",
            "starts-game-assets");
        
		string baseDirectory = string.Empty ;
        
        switch (option)
        {
        case 0:
            baseDirectory = BUNDLE_PATH_ART;
            break;
        case 1:
            baseDirectory = EditorUtility.OpenFolderPanel(
				"Select the base export directory", string.Empty , string.Empty) + "/";
            break;
        case 2:
            baseDirectory = BUNDLE_PATH_GAME;
            break;
        default:
            Debug.Log("Invalid selection for export."); // Shouldn't be possible.
            return false;
        }
        
        // Verify path exists
        if (baseDirectory == string.Empty || !Directory.Exists(baseDirectory))
        {
            Error("Base directory does not exist: " + baseDirectory);
            return false;
        }
        
        selectedPath = baseDirectory;
        
        // Create subdirectories if they do not exist
        if (!Directory.Exists(baseDirectory + ANDROID_BUNDLE_PATH))
        {
            Directory.CreateDirectory(baseDirectory + ANDROID_BUNDLE_PATH);
        }

        if (!Directory.Exists(baseDirectory + IOS_BUNDLE_PATH))
        {
            Directory.CreateDirectory(baseDirectory + IOS_BUNDLE_PATH);
        }

        if (!Directory.Exists(baseDirectory + WEBPLAYER_BUNDLE_PATH))
        {
            Directory.CreateDirectory(baseDirectory + WEBPLAYER_BUNDLE_PATH);
        }
        
        return true;
    }

    private static void SetPathAndExportBundle(UnityEngine.Object[] prefabs, BuildTarget target)
    {
        string path = selectedPath;
        
        switch (target)
        {
        case BuildTarget.iOS:
            path += IOS_BUNDLE_PATH;
            break;
            
        case BuildTarget.Android:
            path += ANDROID_BUNDLE_PATH;
            break;
            
        case BuildTarget.WebPlayer:
            path += WEBPLAYER_BUNDLE_PATH;
            break;
        }

        ExportBundle(prefabs, path, target, false);
    }

    static private bool ExportBundle(UnityEngine.Object[] prefab, string path, BuildTarget target, bool combined)
    {
        string directoryPath = Path.GetDirectoryName(path);
        if (!Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
        }
        
        AssetBundleBuild[] buildMap;
        List<UnityEngine.Object> independentBundles = new List<UnityEngine.Object>();
        string prefabPath;
        if (combined)
        {
            buildMap = new AssetBundleBuild[2];
            
            buildMap[0].assetBundleName = SHARED_PREFAB + ASSETBUNDLE_EXT;
            buildMap[0].assetNames = AssetDatabase.GetDependencies(new string[]{SHARED_PREFAB_PATH + PREFAB_EXT}); 
            
            buildMap[1].assetBundleName = prefab[0].name + ASSETBUNDLE_EXT;
            for (int i = 0; i < prefab.Length; i++)
            {
                prefabPath = AssetDatabase.GetAssetPath(prefab[i]);
                buildMap[1].assetNames = new string[]{prefabPath};    
            }
        }
        else
        {
            buildMap = new AssetBundleBuild[prefab.Length + 1];
            
            buildMap[0].assetBundleName = SHARED_PREFAB + ASSETBUNDLE_EXT;
            buildMap[0].assetNames = AssetDatabase.GetDependencies(new string[] {SHARED_PREFAB_PATH + PREFAB_EXT}); 
            
            for (int i = 0; i < prefab.Length; i++)
            {
                prefabPath = AssetDatabase.GetAssetPath(prefab[i]);

                if (IsIndependentBundle(prefab[i].name))
                {
                    independentBundles.Add(prefab[i]);
                }
                else 
                {
                    buildMap[i + 1].assetBundleName = prefab[i].name + ASSETBUNDLE_EXT;
                    buildMap[i + 1].assetNames = new string[]{prefabPath};
                }
            }
        }

        BuildPipeline.BuildAssetBundles(directoryPath, buildMap, BuildAssetBundleOptions.ForceRebuildAssetBundle, target);

        if (independentBundles.Count > 0)
        {
            buildMap = new AssetBundleBuild[independentBundles.Count];

            for (int i = 0; i < independentBundles.Count; i++)
            {
                prefabPath = AssetDatabase.GetAssetPath(independentBundles[i]);
                buildMap[i].assetBundleName = independentBundles[i].name + ASSETBUNDLE_EXT;
                buildMap[i].assetNames = new string[]{prefabPath};
            }

            BuildPipeline.BuildAssetBundles(directoryPath, buildMap, BuildAssetBundleOptions.ForceRebuildAssetBundle, target);
        }

        return true;
    }

    static private bool IsIndependentBundle(string prefabName)
    {
        int index = Array.FindIndex(independentBundles, item => item.Equals(prefabName));
        if (index > 0)
        {
            return true;
        }

        return false;
    }
}


你可能感兴趣的:(Unity5打包assetbundle)