AssetBundle资源冗余检测

来源:互联网 发布:mysql match against 编辑:程序博客网 时间:2024/05/16 17:37
  •  http://blog.csdn.net/yangxuan0261/article/details/65443673

思路

  • 科普下AB资源冗余,当然这里并不会详细说明,只会放个链接 点我 (需要科学上网)
  • 可以搜到大部分的文章都是在说一个 侑虎科技 的第三方检测平台,我也去上面检测了下正确检测出来,据说是免费几次后就需要付费。但是资源不加密就上传上去貌似不是很靠谱,资源大了上传也麻烦。所以就自己实现了一个检测。 
    • 检测的思路也很简单 
      1. 先用主AB生产一个所有 资源及所在AB 的一个 映射表
      2. 递归遍历打出来的包下的所有的AB,通过 AssetDatabase.GetDependencies 获取到 AB中资源名字在 AssetDatabase 中所有的依赖。(此时要求工程下Asset下有正常的资源)
      3. 遍历所有依赖,是否在 映射表 中,如果 不存在 且 超过两次,相同 资源A 被打进了两个AB中,而不是 资源A 打成一个AB,被其他AB依赖进去。
      4. 最后会收集到这些 不存在 且 超过两次 的资源名及被打进去的AB文件名,导出到一个md文件中,使用md编辑器查看(这里推荐个md客户端叫 Haroopad,平常都用这个写md)

