https://www.xuanyusong.com/archives/4607
AssetBundle.LoadFromMemory基本上是无法在手机上用的,因为要多占一份内存,所以大多Unity项目都不进行资源加密。
Unity2017.2提供了一个新的API AssetBundle.LoadFromStream,通过名字就可以知道它是流加载,那么就不会像AssetBundle.LoadFromMemory那样多占一份很大的内存了。
打包Assetbundle的同时生成加密文件的两个文件分别加载它。
myab.unity3d
encypt_myab.unity3d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[MenuItem("Tools/BuildAB")] static void BuildAB() { FileUtil.DeleteFileOrDirectory(Application.streamingAssetsPath); Directory.CreateDirectory(Application.streamingAssetsPath); var manifest = BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle, BuildTarget.iOS); foreach (var name in manifest.GetAllAssetBundles()) { var uniqueSalt = Encoding.UTF8.GetBytes(name); var data = File.ReadAllBytes(Path.Combine(Application.streamingAssetsPath, name)); using (var myStream = new MyStream(Path.Combine(Application.streamingAssetsPath, "encypt_" + name),FileMode.Create)) { myStream.Write(data, 0, data.Length); } } AssetDatabase.Refresh(); } |
这里测试的Assetbundle一共有20M, 使用LZ4压缩格式。
加密和解密我这里随便写个简单的异或 ^ 。后面也可以用一些更好的算法,总之加密可以慢,但是解密一定要快。
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 |
using System.IO; public class MyStream : FileStream { const byte KEY = 64; public MyStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync) : base(path, mode, access, share, bufferSize, useAsync) { } public MyStream(string path, FileMode mode) : base(path, mode) { } public override int Read(byte[] array, int offset, int count) { var index = base.Read(array, offset, count); for (int i = 0 ; i < array.Length; i++) { array[i] ^= KEY; } return index; } public override void Write(byte[] array, int offset, int count) { for (int i = 0; i < array.Length; i ++) { array[i] ^= KEY; } base.Write(array, offset, count); } } |
界面上放两个Image 分别加载它。
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 |
using System.IO; using UnityEngine; using UnityEngine.UI; public class TestStream : MonoBehaviour { [Header("是否启用Stream加载")] public bool isStream = true; float m_LoadTime ; void Start() { if (isStream) { float t = Time.realtimeSinceStartup; using (var fileStream = new MyStream(Application.streamingAssetsPath + "/encypt_myab.unity3d", FileMode.Open, FileAccess.Read, FileShare.None, 1024 * 4, false)) { var myLoadedAssetBundle = AssetBundle.LoadFromStream(fileStream); m_LoadTime = Time.realtimeSinceStartup - t; GetComponent<Image>().sprite = myLoadedAssetBundle.LoadAsset<Sprite>("1"); myLoadedAssetBundle.Unload(false); } } else { float t = Time.realtimeSinceStartup; var myLoadedAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/myab.unity3d"); m_LoadTime = Time.realtimeSinceStartup - t; GetComponent<Image>().sprite = myLoadedAssetBundle.LoadAsset<Sprite>("1"); myLoadedAssetBundle.Unload(false); } } private void OnGUI() { if (isStream) { GUILayout.Label(string.Format("<size=50>\nAssetBundle.LoadFromStream :{0} </size>", m_LoadTime)); } else { GUILayout.Label(string.Format("<size=50>AssetBundle.LoadFromFile :{0} </size>", m_LoadTime)); } } } |
如下图所示,在iPhone7上,基本上加载时间差不多。
加密以后资源就无法被打开了。
注意:Android下的streamingAssets目录不能使用,因为android下是放在jar里并不是文件系统。一定要用的话需要拷贝到 Application.persistentDataPath下。
原文地址:https://www.cnblogs.com/nafio/p/11811287.html