Search Unity

Asset Bundle Analyzer

Discussion in 'Assets and Asset Store' started by naxel, May 16, 2013.

  1. naxel

    naxel

    Joined:
    Sep 12, 2012
    Posts:
    14
    Hi, all.
    For those of you who lack the tool to get better understanding what is inside your asset bundle, I introduce "Asset Bundle Analyzer". Tool is completely free of charge and you can integrate it in your project by simply copying this source code in your "Editor" folder. After that you can open utility window from Unity menu (Tools->Analyze Asset Bundle). Than you should select asset bundle you want to analyze in your project tab and press 'analyze' button. Also you can specify folder for temp files.
    Utility output looks like:

    $AssetBundleAnalyzer.png

    Here you can analyze what types of resources present in your bundle and what is the amount of storage space they occupy.
    This is very useful if you want to understand why your asset bundle is so large or if you want to check that all shaders are extracted into separate asset bundle.
    Also note 'Compress' checkbox. Let's assume that all your bundles are compressed. So you can check this box and analyze approximate size of resource in you bundle. If you uncheck it you can analyze approximate run-time memory usage for resources in bundle.

    Unsolved problems:
    - By the moment tool doesn't analyze memory that used for components, only assets and Transform components are taken into account.
    - Platform detection of incoming asset bundle required. By the moment tool supports autodetection for android and ios by asset bundle name (if it contains '-android' or '-ios' in it's name).

    Special notes:
    - Resource sizes returned by the tool are just an approximation, but in practice precision for everything which is more than 1 Kb is good enough.

    AssetBundleAnalyzer.cs:
    Code (csharp):
    1.  
    2. using System.IO;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Collections.Generic;
    6.  
    7. public class AssetBundleAnalyzer : EditorWindow {
    8.     private struct StatData {
    9.         public string typeName;
    10.         public string objName;
    11.         public int    size;
    12.     }  
    13.    
    14.     private class StatDataComparer : IComparer<StatData> {
    15.         Dictionary<string, int> _typeSizeMap;
    16.        
    17.         public StatDataComparer(Dictionary<string, int> typeSizeMap)
    18.         {
    19.             _typeSizeMap = typeSizeMap;
    20.         }
    21.        
    22.         public int Compare(StatData stat1, StatData stat2)
    23.         {
    24.             int typeSize1 = _typeSizeMap[stat1.typeName];
    25.             int typeSize2 = _typeSizeMap[stat2.typeName];
    26.            
    27.             int stringCompare = stat1.typeName.CompareTo(stat2.typeName);
    28.    
    29.             if        (typeSize1 > typeSize2) {
    30.                 return -1;
    31.             } else if (typeSize1 < typeSize2) {
    32.                 return +1;
    33.             } else if (stringCompare != 0) {
    34.                 return stringCompare;
    35.             } else if (stat1.size > stat2.size) {
    36.                 return -1;
    37.             } else if (stat1.size < stat2.size) {
    38.                 return +1;
    39.             } else {
    40.                 return 0;
    41.             }                          
    42.         }
    43.     }
    44.    
    45.     private Vector2 scrollPosition = Vector2.zero;
    46.     private bool    compressed = false;
    47.     private string  outputPath = "";
    48.     private string  selectedPath = "";
    49.     private Object  analyzedObject = null; 
    50.     private List<StatData>  statistics = new List<StatData>();
    51.     private Dictionary<string, int >    typeSizeMap   = new Dictionary<string, int>();
    52.     private Dictionary<string, bool>    typeStatusMap = new Dictionary<string, bool>();
    53.    
    54.     [MenuItem("Tools/Analyze Asset Bundle")]
    55.     public static void ShowWindow()
    56.     {
    57.         EditorWindow.GetWindow(typeof(AssetBundleAnalyzer));
    58.     }
    59.        
    60.     void OnGUI()
    61.     {
    62.         Object currentObject = null;
    63.         string assetPath = "";
    64.        
    65.         if (Selection.activeObject != null) {
    66.             assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(Selection.activeObject));
    67.             if (assetPath.ToLower().Contains(".bytes")) {
    68.                 currentObject = Selection.activeObject;
    69.             }
    70.         }
    71.        
    72.         GUILayout.Label ("Asset bundle to analyze", EditorStyles.boldLabel);       
    73.         if (currentObject != null) {
    74.             FileInfo file = new FileInfo(assetPath);
    75.            
    76.             GUILayout.Label("   file: " + assetPath);          
    77.             GUILayout.Label("   size: " + file.Length/1024 + " Kb");
    78.         } else {
    79.             GUILayout.Label("   file: None (select in project)");
    80.             GUILayout.Label("   size: 0 Kb");
    81.         }          
    82.        
    83.         GUILayout.Label ("Settings", EditorStyles.boldLabel);      
    84.         compressed = EditorGUILayout.Toggle ("   Compress", compressed);       
    85.    
    86.         EditorGUILayout.BeginHorizontal();
    87.         {
    88.             selectedPath = EditorGUILayout.TextField("   Output path: ", selectedPath);
    89.             if (GUILayout.Button("select", GUILayout.Width(50))) {
    90.                 selectedPath = EditorUtility.SaveFolderPanel ("Select output directory", "", selectedPath);
    91.             }
    92.            
    93.             outputPath = selectedPath + "/.analyze";
    94.         }
    95.         EditorGUILayout.EndHorizontal();
    96.        
    97.         EditorGUILayout.Space();
    98.         if (GUILayout.Button ("analyze", GUILayout.Width (100))  currentObject != null) {
    99.             if (outputPath.Length == 0) {
    100.                 Debug.LogError("Please select valid output path");
    101.                 return;
    102.             }
    103.            
    104.             try {
    105.                 if (Directory.Exists(outputPath)) {
    106.                     Directory.Delete(outputPath, true);    
    107.                 }          
    108.             } finally {
    109.                 Directory.CreateDirectory(outputPath); 
    110.             }
    111.            
    112.             if (!Directory.Exists(outputPath)) {
    113.                 Debug.LogError("Please select valid output path");
    114.                 return;
    115.             }
    116.            
    117.             // detect platform
    118.             BuildTarget buildTarget = BuildTarget.Android;
    119.             if (assetPath.Contains("-ios")) {
    120.                 buildTarget = BuildTarget.iPhone;
    121.             } else if (assetPath.Contains("-android")) {
    122.                 buildTarget = BuildTarget.Android;
    123.             } else {
    124.                 Debug.LogWarning("Original asset bundle platform not detected. Android selected as default");
    125.             }
    126.                        
    127.             analyzeAssetBundle(currentObject, buildTarget);        
    128.         }
    129.        
    130.         if (analyzedObject != currentObject) {
    131.             statistics.Clear();
    132.             analyzedObject = null;         
    133.         }
    134.                
    135.         if (analyzedObject != null) {
    136.             scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
    137.             {
    138.                 string curType = "";
    139.                
    140.                 foreach(StatData data in statistics) {
    141.                     if (curType != data.typeName) {
    142.                         EditorGUILayout.BeginHorizontal();
    143.                         {                                          
    144.                             typeStatusMap[data.typeName] = EditorGUILayout.Foldout(typeStatusMap[data.typeName], data.typeName);       
    145.                            
    146.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;
    147.                             GUI.skin.label.fontStyle = FontStyle.Bold;                                         
    148.                            
    149.                             GUILayout.Label(typeSizeMap[data.typeName]/1024 + " Kb");
    150.                             GUILayout.Space(400);
    151.                         }
    152.                         EditorGUILayout.EndHorizontal();
    153.                        
    154.                         curType = data.typeName;
    155.                     }
    156.                    
    157.                     if (typeStatusMap[data.typeName]) {
    158.                         EditorGUILayout.BeginHorizontal();
    159.                         {
    160.                             GUI.skin.label.alignment = TextAnchor.MiddleLeft;
    161.                             GUI.skin.label.fontStyle = FontStyle.Normal;                                           
    162.                            
    163.                             GUILayout.Label("    " + data.objName);
    164.                            
    165.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;                     
    166.                             GUILayout.Label(data.size/1024 + " Kb");
    167.                            
    168.                             GUILayout.Space(400);  
    169.                         }
    170.                         EditorGUILayout.EndHorizontal();
    171.                     }
    172.                 }
    173.             }
    174.             EditorGUILayout.EndScrollView();
    175.         }
    176.     }
    177.    
    178.     private void analyzeAssetBundle(Object obj, BuildTarget buildTarget)
    179.     {  
    180.         typeStatusMap.Clear();
    181.         typeSizeMap.Clear();
    182.         statistics.Clear();
    183.         analyzedObject = obj;      
    184.        
    185.         string assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(obj));
    186.         WWW www = new WWW("file:///" + assetPath);
    187.         Object[]    loadedObjects = www.assetBundle.LoadAll();         
    188.        
    189.         foreach(Object loadedObj in loadedObjects) {
    190.             string directory = outputPath + "/" + loadedObj.GetType().FullName + "/";
    191.             if (!Directory.Exists(directory)) {
    192.                 Directory.CreateDirectory(directory);
    193.             }
    194.            
    195.             string bundlePath = directory + loadedObj.name.Replace("/", ".") + "." + loadedObj.GetInstanceID() + ".bytes";
    196.             BuildPipeline.BuildAssetBundle(loadedObj, null, bundlePath,                                    
    197.                                            compressed ? 0 : BuildAssetBundleOptions.UncompressedAssetBundle,
    198.                                            buildTarget);   
    199.            
    200.             if (File.Exists(bundlePath)) {
    201.                 StatData    stat = new StatData();
    202.                 stat.objName  = loadedObj.name;
    203.                 stat.typeName = loadedObj.GetType().FullName;
    204.                
    205.                 FileInfo    fileInfo = new FileInfo(bundlePath);
    206.                 stat.size     = (int) fileInfo.Length;
    207.                
    208.                 statistics.Add(stat);
    209.             }
    210.         }
    211.        
    212.         www.assetBundle.Unload(true);
    213.         www.Dispose(); 
    214.        
    215.         // fill type size map
    216.         foreach(StatData data in statistics) {
    217.             if (typeSizeMap.ContainsKey(data.typeName)) {
    218.                 typeSizeMap[data.typeName] += data.size;
    219.             } else {
    220.                 typeSizeMap.Add(data.typeName, data.size);
    221.             }
    222.         }              
    223.        
    224.         // fill type status map
    225.         foreach(string typeName in typeSizeMap.Keys) {
    226.             typeStatusMap.Add(typeName, false);
    227.         }
    228.        
    229.         statistics.Sort(new StatDataComparer(typeSizeMap));    
    230.     }
    231. }
    232.  
     
  2. sathya

    sathya

    Joined:
    Jul 30, 2012
    Posts:
    297
    Hi naxel thanks for the script. unfortunately i am not able to selecet any asset bundles from project hierarchy. Am i missing any steps. !
     
  3. MikeBastien

    MikeBastien

    Joined:
    Apr 24, 2009
    Posts:
    139
    I had the same problem at the start, but if you look at his comments you'll see that he only had it set up for ios or android.

    It should not take you much to adjust it to your needs. Try this:

    Comment out lines #66 #68.

    Then comment out the line at #123:
    Code (csharp):
    1. Debug.LogWarning("Original asset bundle platform not detected. Android selected as default");
    and then insert this in the else block:
    Code (csharp):
    1. buildTarget = BuildTarget.StandaloneWindows;
    and it should work for you in the editor (although there may be something else I missed, but I think that's it).

    You can then adjust based on your project's needs.

    It has certainly been a helpful tool for me.

    It throws warnings about missing components and that I should use BuildAssetBundleOptions.CollectDependencies (which I am). A visual verification seems to indicate that everything is there and the warning is wrong.

    Perhaps I'm missing something.
     
  4. Felix-Schlitter

    Felix-Schlitter

    Joined:
    Sep 30, 2013
    Posts:
    8
    What a wonderful tool! Thanks so much for sharing!
     
  5. artbyalex

    artbyalex

    Joined:
    Mar 11, 2012
    Posts:
    4
    @naxel thanks for sharing this tool!

    i get the following error when trying to run the script in editor.

    Assets/Editor/NewBehaviourScript.cs(98,86): error CS1525: Unexpected symbol `currentObject'

    any ideas??
     
  6. CoalCzar

    CoalCzar

    Joined:
    Nov 25, 2012
    Posts:
    22
    Sorry to necro this thread, but I fixed a couple things with the script to make it more usable.
    1. I fixed the bug @artbyalex noticed (was missing &&).
    2. I added a popup to choose the Build Target for users (it defaults to your currently selected one).
    Enjoy!

    Code (CSharp):
    1. using System.IO;
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections.Generic;
    5.  
    6. public class AssetBundleAnalyzer : EditorWindow {
    7.     private struct StatData {
    8.         public string typeName;
    9.         public string objName;
    10.         public int    size;
    11.     }
    12.    
    13.     private class StatDataComparer : IComparer<StatData> {
    14.         Dictionary<string, int> _typeSizeMap;
    15.        
    16.         public StatDataComparer(Dictionary<string, int> typeSizeMap)
    17.         {
    18.             _typeSizeMap = typeSizeMap;
    19.         }
    20.        
    21.         public int Compare(StatData stat1, StatData stat2)
    22.         {
    23.             int typeSize1 = _typeSizeMap[stat1.typeName];
    24.             int typeSize2 = _typeSizeMap[stat2.typeName];
    25.            
    26.             int stringCompare = stat1.typeName.CompareTo(stat2.typeName);
    27.            
    28.             if        (typeSize1 > typeSize2) {
    29.                 return -1;
    30.             } else if (typeSize1 < typeSize2) {
    31.                 return +1;
    32.             } else if (stringCompare != 0) {
    33.                 return stringCompare;
    34.             } else if (stat1.size > stat2.size) {
    35.                 return -1;
    36.             } else if (stat1.size < stat2.size) {
    37.                 return +1;
    38.             } else {
    39.                 return 0;
    40.             }                        
    41.         }
    42.     }
    43.    
    44.     private Vector2 scrollPosition = Vector2.zero;
    45.     private bool    compressed = false;
    46.     private BuildTarget buildTarget = EditorUserBuildSettings.activeBuildTarget;
    47.     private string  outputPath = "";
    48.     private string  selectedPath = "";
    49.     private Object  analyzedObject = null;
    50.     private List<StatData>  statistics = new List<StatData>();
    51.     private Dictionary<string, int >    typeSizeMap   = new Dictionary<string, int>();
    52.     private Dictionary<string, bool>    typeStatusMap = new Dictionary<string, bool>();
    53.    
    54.     [MenuItem("Tools/Analyze Asset Bundle")]
    55.     public static void ShowWindow()
    56.     {
    57.         EditorWindow.GetWindow(typeof(AssetBundleAnalyzer));
    58.     }
    59.    
    60.     void OnGUI()
    61.     {
    62.         Object currentObject = null;
    63.         string assetPath = "";
    64.        
    65.         if (Selection.activeObject != null) {
    66.             assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(Selection.activeObject));
    67.             if (assetPath.ToLower().Contains(".unity3d")) {
    68.                 currentObject = Selection.activeObject;
    69.             }
    70.         }
    71.        
    72.         GUILayout.Label ("Asset bundle to analyze", EditorStyles.boldLabel);      
    73.         if (currentObject != null) {
    74.             FileInfo file = new FileInfo(assetPath);
    75.            
    76.             GUILayout.Label("   file: " + assetPath);        
    77.             GUILayout.Label("   size: " + file.Length/1024 + " Kb");
    78.         } else {
    79.             GUILayout.Label("   file: None (select in project)");
    80.             GUILayout.Label("   size: 0 Kb");
    81.         }        
    82.        
    83.         GUILayout.Label ("Settings", EditorStyles.boldLabel);    
    84.  
    85.         compressed = EditorGUILayout.Toggle ("   Compress", compressed);      
    86.         buildTarget = (BuildTarget)EditorGUILayout.EnumPopup("   Build Target", buildTarget);
    87.        
    88.         EditorGUILayout.BeginHorizontal();
    89.         {
    90.             selectedPath = EditorGUILayout.TextField("   Output path: ", selectedPath);
    91.             if (GUILayout.Button("select", GUILayout.Width(50))) {
    92.                 selectedPath = EditorUtility.SaveFolderPanel ("Select output directory", "", selectedPath);
    93.             }
    94.            
    95.             outputPath = selectedPath + "/.analyze";
    96.         }
    97.         EditorGUILayout.EndHorizontal();
    98.        
    99.         EditorGUILayout.Space();
    100.         if (GUILayout.Button ("analyze", GUILayout.Width (100)) && currentObject != null) {
    101.             if (outputPath.Length == 0) {
    102.                 Debug.LogError("Please select valid output path");
    103.                 return;
    104.             }
    105.            
    106.             try {
    107.                 if (Directory.Exists(outputPath)) {
    108.                     Directory.Delete(outputPath, true);  
    109.                 }        
    110.             } finally {
    111.                 Directory.CreateDirectory(outputPath);
    112.             }
    113.            
    114.             if (!Directory.Exists(outputPath)) {
    115.                 Debug.LogError("Please select valid output path");
    116.                 return;
    117.             }
    118.            
    119.             analyzeAssetBundle(currentObject, buildTarget);      
    120.         }
    121.        
    122.         if (analyzedObject != currentObject) {
    123.             statistics.Clear();
    124.             analyzedObject = null;        
    125.         }
    126.        
    127.         if (analyzedObject != null) {
    128.             scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
    129.             {
    130.                 string curType = "";
    131.                
    132.                 foreach(StatData data in statistics) {
    133.                     if (curType != data.typeName) {
    134.                         EditorGUILayout.BeginHorizontal();
    135.                         {                                        
    136.                             typeStatusMap[data.typeName] = EditorGUILayout.Foldout(typeStatusMap[data.typeName], data.typeName);      
    137.                            
    138.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;
    139.                             GUI.skin.label.fontStyle = FontStyle.Bold;                                        
    140.                            
    141.                             GUILayout.Label(typeSizeMap[data.typeName]/1024 + " Kb");
    142.                             GUILayout.Space(400);
    143.                         }
    144.                         EditorGUILayout.EndHorizontal();
    145.                        
    146.                         curType = data.typeName;
    147.                     }
    148.                    
    149.                     if (typeStatusMap[data.typeName]) {
    150.                         EditorGUILayout.BeginHorizontal();
    151.                         {
    152.                             GUI.skin.label.alignment = TextAnchor.MiddleLeft;
    153.                             GUI.skin.label.fontStyle = FontStyle.Normal;                                          
    154.                            
    155.                             GUILayout.Label("    " + data.objName);
    156.                            
    157.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;                    
    158.                             GUILayout.Label(data.size/1024 + " Kb");
    159.                            
    160.                             GUILayout.Space(400);
    161.                         }
    162.                         EditorGUILayout.EndHorizontal();
    163.                     }
    164.                 }
    165.             }
    166.             EditorGUILayout.EndScrollView();
    167.         }
    168.     }
    169.    
    170.     private void analyzeAssetBundle(Object obj, BuildTarget buildTarget)
    171.     {
    172.         typeStatusMap.Clear();
    173.         typeSizeMap.Clear();
    174.         statistics.Clear();
    175.         analyzedObject = obj;    
    176.        
    177.         string assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(obj));
    178.         WWW www = new WWW("file:///" + assetPath);
    179.         Object[]    loadedObjects = www.assetBundle.LoadAll();        
    180.        
    181.         foreach(Object loadedObj in loadedObjects) {
    182.             string directory = outputPath + "/" + loadedObj.GetType().FullName + "/";
    183.             if (!Directory.Exists(directory)) {
    184.                 Directory.CreateDirectory(directory);
    185.             }
    186.            
    187.             string bundlePath = directory + loadedObj.name.Replace("/", ".") + "." + loadedObj.GetInstanceID() + ".bytes";
    188.             BuildPipeline.BuildAssetBundle(loadedObj, null, bundlePath,                                  
    189.                                            compressed ? 0 : BuildAssetBundleOptions.UncompressedAssetBundle,
    190.                                            buildTarget);  
    191.            
    192.             if (File.Exists(bundlePath)) {
    193.                 StatData    stat = new StatData();
    194.                 stat.objName  = loadedObj.name;
    195.                 stat.typeName = loadedObj.GetType().FullName;
    196.                
    197.                 FileInfo    fileInfo = new FileInfo(bundlePath);
    198.                 stat.size     = (int) fileInfo.Length;
    199.                
    200.                 statistics.Add(stat);
    201.             }
    202.         }
    203.        
    204.         www.assetBundle.Unload(true);
    205.         www.Dispose();
    206.        
    207.         // fill type size map
    208.         foreach(StatData data in statistics) {
    209.             if (typeSizeMap.ContainsKey(data.typeName)) {
    210.                 typeSizeMap[data.typeName] += data.size;
    211.             } else {
    212.                 typeSizeMap.Add(data.typeName, data.size);
    213.             }
    214.         }            
    215.        
    216.         // fill type status map
    217.         foreach(string typeName in typeSizeMap.Keys) {
    218.             typeStatusMap.Add(typeName, false);
    219.         }
    220.        
    221.         statistics.Sort(new StatDataComparer(typeSizeMap));  
    222.     }
    223. }
     
    Art-Leaping and ccklokwerks like this.
  7. l0cke

    l0cke

    Joined:
    Apr 15, 2012
    Posts:
    438
    I does not seem to work with Unity 5.
     
  8. Alexander21

    Alexander21

    Joined:
    Dec 14, 2015
    Posts:
    302
    Ya it does not seem to work with unity 5. i have received the following error..,...

    Assets/AssetBundleManager/AssetBundleAnalyzer.cs(179,53): error CS0619: `UnityEngine.AssetBundle.LoadAll()' is obsolete: `Method LoadAll has been deprecated. Script updater cannot update it as the loading behaviour has changed. Please use LoadAllAssets instead and check the documentation for details.'
     
  9. MaxFr77

    MaxFr77

    Joined:
    Nov 9, 2015
    Posts:
    7
    Hello
    Here's a fix that makes it work in unity 5.5.
    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Collections.Generic;
    6.  
    7.  
    8. public class AssetBundleAnalyzer : EditorWindow {
    9.     private struct StatData {
    10.         public string typeName;
    11.         public string objName;
    12.         public int    size;
    13.     }
    14.  
    15.     private class StatDataComparer : IComparer<StatData> {
    16.         Dictionary<string, int> _typeSizeMap;
    17.  
    18.         public StatDataComparer(Dictionary<string, int> typeSizeMap)
    19.         {
    20.             _typeSizeMap = typeSizeMap;
    21.         }
    22.  
    23.         public int Compare(StatData stat1, StatData stat2)
    24.         {
    25.             int typeSize1 = _typeSizeMap[stat1.typeName];
    26.             int typeSize2 = _typeSizeMap[stat2.typeName];
    27.  
    28.             int stringCompare = stat1.typeName.CompareTo(stat2.typeName);
    29.  
    30.             if        (typeSize1 > typeSize2) {
    31.                 return -1;
    32.             } else if (typeSize1 < typeSize2) {
    33.                 return +1;
    34.             } else if (stringCompare != 0) {
    35.                 return stringCompare;
    36.             } else if (stat1.size > stat2.size) {
    37.                 return -1;
    38.             } else if (stat1.size < stat2.size) {
    39.                 return +1;
    40.             } else {
    41.                 return 0;
    42.             }                      
    43.         }
    44.     }
    45.  
    46.     private Vector2 scrollPosition = Vector2.zero;
    47.     private bool    compressed = false;
    48.     private BuildTarget buildTarget;
    49.     private string  outputPath = "";
    50.     private string  selectedPath = "";
    51.     private UnityEngine.Object  analyzedObject = null;
    52.     private List<StatData>  statistics = new List<StatData>();
    53.     private Dictionary<string, int >    typeSizeMap   = new Dictionary<string, int>();
    54.     private Dictionary<string, bool>    typeStatusMap = new Dictionary<string, bool>();
    55.  
    56.     [MenuItem("Tools/Analyze Asset Bundle")]
    57.     public static void ShowWindow()
    58.     {
    59.         AssetBundleAnalyzer AssetBundleAnalyzerEditorWindow = (AssetBundleAnalyzer) EditorWindow.GetWindow(typeof(AssetBundleAnalyzer));
    60.         AssetBundleAnalyzerEditorWindow.buildTarget = EditorUserBuildSettings.activeBuildTarget;
    61.     }
    62.  
    63.     void OnGUI()
    64.     {          
    65.         UnityEngine.Object currentObject = null;
    66.         string assetPath = "";
    67.  
    68.         if (Selection.activeObject != null) {
    69.             assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(Selection.activeObject));
    70.             if (assetPath.Contains("AssetBundles") && !assetPath.Contains(".Manifest")) {
    71.                 currentObject = Selection.activeObject;
    72.             }
    73.         }
    74.  
    75.         GUILayout.Label ("Asset bundle to analyze", EditorStyles.boldLabel);    
    76.         if (currentObject != null) {
    77.             FileInfo file = new FileInfo(assetPath);
    78.  
    79.             GUILayout.Label("   file: " + assetPath);      
    80.             GUILayout.Label("   size: " + file.Length/1024 + " Kb");
    81.         } else {
    82.             GUILayout.Label("   file: None (select in project)");
    83.             GUILayout.Label("   size: 0 Kb");
    84.         }      
    85.  
    86.         GUILayout.Label ("Settings", EditorStyles.boldLabel);  
    87.  
    88.         compressed = EditorGUILayout.Toggle ("   Compress", compressed);    
    89.         buildTarget = (BuildTarget)EditorGUILayout.EnumPopup("   Build Target", buildTarget);
    90.  
    91.         EditorGUILayout.BeginHorizontal();
    92.         {
    93.             selectedPath = EditorGUILayout.TextField("   Output path: ", selectedPath);
    94.             if (GUILayout.Button("select", GUILayout.Width(50))) {
    95.                 selectedPath = EditorUtility.SaveFolderPanel ("Select output directory", "", selectedPath);
    96.             }
    97.  
    98.             outputPath = selectedPath + "/.analyze";
    99.         }
    100.         EditorGUILayout.EndHorizontal();
    101.  
    102.         EditorGUILayout.Space();
    103.         if (GUILayout.Button ("analyze", GUILayout.Width (100)) && currentObject != null) {
    104.             if (outputPath.Length == 0) {
    105.                 Debug.LogError("Please select valid output path");
    106.                 return;
    107.             }
    108.  
    109.             try {
    110.                 if (Directory.Exists(outputPath)) {
    111.                     Directory.Delete(outputPath, true);
    112.                 }      
    113.             } finally {
    114.                 Directory.CreateDirectory(outputPath);
    115.             }
    116.  
    117.             if (!Directory.Exists(outputPath)) {
    118.                 Debug.LogError("Please select valid output path");
    119.                 return;
    120.             }
    121.  
    122.             analyzeAssetBundle(currentObject, buildTarget);    
    123.         }
    124.  
    125.         if (analyzedObject != currentObject) {
    126.             statistics.Clear();
    127.             analyzedObject = null;      
    128.         }
    129.  
    130.         if (analyzedObject != null) {
    131.             scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
    132.             {
    133.                 string curType = "";
    134.  
    135.                 foreach(StatData data in statistics) {
    136.                     if (curType != data.typeName) {
    137.                         EditorGUILayout.BeginHorizontal();
    138.                         {                                      
    139.                             typeStatusMap[data.typeName] = EditorGUILayout.Foldout(typeStatusMap[data.typeName], data.typeName);    
    140.  
    141.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;
    142.                             GUI.skin.label.fontStyle = FontStyle.Bold;                                      
    143.  
    144.                             GUILayout.Label(typeSizeMap[data.typeName]/1024 + " Kb");
    145.                             GUILayout.Space(100);
    146.                         }
    147.                         EditorGUILayout.EndHorizontal();
    148.  
    149.                         curType = data.typeName;
    150.                     }
    151.  
    152.                     if (typeStatusMap[data.typeName]) {
    153.                         EditorGUILayout.BeginHorizontal();
    154.                         {
    155.                             GUI.skin.label.alignment = TextAnchor.MiddleLeft;
    156.                             GUI.skin.label.fontStyle = FontStyle.Normal;                                        
    157.  
    158.                             GUILayout.Label("    " + data.objName);
    159.  
    160.                             GUI.skin.label.alignment = TextAnchor.MiddleRight;                  
    161.                             GUILayout.Label(data.size/1024 + " Kb");
    162.  
    163.                             GUILayout.Space(100);
    164.                         }
    165.                         EditorGUILayout.EndHorizontal();
    166.                     }
    167.                 }
    168.             }
    169.             EditorGUILayout.EndScrollView();
    170.         }
    171.     }
    172.  
    173.     private void analyzeAssetBundle(UnityEngine.Object obj, BuildTarget buildTarget)
    174.     {
    175.         typeStatusMap.Clear();
    176.         typeSizeMap.Clear();
    177.         statistics.Clear();
    178.         analyzedObject = obj;  
    179.  
    180.         string assetPath = Path.GetFullPath(AssetDatabase.GetAssetPath(obj));
    181.         WWW www = new WWW("file:///" + assetPath);
    182.         UnityEngine.Object[]    loadedObjects = www.assetBundle.LoadAllAssets();      
    183.  
    184.         foreach(UnityEngine.Object loadedObj in loadedObjects) {
    185.             string directory = outputPath + "/" + loadedObj.GetType().FullName + "/";
    186.             if (!Directory.Exists(directory)) {
    187.                 Directory.CreateDirectory(directory);
    188.             }
    189.  
    190.             string bundlePath = directory + loadedObj.name.Replace("/", ".") + "." + loadedObj.GetInstanceID() + ".bytes";
    191.             try{
    192.                 BuildPipeline.BuildAssetBundle(loadedObj, null, bundlePath,                                
    193.                     compressed ? 0 : BuildAssetBundleOptions.UncompressedAssetBundle,
    194.                     buildTarget);
    195.             } catch (Exception e) {
    196.             }
    197.  
    198.             if (File.Exists(bundlePath)) {
    199.                 StatData    stat = new StatData();
    200.                 stat.objName  = loadedObj.name;
    201.                 stat.typeName = loadedObj.GetType().FullName;
    202.  
    203.                 FileInfo    fileInfo = new FileInfo(bundlePath);
    204.                 stat.size     = (int) fileInfo.Length;
    205.  
    206.                 statistics.Add(stat);
    207.             }
    208.         }
    209.  
    210.         www.assetBundle.Unload(true);
    211.         www.Dispose();
    212.  
    213.         // fill type size map
    214.         foreach(StatData data in statistics) {
    215.             if (typeSizeMap.ContainsKey(data.typeName)) {
    216.                 typeSizeMap[data.typeName] += data.size;
    217.             } else {
    218.                 typeSizeMap.Add(data.typeName, data.size);
    219.             }
    220.         }          
    221.  
    222.         // fill type status map
    223.         foreach(string typeName in typeSizeMap.Keys) {
    224.             typeStatusMap.Add(typeName, false);
    225.         }
    226.  
    227.         statistics.Sort(new StatDataComparer(typeSizeMap));
    228.     }
    229. }
    230.  
    Still not perfect though: it's very slow and has difficulties with dependencies.
    Personally after I tried many things, I finally ended up using this asset extractor tool, which lets you inspect the bundle contents and is very fast:
    https://7daystodie.com/forums/showthread.php?22675-Unity-Assets-Bundle-Extractor
     
    Art-Leaping likes this.
  10. Wappenull

    Wappenull

    Joined:
    Oct 29, 2013
    Posts:
    51
    Pardon for bumping. Just adding useful info to internet traveller.
    Since this thread appear very early on google search asset bundle size analyze

    Hey, just to remind everyone that when building an asset bundle, editor will produce editor log file similar to when building a standalone player. You can watch size composition there too. No special tool. No magic. No 200-lines script is needed.
    upload_2021-2-12_0-42-0.png
    Scroll down to bottom for most recent messages.
    upload_2021-2-12_0-43-21.png
    For third party asset bundle, if you want to sneak peek them, probably require third party tool.
    FYI: I'm using this to build my bundles. https://github.com/Unity-Technologies/AssetBundles-Browser

    PS. Just landed here from google-sensei search too. Tried the script, realized it did not work. And just realize this method.
     
    BeregAlto likes this.
  11. BeregAlto

    BeregAlto

    Joined:
    Aug 5, 2018
    Posts:
    14
    Thank you, very helpful!
     
  12. KAJed

    KAJed

    Joined:
    Mar 15, 2013
    Posts:
    122
    My experience has been that these logs are no longer available. Is there an option to re-enable them?
     
  13. Wappenull

    Wappenull

    Joined:
    Oct 29, 2013
    Posts:
    51
    • As to my knowledge, these editor log cannot be turned off, (It is always output) it is part of editor core function.
    • Be noted that asset bundle system will NOT rebuild asset bundle if it is up to date, thus no log output even if you command them to build. Try remove the output files and start build fresh.
    • Or check the location of editor log file manually. Mine is at
      C:\Users\{USERNAME}\AppData\Local\Unity\Editor
    • Or maybe try close editor, delete log files, and start again to see if it is happily outputting the log?