热更细节流程
## 热更细节流程
此流程基于UnityAndroidIl2cppPatch整包热更方案。
为了避免混淆,交流时和写代码时,应尽量保持这些术语一致:
- 热更 = Patch = 支持代码更新的整包热更
- 强更 = APK包重新下载并安装
- AB包更新 = 资源更新 = 仅涉及部分资源不涉及代码的AssetBundle更新
### 版本号定义和管理
1. 显示版本号:即带“.”的版本号,例如6.9.1,原则上只应用于简化显示,不用此值来进行任何版本更新相关的判定。此值由BaseVersion和PatchVersion组成,例如BaseVersion=691000,PatchVersion=701000,怎么界面上显示的版本号为7.0.1(6.9.1),表示当前版本内容是7.0.1,但是包体版本是6.9.1;如果没有PatchVersion,则显示逻辑跟以前一样为6.9.1。如果以后升多了一位数,例如到了1012000,那么显示版本号格式为10.1.2;
2. BaseVersion:即APK包的VersionCode,例如691000,所有版本判断相关的逻辑都会使用此值进行;
3. PatchVersion:即当前热更包的目标版本,例如一个从691000升级到701000的热更包,其PatchVersion为701000,保存在热更文件内;
4. CompleteVersion:完整版本号,用于最终判断一个APK包是否为最新版本,使用`max(BaseVersion, PatchVersion)`计算得出,用于跟当前Server上的最新版本号进行比较;
5. ServerVersion:即当前服务器最新的版本号,在VersionXML(例如com.bairimeng.dmmdzz.xml)的bundleVersionCode里描述;
5. 如果客户端的CompleteVersion小于ServerVersion,则会发生热更或强更行为;
6. 客户端的CompleteVersion可能会大于ServerVersion,此时不会发生降级更新行为,仍然认为客户端是最新的;
7. 所有后台数据上报时(例如Bugly等)用的版本号,如果只能有一个,则使用CompleteVersion;如果可以附带额外的分类标签,则附加上BaseVersion;
### 客户端更新加载流程
1. 启动时,在Loading界面,拉取服务器上的`VersionXML`文件,检查是否要进行更新。如果客户端的CompleteVersion小于ServerVersion,则:
- 检查是否存在从当前BaseVersion到ServerVersion的热更包;
- 如果存在,则下载热更包,并保存在本地目录`DirectoryTemp`;
- 如果不存在,则进行强更,跳过后续热更流程;
2. 下载热更包完成后,根据`VersionXML`里的配置开关,决定是自动重启Activity,还是弹提示让玩家自己手动重新启动App(作为一种Fallback保护机制);
3. 重启后,在Unity启动前,Java层检查目录`DirectoryTemp`里是否有热更文件,并且其PatchVersion是否大于目录`DirectoryPatch`里的已有热更文件:
- 如果大于,则清除`DirectoryPatch`里的热更文件,并把`DirectoryTemp`里的热更文件复制到`DirectoryPatch`下;
- 如果小于或等于,则忽略;
4. 进入Unity加载流程,如果`DirectoryPatch`里有热更文件,则进入Patch加载流程,否则正常加载;

