// // BuildScript.cs // // Author: // fjy // // Copyright (c) 2020 fjy // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; namespace libx { public static class BuildScript { public static string outputPath = "../Release/" + GetPlatformName(); public static void ClearAssetBundles () { string[] allAssetBundleNames = AssetDatabase.GetAllAssetBundleNames (); for (int i = 0; i < allAssetBundleNames.Length; i++) { string text = allAssetBundleNames [i]; if (EditorUtility.DisplayCancelableProgressBar ( string.Format ("Clear AssetBundles {0}/{1}", i, allAssetBundleNames.Length), text, i * 1f / allAssetBundleNames.Length)) break; AssetDatabase.RemoveAssetBundleName (text, true); } EditorUtility.ClearProgressBar (); } internal static void ApplyBuildRules () { BuildRules rule = GetBuildRules (); //string hotUpdatePath = "Assets/Download/"; //if (!Directory.Exists(hotUpdatePath)) //{ // Directory.CreateDirectory(hotUpdatePath); //} //rule.rules = new[] //{ // new BuildRule() // { // searchPath = hotUpdatePath+"Controller", // searchPattern = rule.searchPatternController, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"Dll", // searchPattern = rule.searchPatternText, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"Material", // searchPattern = rule.searchPatternMaterial, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"Other", // searchPattern = rule.searchPatternDir, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"Prefab", // searchPattern = rule.searchPatternPrefab, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"Scene", // searchPattern = rule.searchPatternScene, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"ScriptableObject", // searchPattern = rule.searchPatternAsset, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"TextAsset", // searchPattern = rule.searchPatternText, // nameBy = NameBy.Path // }, // new BuildRule() // { // searchPath = hotUpdatePath+"UI", // searchPattern = rule.searchPatternPng, // nameBy = NameBy.Path // } //}; //foreach (var _rule in rule.rules) //{ // if (!Directory.Exists(_rule.searchPath)) // { // Directory.CreateDirectory(_rule.searchPath); // } //} //AssetDatabase.SaveAssets(); rule.Apply (); } internal static BuildRules GetBuildRules () { return GetAsset ("Assets/Res/Common/Rules.asset"); } public static void CopyAssetBundlesTo(string path, bool vfs = false) { if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var versions = new List(); if (!vfs) { versions.AddRange(Versions.LoadVersions(outputPath + "/" + Versions.Filename)); versions.Add(new VFile() { name = Versions.Filename }); versions.RemoveAt(versions.FindIndex(file => file.name.Equals(Versions.Dataname))); } else { versions.Add(new VFile() { name = Versions.Filename }); versions.Add(new VFile() { name = Versions.Dataname }); } foreach (VFile item in versions) { string src = outputPath + "/" + item.name; string dest = path + "/" + item.name; if (File.Exists(src)) { File.Copy(src, dest, true); } } AssetDatabase.Refresh(); } public static string GetPlatformName () { return GetPlatformForAssetBundles (EditorUserBuildSettings.activeBuildTarget); } private static string GetPlatformForAssetBundles (BuildTarget target) { switch (target) { case BuildTarget.Android: return "Android"; case BuildTarget.iOS: return "iOS"; case BuildTarget.WebGL: return "WebGL"; case BuildTarget.StandaloneWindows: case BuildTarget.StandaloneWindows64: return "Windows"; #if UNITY_2017_3_OR_NEWER case BuildTarget.StandaloneOSX: return "OSX"; #else case BuildTarget.StandaloneOSXIntel: case BuildTarget.StandaloneOSXIntel64: case BuildTarget.StandaloneOSXUniversal: return "OSX"; #endif default: return null; } } private static string[] GetLevelsFromBuildSettings () { List scenes = new List (); foreach (SceneAsset item in GetBuildRules().scenesInBuild) { string path = AssetDatabase.GetAssetPath (item); if (!string.IsNullOrEmpty (path)) { scenes.Add (path); } } return scenes.ToArray (); } private static string GetAssetBundleManifestFilePath () { string relativeAssetBundlesOutputPathForPlatform = Path.Combine ("Asset", GetPlatformName ()); return Path.Combine (relativeAssetBundlesOutputPathForPlatform, GetPlatformName ()) + ".manifest"; } public static void BuildStandalonePlayer () { string outputPath = Path.Combine (Environment.CurrentDirectory, "Build/" + GetPlatformName () .ToLower ()); //EditorUtility.SaveFolderPanel("Choose Location of the Built Game", "", ""); if (outputPath.Length == 0) return; string[] levels = GetLevelsFromBuildSettings (); if (levels.Length == 0) { Debug.Log ("Nothing to build."); return; } string targetName = GetBuildTargetName (EditorUserBuildSettings.activeBuildTarget); if (targetName == null) return; #if UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0 BuildOptions option = EditorUserBuildSettings.development ? BuildOptions.Development : BuildOptions.None; BuildPipeline.BuildPlayer(levels, path + targetName, EditorUserBuildSettings.activeBuildTarget, option); #else BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions { scenes = levels, locationPathName = outputPath + targetName, assetBundleManifestPath = GetAssetBundleManifestFilePath (), target = EditorUserBuildSettings.activeBuildTarget, options = EditorUserBuildSettings.development ? BuildOptions.Development : BuildOptions.None }; BuildPipeline.BuildPlayer (buildPlayerOptions); #endif } public static string CreateAssetBundleDirectory () { // Choose the output path according to the build target. if (!Directory.Exists (outputPath)) Directory.CreateDirectory (outputPath); return outputPath; } public static void BuildAssetBundles () { // Choose the output path according to the build target. string outputPath = CreateAssetBundleDirectory (); const BuildAssetBundleOptions options = BuildAssetBundleOptions.ChunkBasedCompression; BuildTarget targetPlatform = EditorUserBuildSettings.activeBuildTarget; BuildRules rules = GetBuildRules (); var builds = rules.GetBuilds (); AssetBundleManifest assetBundleManifest = BuildPipeline.BuildAssetBundles (outputPath, builds, options, targetPlatform); if (assetBundleManifest == null) { return; } Manifest manifest = GetManifest (); var dirs = new List (); var assets = new List (); string[] bundles = assetBundleManifest.GetAllAssetBundles (); var bundle2Ids = new Dictionary (); for (int index = 0; index < bundles.Length; index++) { string bundle = bundles [index]; bundle2Ids [bundle] = index; } var bundleRefs = new List (); for (int index = 0; index < bundles.Length; index++) { string bundle = bundles [index]; string[] deps = assetBundleManifest.GetAllDependencies (bundle); string path = string.Format ("{0}/{1}", outputPath, bundle); if (File.Exists (path)) { using (FileStream stream = File.OpenRead (path)) { bundleRefs.Add (new BundleRef { name = bundle, id = index, deps = Array.ConvertAll (deps, input => bundle2Ids [input]), len = stream.Length, hash = assetBundleManifest.GetAssetBundleHash (bundle).ToString (), }); } } else { Debug.LogError (path + " file not exsit."); } } for (int i = 0; i < rules.ruleAssets.Length; i++) { RuleAsset item = rules.ruleAssets [i]; string path = item.path; string dir = Path.GetDirectoryName (path).Replace("\\", "/"); int index = dirs.FindIndex (o => o.Equals (dir)); if (index == -1) { index = dirs.Count; dirs.Add (dir); } AssetRef asset = new AssetRef { bundle = bundle2Ids [item.bundle], dir = index, name = Path.GetFileName (path) }; assets.Add (asset); } manifest.dirs = dirs.ToArray (); manifest.assets = assets.ToArray (); manifest.bundles = bundleRefs.ToArray (); EditorUtility.SetDirty (manifest); AssetDatabase.SaveAssets (); AssetDatabase.Refresh (); string manifestBundleName = "manifest.unity3d"; builds = new[] { new AssetBundleBuild { assetNames = new[] { AssetDatabase.GetAssetPath (manifest), }, assetBundleName = manifestBundleName } }; BuildPipeline.BuildAssetBundles (outputPath, builds, options, targetPlatform); ArrayUtility.Add (ref bundles, manifestBundleName); Versions.BuildVersions (outputPath, bundles, GetBuildRules ().AddVersion ()); } private static string GetBuildTargetName (BuildTarget target) { string time = DateTime.Now.ToString ("yyyyMMdd-HHmmss"); string name = PlayerSettings.productName + "-v" + PlayerSettings.bundleVersion + "."; switch (target) { case BuildTarget.Android: return string.Format ("/{0}{1}-{2}.apk", name, GetBuildRules().version, time); case BuildTarget.StandaloneWindows: case BuildTarget.StandaloneWindows64: return string.Format ("/{0}{1}-{2}.exe", name, GetBuildRules().version, time); #if UNITY_2017_3_OR_NEWER case BuildTarget.StandaloneOSX: return "/" + name + ".app"; #else case BuildTarget.StandaloneOSXIntel: case BuildTarget.StandaloneOSXIntel64: case BuildTarget.StandaloneOSXUniversal: return "/" + path + ".app"; #endif case BuildTarget.WebGL: case BuildTarget.iOS: return ""; // Add more build targets for your own. default: Debug.Log ("Target not implemented."); return null; } } private static T GetAsset (string path) where T : ScriptableObject { T asset = AssetDatabase.LoadAssetAtPath (path); if (asset == null) { asset = ScriptableObject.CreateInstance (); AssetDatabase.CreateAsset (asset, path); AssetDatabase.SaveAssets (); } return asset; } public static Manifest GetManifest () { return GetAsset (Assets.ManifestAsset); } } }