热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

unity打包的安卓无法解析_UnityAssetBundle热更新完整工作流与知识点解析

前言虽然这一块内容是比较基础的,但是知识点比较分散,所以我还是决定写一篇博客来记录梳理一下。环境:Unity2018.4.0参考文献Uni
5dc15237b1cd98676eb0dec99ef13330.png

前言

虽然这一块内容是比较基础的,但是知识点比较分散,所以我还是决定写一篇博客来记录梳理一下。

环境:Unity 2018.4.0

参考文献

Unity官方文档:[Unity User Manual (2019.2)](Unity User Manual (2019.2))

不会C++的码农知乎文章:[游侠:Unity 5.x AssetBundle零冗余解决方案](游侠:Unity 5.x AssetBundle零冗余解决方案)

AssetBundle相关知识

## 什么是AssetBundle?

一个AssetBundle可以当做一个文件集合,它包含了Unity可以在运行时加载的特定于平台的非代码资产(例如模型、纹理、预制组件、音频,甚至整个场景)。AssetBundle可以表示彼此之间的依赖关系;例如,一个AssetBundle中的material可以引用另一个AssetBundle中的texture。为了在减轻网络传输压力,您可以根据需求选择内置算法(LZMA和LZ4)来压缩AssetBundle。

AssetBundle对于可下载内容(DLC)、减少初始安装大小、加载针对最终用户平台优化的资产以及减少运行时内存压力都很有用。

## AssetBundle里有什么?

“AssetBundle”可以指两个不同但相关的东西。

首先是磁盘上的实际文件。这称为AssetBundle archive。AssetBundle archive是一个容器,就像一个文件夹一样,其中包含了额外的文件。这些额外的文件包括两类:

一个序列化文件,它包含您的资产分解成它们各自的对象并写入到这个文件中。

另一个是资源文件,这是二进制数据块单独存储的某些资产(纹理和音频),以允许Unity高效地在另一个线程从磁盘上加载他们。

“AssetBundle”也可以指通过代码与实际的AssetBundle对象交互,从特定的AssetBundle加载资产。这个对象包含了所有我们当初添加到包里面的内容。

## AssetBundle依赖与冗余介绍

Unity 5.x版本里提供了更加人性化的依赖自动管理机制——对指定打包的资源,Unity会自动收集并分析其依赖的资源,如果该资源依赖的某个资源没有被显式指定打包到ab中,就将其依赖的这个资源打包进该资源所在的ab里;如果已经被指定打包进其他ab里,那么这两个ab之间就会构成依赖关系,加载ab时,先加载其依赖的ab即可。

请避免ab循环依赖,比如a依赖b,b也依赖a,那么加载a的时候会去先加载a在b中的依赖资源,那么就得去加载b,加载b前又得去加载a,造成死循环。

这一套依赖管理机制使用方便的同时也会带来一个问题,如果两个ab A和B中的一些资源都依赖了一个没有被指定要打包的资源C,那么C就会同时被打进ab A和B中,造成资源的冗余,增大ab和安装包的体积。

至于处理这些问题的方法,大家可以自己去寻找。

## AssetBundle工作流

先来一张图

b4b7ac9c175cbee0f08958bc1280a948.png

### 打包AB

使用Unity打出AB包:[AssetBundle Workflow](AssetBundle Workflow)

压缩算法目前LZ4压缩方式天下第一(BuildAssetBundleOptions.ChunkBasedCompression)

### 加载AB

#### Unity中资源相关目录介绍

  • Resources:全部资源都会被压缩,转化成二进制。打包后该路径不存在,不可写也不可读。只能使用Resources.Load加载资源。
  • StreamingAssets:全部资源原封不动打包。在移动平台下,是只读的,不能写入数据,其他平台下可以使用System.File类进行读写。在`任意平台`都可以使用AssetBundle.LoadFromFile来从此文件夹读取加载ab包。

#### 资源相关路径介绍

  • Application.streamingAssetsPath:对应了StreamingAssets目录。安卓,PC平台WWW,UWR,AssetBundle.LoadFromFile对于streamingAssets里的文件访问直接用Application.streamingAssetsPath即可,苹果就用"file://{Application.streamingAssetsPath}"
  • Application.persistentDataPath:可读写目录,任意平台可以使用System.File库进行读写操作,WWW,UWR,AssetBundle.LoadFromFile更不在话下。移动平台可以使用"{Application.persistentDataPath}/{Application.productName}/"进行访问,非移动平台直接使用Application.persistentDataPath即可访问。注意如果移动平台使用UWR访问,需要加file://前缀。(官方什么时候把这些东西给统一好啊,开发者花费时间在这上面毫无意义)

#### 加载AB的API

  • AssetBundle.LoadFromFile(path):同步加载,path为本地路径
  • AssetBundle.LoadFromFileAsync(path):异步加载,path为本地路径
  • AssetBundle.LoadFromMemory(byte[] binary):从字节数组加载,binary为目标ab二进制流
  • AssetBundle.LoadFromMemoryAsync(byte[] binary):从字节数组异步加载,binary为目标ab二进制流
  • UnityWebRequest.GetAssetBundle(string uri):url为ab文件路径,可为本地,也可为云端,