==注意实现时,要留意每个流程节点里可能出现的意外问题,例如下载过程中退出后台、下载文件损坏、空间不够等问题。==
### 热更包打包和上传流程
目前热更版本采用【直升】的机制,例如如果当前是1.3版本,那么1.0老版本直接会下载从1.0=>1.3的热更包,跳过中间的版本,而不用从下载从1.0=>1.1,1.1=>1.2,1.2=>1.3的多个增量升级包,这样便于管理,并减少开发出错的概率,但会增加需要维护的热更包的数量,让每个新版本都需要生成对以往多个基准版本的热更包,CDN文件数会多一些,但综合来说成本应该可控。
> 注意现网1.0老版本,热更到最新的1.3版本后,其基准版本号BaseVersion依然是1.0,而不是1.3。其它1.1,1.2版本同理。只是内容版本更新到了1.3。
==前期测试阶段,可以只向前兼容1个热更版本,打包和上传流程自动化以后,希望能扩展到5个左右。==
> 由于很多渠道支持后台自动更新,因此根据经验数据,当上传了新包后,2周内新版本能自然扩散到大部分玩家;因此即便我们每2周一个版本,5个周期以后,依然还在使用最老的基准版本的玩家数应该可以忽略不计,因此前向兼容5个版本的热更功能预期能满足需求,但最终还需要看实际的版本扩散数据来决定;
更老的版本依然采用强更的方式升级。另外如果U3D升级,或者底层有大的改动,也会触发强制更新。
==一个热更包包含两部分:SO代码和资源文件,其中资源文件对每个渠道应该是一样的,SO代码是不一样的。热更包文件名里要包含对应的BaseVersion和PatchVersion信息==
因此不同渠道的热更包,可以共享同样的资源热更文件,以节省维护成本。
每次版本发布时,对原来流程影响有:
1. 如果热更包很小,小于50MB,可以不用走新APK包上传到渠道商店的流程,以减少现网基准包的数量;
2. 对每个渠道的新包,以及最近的N个版本的历史渠道包,生成对应的N个热更包;
2. 如果渠道数量为X,那么最终的热更包会有X*N个,为了减少文件大小,同一个版本的不同渠道的热更包,里面的资源文件应该是一样的,所以可以共用;但SO文件不行,仍需要分渠道下载;
3. 将这些热更包文件,上传到CDN上;
4. 预配置好`VersionXML`文件,针对每个渠道配好对应的热更包版本和地址;
5. 真机测试热更流程;
6. 在版本发布出去后,才能把CDN上老的热更文件清除,以节省空间,千万不要提前删;
### 自测用例
|测试用例|预期结果|
|-|-|
|测试每一个支持热更的Base版本的热更新|每个老版本都能更新成功|
|测试不支持热更的版本的强更升级逻辑|走以前的强更逻辑更新|
|测试下载热更文件或解压时退到后台,再回来|继续下载或解压|
|测试下载热更文件时杀掉进程,再启动|重新下载热更文件|
|测试在解压热更文件时杀掉进程,再启动|不用重新下载文件,直接解压|
|手动故意损坏热更文件,再启动|重新下载热更文件并解压|
|磁盘空间空间不够|弹出提示,让用户清理空间再重新启动游戏
|使用新的整APK包,但手动放入一个老版本的热更文件|不加载老的热更文件内容,而加载原生APK里的内容,并删除掉老的热更文件|
|假设热更加载逻辑在现网出现大面积崩溃,玩家无法进游戏|通过控制version.xml可以强制屏蔽掉所有热更逻辑,走老的强更逻辑|
### 附录
另外一种热更包管理的方式是:采用非直升,而是增量升级的机制:[https://blog.csdn.net/bdalasja/article/details/95622429](https://blog.csdn.net/bdalasja/article/details/95622429
)
但我们不采用这种方式,是因为:
1. 实现比较复杂,容易出错;
2. 使此方法,对上传到渠道后台的包有要求:例如当前打出了一个完整的1.3版本APK包,但发布到渠道时不能直接上传这个完整的包,而必须是1.0+0.3的合成包,因为只有这样后续才能继续热更升级到1.4。因为在文件数据层面,1.0+0.3的合成包,跟1.3版本的完整包,其实是不一样的,虽然内容都是1.3版本。
3. 而采用1.0+0.3合成包的方式,在热更资源管理没优化好的前提下,会极大增加包体大小(基本会翻倍),同时会增加一个生成合成包的流程;
4. 综合以上原因,考虑到其带来的唯一好处是减少需要生成和上传到CDN上的热更文件数量,从X*N减少到X,而这个问题可以通过自动化工具解决,所以不采用这种方式;