源码 及 使用

  • 鉴于源码就一个cs文件,就不上传到git,直接这里贴了,同时也会上传几个测试的 源资源(test_res.rar)、打包出的 有冗余(ABoutput.rar)、无冗余(ABoutput_red.rar) 的资源
  • 使用:

    1. 分别解压出来,test_res目录放到工程Asset目录下(AssetDatabase才能找到资源,获取依赖),打包出的资源随意放(最好英文路径)
    2. 选择打包出的资源的主AB 
      这里写图片描述

      这里写图片描述

    3. 开始检测,有冗余会导出md文件 
      这里写图片描述

      这里写图片描述

  • 资源传送门:unity3d冗余测试资源.rar(csdn传了一天还在审查,放在百度盘,失效说声)

  • 源码:

    using System;using System.Collections.Generic;using System.Text;using UnityEngine;using UnityEditor;using System.IO;using System.Linq;class ABRedundancyChecker : EditorWindow{    class CRedAsset    {        public CRedAsset()        { }        public string mName = "";        public string mType = "";        public List<string> mUsers = new List<string>();    }    List<Type> mAssetTypeList = new List<Type> {        typeof(Material), typeof(Texture2D), typeof(AnimationClip), typeof(AudioClip), typeof(Sprite), typeof(Shader), typeof(Font), typeof(Mesh)    };    const string kABRedundencyDir = "/a_ABRedundency"; //输出文件的目录    const string kSearchPattern = "*.assetbundle";    string kResultPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + kABRedundencyDir;    //const string kABPath = "Assets/test_res/ABoutput_red";    //const string kManiFest = "ABoutput";    bool mIsForQ6 = false;    string mABPath = "D:\\svn_q6_app\\win64\\q6-v0.0.63.0\\q6_Data\\StreamingAssets\\resource";    string mMainAb = "resource";    List<string> mAllABFiles = null;    Dictionary<string, string> mAssetGenMap = null;    Dictionary<string, CRedAsset> mRedAssetMap = null;    float mCheckTime = 0f;    static ABRedundancyChecker mInstance = null;    public static ABRedundancyChecker Ins    {        get        {            if (mInstance == null)                mInstance = new ABRedundancyChecker();            return mInstance;        }    }    //[MenuItem("AB冗余检测/AB检测")]    ////[MenuItem("Q5/Bundle相关/Bundle冗余检测")]    //public static void Launch()    //{    //    ABRedundancyChecker.Ins.StartCheck();    //}    // 提供给其他脚本调用的接口    public void StartCheck(string path, string abName)    {        mABPath = path;        mMainAb = abName;        mIsForQ6 = true;        StartCheck();    }    void StartCheck()    {        EditorUtility.DisplayCancelableProgressBar("AB资源冗余检测中", "资源读取中......", 0f);        mCheckTime = UnityEngine.Time.realtimeSinceStartup;        if (mAllABFiles == null)            mAllABFiles = new List<string>();        if (mAssetGenMap == null)            mAssetGenMap = new Dictionary<string, string>();        if (mRedAssetMap == null)            mRedAssetMap = new Dictionary<string, CRedAsset>();        if (!GenAssetMap(mABPath, mMainAb))        {            EditorUtility.ClearProgressBar();            EditorUtility.DisplayDialog("错误", "请检查是否选择正确的AB资源", "Ok");            return;        }        GetAllFiles(mAllABFiles, mABPath, kSearchPattern);        int startIndex = 0;        EditorApplication.CallbackFunction myUpdate = null;        myUpdate = () =>        {            string file = mAllABFiles[startIndex];            AssetBundle ab = null;            try            {                ab = CreateABAdapter(file);                string[] arr = file.Split('/');                CheckABInfo(ab, arr[arr.Length - 1]);            }            catch (Exception e)            {                Debug.LogError("MyError:" + e.StackTrace);            }            finally            {                if (ab != null)                    ab.Unload(true);            }            bool isCancel = EditorUtility.DisplayCancelableProgressBar("AB资源冗余检测中", file, (float)startIndex / (float)mAllABFiles.Count);            startIndex++;            if (isCancel || startIndex >= mAllABFiles.Count)            {                EditorUtility.ClearProgressBar();                if (!isCancel)                {                    CullNotRed();                    mCheckTime = UnityEngine.Time.realtimeSinceStartup - mCheckTime;                    EditorUtility.DisplayDialog("AssetBundle资源冗余检测结果", Export(), "Ok");                }                mAllABFiles.Clear();                mAllABFiles = null;                mAssetGenMap.Clear();                mAssetGenMap = null;                mRedAssetMap.Clear();                mRedAssetMap = null;                Resources.UnloadUnusedAssets();                EditorUtility.UnloadUnusedAssetsImmediate();                GC.Collect();                EditorApplication.update -= myUpdate;                startIndex = 0;            }        };        EditorApplication.update += myUpdate;    }    //适配项目打包(有加密) 或 原生打包    AssetBundle CreateABAdapter(string path)    {        //if (mIsForQ6)        //    return UtilCommon.CreateBundleFromFile(path);        //else            return AssetBundle.LoadFromFile(path);    }    bool GenAssetMap(string path, string maniFest)    {        path = path.Replace("\\", "/");        AssetBundle maniFestAb = CreateABAdapter(System.IO.Path.Combine(path, maniFest));        if (maniFestAb == null)            return false;        AssetBundleManifest manifest = maniFestAb.LoadAsset<AssetBundleManifest>("AssetBundleManifest");        if (manifest == null)            return false;        string[] allBundles = manifest.GetAllAssetBundles();        maniFestAb.Unload(true);        foreach (string abName in allBundles)        {            string filePath = System.IO.Path.Combine(path, abName);            AssetBundle ab = CreateABAdapter(filePath);            foreach (string asset in ab.GetAllAssetNames())            {                mAssetGenMap.Add(asset.ToLower(), abName);            }            foreach (string asset in ab.GetAllScenePaths())            {                mAssetGenMap.Add(asset.ToLower(), abName);            }            ab.Unload(true);        }        if (mAssetGenMap.Count == 0)            return false;        return true;    }    void CheckABInfo(AssetBundle ab, string abName)    {        EditorSettings.serializationMode = SerializationMode.ForceText;        string[] names = ab.GetAllAssetNames();        string[] dependencies = AssetDatabase.GetDependencies(names);        string[] allDepen = dependencies.Length > 0 ? dependencies : names;        string currDep = "";        for (int i = 0; i < allDepen.Length; i++)        {            currDep = allDepen[i].ToLower();            CalcuDenpend(currDep, abName);            //UnityEngine.Object obj = ab.LoadAsset(currDep, typeof(UnityEngine.Object));            //if (obj != null)            //{            //    Debugger.Log("--- obj type:{0}", GetObjectType(obj));            //}        }    }    //todo: 待加入 类型    void CalcuDenpend(string depName, string abName)    {        if (depName.EndsWith(".cs"))            return;        if (!mAssetGenMap.ContainsKey(depName)) //不存在这个ab,记录一下        {            if (!mRedAssetMap.ContainsKey(depName))            {                CRedAsset ra = new CRedAsset();                ra.mName = depName;                ra.mType = "我了个去";                mRedAssetMap.Add(depName, ra);                ra.mUsers.Add(abName);            }            else            {                CRedAsset ra = mRedAssetMap[depName];                ra.mUsers.Add(abName);            }        }    }    // mRedAssetMap 中 CRedAsset 的 mUsers 只有一个的,视为不冗余的资源,直接打到了该 ab 中    void CullNotRed()    {        List<string> keys = new List<string>();        foreach (var item in mRedAssetMap)        {            if (item.Value.mUsers.Count == 1)                keys.Add(item.Key);        }        foreach (var value in keys)            mRedAssetMap.Remove(value);    }    List<string> GetAllFiles(List<string> files, string folder, string pattern)    {        folder = folder.Replace("\\", "/");        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(folder);        foreach (var file in dir.GetFiles(pattern))        {            files.Add((System.IO.Path.Combine(folder, file.Name).Replace("\\", "/")).ToLower());        }        foreach (var sub in dir.GetDirectories())        {            files = GetAllFiles(files, System.IO.Path.Combine(folder, sub.Name), pattern);        }        return files;    }    string GetObjectType(UnityEngine.Object obj)    {        string longType = obj.GetType().ToString();        string[] longTypeArr = longType.Split('.');        return longTypeArr[longTypeArr.Length - 1];    }    private string AppendSlash(string path)    {        if (path == null || path == "")            return "";        int idx = path.LastIndexOf('/');        if (idx == -1)            return path + "/";        if (idx == path.Length - 1)            return path;        return path + "/";    }    string Export()    {        if (mRedAssetMap.Count == 0)            return "未检查到有资源冗余";        List<CRedAsset> raList = mRedAssetMap.Values.ToList<CRedAsset>();        string currTime = System.DateTime.Now.ToString("yyyyMMdd_HHmmss");        string path = string.Format("{0}/{1}_{2}.md", kResultPath, "ABRedundency", currTime);        if (!System.IO.Directory.Exists(kResultPath))            System.IO.Directory.CreateDirectory(kResultPath);        using (FileStream fs = File.Create(path))        {            StringBuilder sb = new StringBuilder();            sb.Append(string.Format("## 资源总量:{0},冗余总量:{1},检测时间:{2},耗时:{3:F2}s\r\n---\r\n", mAllABFiles.Count, raList.Count, currTime, mCheckTime));            sb.Append("| 排序 | 资源名称 | 资源类型 | AB文件数量 | AB文件名 |\r\n");            sb.Append("|---|---|:---:|:---:|---|\r\n");            CRedAsset ra = null;            StringBuilder abNames = new StringBuilder();            raList.Sort((CRedAsset ra1, CRedAsset ra2) =>            {//排序优先级: ab文件个数 -> 名字                int ret = ra2.mUsers.Count.CompareTo(ra1.mUsers.Count);                if (ret == 0)                    ret = ra1.mName.CompareTo(ra2.mName);                return ret;            });            for (int i = 0; i < raList.Count; i++)            {                ra = raList[i];                foreach (var abName in ra.mUsers)                    abNames.Append(string.Format("**{0}**, ", abName));                //abNames.Append(string.Format("{0}<br>", abName)); //另一种使用换行                sb.Append(string.Format("| {0} | **{1}** | {2} | {3} | {4} |\r\n"                    , i + 1, ra.mName, ra.mType, ra.mUsers.Count, abNames.ToString()));                abNames.Length = 0;            }            byte[] info = new UTF8Encoding(true).GetBytes(sb.ToString());            fs.Write(info, 0, info.Length);        }        return "有冗余,导出结果:" + path.Replace("\\", "/");    }    //---------------- gui begin ------------    [MenuItem("AB冗余检测/AB检测")]    static void Init()    {        EditorWindow.GetWindow(typeof(ABRedundancyChecker), false, "AB资源冗余检测");    }    void Awake()    {        mInstance = this;    }    string mSelPath = "";    public void OnGUI()    {        EditorGUILayout.Space();        EditorGUILayout.LabelField("路径:", EditorStyles.boldLabel);        EditorGUILayout.Space();        GUILayout.Label(mSelPath);        EditorGUILayout.Space();        if (GUILayout.Button("选择主AB文件"))            mSelPath = EditorUtility.OpenFilePanelWithFilters("选择主AB文件", mSelPath, null);        EditorGUILayout.Space();        //mIsForQ6 = EditorGUILayout.Toggle("是否Q6(Q6有解密机制)", mIsForQ6);        EditorGUILayout.Space();        if (GUILayout.Button("开始检测"))        {            if (mSelPath == "")                EditorUtility.DisplayDialog("错误", "请先 选择主AB文件", "Ok");            else            {                mSelPath = mSelPath.Replace("\\", "/");                string[] arr = mSelPath.Split('/');                mMainAb = arr[arr.Length - 1];                mABPath = mSelPath.Substring(0, mSelPath.LastIndexOf('/'));                StartCheck();            }        }    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
原创粉丝点击