### 从AB中加载具体的资产(Asset)API

  • assetBundle.LoadAsset(name):T为目标资产类型,name为资产名称,会返回一个T实例
  • assetBundle.LoadAsset(name,type):name为资产名,type为资产类型
  • assetBundle.LoadAllAssets():T为目标资产类型,会返回一个assetBundle中所有T类型资产数组
  • assetBundle.LoadAllAssets():加载assetBundle中所有资产,返回一个assetBundle中所有资产数组

### 卸载AB的API

  • assetbundle.Unload(bool unloadAllLoadedObjects):unloadAlLoadedlObjects:是否卸载所有加载的资源,参数为false时,AssetBundle内的文件内存镜像会被释放,实例化的物体还都保持完好。简单的说就是断开了AssetBundle内存镜像和实例之间的联系。如果再次实例化对象,也不会返回以前初例化过的AssetBundle内存镜像,而是重新实例化一个新的AssetBundle内存镜像,那么这样就出现了冗余,同样的资源,内存中会出现多份。参数为true时,卸载AssetBundle,并且删除被引用的资源。这种卸载方式,最为彻底,完全从内存移除,缺点是需要一套机制(目前流行的是引用计数),来关注是不是还有资源引用,会不会引起异常。
  • AssetBundle.UnloadAllAssetBundles(bool unloadAllObjects):unloadAllObjects:是否卸载所有加载的资源,如果为true,则会卸载所有资源,包括正在使用着(被依赖)的资源。,如果为false,则会卸载未被依赖的资源,被其他资源依赖的资源不会被卸载。

总结:AssetBundle.Unload(false)适用于一次性使用的资源,获得资源引用后直接调用,当删除引用后,下次调用Resources.UnloadUnusedAssets后就删除了。AssetBundle.Unload(true)在使用中,最好的做法是给创建出来的实例都添加计数,当计数不为0时,表示场景或代码中仍有引用,而当计数为0时,表示没有引用了,这样就可以AssetBundle.Unload(true)了。

# 资源热更新完整工作流

  1. 自己创建定义version.txt文件,此文件包含所有热更新信息,譬如`游戏版本号,资源版本号,ab包以及其manifast信息等`,譬如ab包名称,ab包大小,ab唯一标识符(hash码,比如md5值)等一系列需要与云端文件服务器进行对比的信息,设计好格式之后传送到文件资源服务器。
  2. 三方对比,将第一步的version.txt一式两份,本地StreamingAssets一份(或者不放也行,看自己怎么处理了),文件资源服务器一份,游戏首次运行,先下载文件资源服务器的version.txt,并保存到Application.persistentDataPath,然后会拿本地的Application.streamingAssetsPath下的version.txt与Application.persistentDataPath下的version.txt进行对比,记录差异文件,最后统一更新。之后每次进入游戏都会下载文件资源服务器的version.txt与Application.persistentDataPath中的version.txt进行对比,发现差异文件就会记录,然后更新具体ab和更改Application.persistentDataPath中的version.txt数据。更新完毕进入游戏。
  3. 资源解压缩,或许我们可以追求更高的网络传输性能,可以再次对准备上传到文件资源服务器的ab进行压缩,下载到本地时再进行解压,能节省更多文件服务器带宽和资源。

# 优秀AssetBundle框架推荐

或许我们并不想把过多的精力花费在这些底层的设计上,那么我们可以选择站在巨人的肩膀上。

GameFramework框架:[EllanJiang/UnityGameFramework](EllanJiang/UnityGameFramework "EllanJiang/UnityGameFramework")

xasset框架:[xasset/xasset](xasset/xasset "xasset/xasset")



推荐阅读
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • ASP.NET MVC中Area机制的实现与优化
    本文探讨了在ASP.NET MVC框架中,如何通过Area机制有效地组织和管理大规模应用程序的不同功能模块。通过合理的文件夹结构和命名规则,开发人员可以更高效地管理和扩展项目。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 深入解析JVM垃圾收集器
    本文基于《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版,详细探讨了JVM中不同类型的垃圾收集器及其工作原理。通过介绍各种垃圾收集器的特性和应用场景,帮助读者更好地理解和优化JVM内存管理。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 使用Python在SAE上开发新浪微博应用的初步探索
    最近重新审视了新浪云平台(SAE)提供的服务,发现其已支持Python开发。本文将详细介绍如何利用Django框架构建一个简单的新浪微博应用,并分享开发过程中的关键步骤。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 本题通过将每个矩形视为一个节点,根据其相对位置构建拓扑图,并利用深度优先搜索(DFS)或状态压缩动态规划(DP)求解最小涂色次数。本文详细解析了该问题的建模思路与算法实现。 ... [详细]
  • 在 Flutter 开发过程中,开发者经常会遇到 Widget 构造函数中的可选参数 Key。对于初学者来说,理解 Key 的作用和使用场景可能是一个挑战。本文将详细探讨 Key 的概念及其应用场景,并通过实例帮助你更好地掌握这一重要工具。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • 本文介绍如何使用 Python 提取和替换 .docx 文件中的图片。.docx 文件本质上是压缩文件,通过解压可以访问其中的图片资源。此外,我们还将探讨使用第三方库 docx 的方法来简化这一过程。 ... [详细]
author-avatar
canku
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有