AssetBundle的基本概念和优势我就略过了,网上一搜索很多这方面知识,无非是便于更新,资源管理和控制项目大小。
按流程先后说明一下相关知识:
标记:
目前主要分手动标记和代码标记,手动标记就是在Inspector面板手动选择AssetLabels里的AssetBundle名和后缀名,代码标记就是通过
importer.assetBundleVariant
importer.assetBundleName
importer.SetAssetBundleNameAndVariant(ABName, variant);
这三个API标记BundleName和Variant的,其中importer是通过AssetImporter.GetAtPath(string)得到,string是待标记的预制物路径。
对于代码标记,有个好东西AssetDatabase.GetDependencies(new string[] { PrefabPath }),这玩意可以找到某个预制物关联的所有物品,比如要将某个预制物和该预制物材质、贴图、shader分开打包,可以通过GetDependencies找到该预制物用过的各种关联物品路径,然后通过后缀(.prefab/.materal/.png/.fax)分类标记。
一般来讲都是把代码标记写在编辑器里,选择文件以后代码不断遍历文件的子文件如果是非文件格式则以文件名标记。如果按这种方式需要对项目的结构把控的很严格。
打包:
打包预制物主要靠
BuildPipeline.BuildAssetBundles(Path,BuildAssetBundleOptions,BuildTarget)
这个API,第一个参数是bundle的输出路径,第二个参数BuildAssetBundleOptions资源包编译选项,https://blog.csdn.net/AnYuanLzh/article/details/81485762这个写的很详细,第三个参数BuildTarget主要是选择平台。
BuildPipeline.BuildAssetBundles还有一个重载,多了一个预制物路径参数,主要是用于单独打包该路径的某个预制物,但是个人不是很推荐用在正式项目里,因为单独打包很有可能会不小心把之前已经打包的物品重新打进单独包里,造成资源的重复。如果后期需要单独加资源又不想把已经打过的包再打一遍,建议用增量打包,增量打包会根据Manifest只打包改动或者新增的包。
场景打包和预制物打包用的API不同,主要是靠
BuildPipeline.BuildPlayer(new string[] {"Assets/AssetBundle.unity"},"Scene.unity3d", BuildTarget.StandaloneWindows, BuildOptions.None)
这个API,第一个参数需要打包的场景名字,第二个是场景路径,第三第四和之前一样,只不过倒过来了。
这里介绍个官方打包插件Asset Bundle Browser,这个翻译过的官方文档讲的很详细:https://www.cnblogs.com/hearthstone/p/8478530.html
增量打包:
第一次打包是彻底打包,接着再进行打包是增量打包,此时会通过计算manifest文件的依赖关系和文件哈希值,来确定这次打包对于上次打包作出的改变。然后只会对做出改变的那部分进行打包,未改变的则不打包,这样可以极大地减少打包时间。打包时最好选上BuildAssetBundleOptions.DeterministicAssetBundle,这样可以使每次不变资源打包出来的哈希值一致,从而使增量计算更精确。
依赖:
打成依赖包的好处就是可以避免把同个资源打进不同的包以减少包体积,缺点就是把包分细了关系过于复杂,管理起来有点麻烦。其实依赖的本质还是标记,详细以后补上。
加密:
目前在网上找到了三种加密方式:
按安全性先后排序:
一、把AB包转成byte[],对byte[]中的每一位执行异或或者别的加密,然后再将新的byte[]重新写入文件中。
详细方法链接:https://blog.csdn.net/wangjiangrong/article/details/89671861
这个方案好处是安全性强,缺点是读取的时候得通过AssetBundle.LoadFromMemory从内存读取,效率极慢,而且占用双倍内存。此方法我觉得加密的代价太过巨大,得不偿失。
二、通过文件流加密和LoadFromStream流读取
详细方法链接:http://www.xuanyusong.com/archives/4607
这个方案安全性我觉得也还不错,读取速度和LoadFromFile区别不大,但是LoadFromStream占用内存会大点,而且在安卓上好像会存在一些问题,具体问题这个人好像讲了一点:https://www.jianshu.com/p/be59dbe2ff31。
三、通过LoadFromFile的第三个参数offset进行加密
详细方法链接:https://blog.uwa4d.com/archives/USparkle_AssetBundle.html
这个方案我感觉有点投机取巧,不确定有人真的会用这个方案,但是读取速度和占用内存应该是所有加密方案里最好的吧。
之前我在腾讯技术员的一个问答里听到,目前没有完美的加密方案,技术牛逼的人要破解的话,无论如何都能破的,与其牺牲用户体验去加密,不如不加密或者只防范小白用户。这应该是目前的主流思想了。
压缩:
unity内置的压缩方式主要是LZMA和LZ4压缩,当然也可以不用他的自己在外部再压缩一遍。
LZMA:默认压缩方式,只要不选BuildAssetBundleOptions.ChunkBasedCompression就是按LZMA压缩,优点是读取快,缺点是占用的容量大。
LZ4:通过BuildAssetBundleOptions.ChunkBasedCompression 选取,优点是占用的容量小,缺点是读取慢,不过据说LZ4是分块压缩,要读取某个文件的话只读取压缩了该文件的块,并不会整个一起读取,所以我感觉读取时的占用内存应该会小点。
载入:
正常流程是先载入AB包及AB包的依赖包(unity高版本AB包和AB依赖包载入顺序可以无视),然后再从AB包载入具体资源。
载入AB包主要有以下几种方式:
AssetBundle.LoadFromFile
AssetBundle.LoadFromMemory
AssetBundle.LoadFromStream
WWW
LoadFromCacheOrDownload
详细区别以后再补上
然后可以通过
AssetBundleManifest manifest = (AssetBundleManifest)assetBundleManifest.LoadAsset("AssetBundleManifest");
manifest.GetAllDependencies(FilePureName)//获取所有依赖包,也就是依赖包的依赖包也能获取
或者manifest.GetDirectDependencies(FilePureName)//获取直接依赖包,就是manifest 文件记录的依赖包
这些API获取依赖包名,再逐个加载依赖包。
加载场景是直接加载场景包和场景依赖包进内存,然后通过普通的场景加载API
SceneManager.LoadSceneAsync("SceneName")
就行了,有点神奇。
剩下的部分以后再补上-----------------------------------------------------------------------------------------------------------------------------------------
卸载:
遇到的坑: