内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据,常用于页面置换算法,是为虚拟页式存储管理服务的。
一、基础
- 关于appstore禁用热更新的通知
1 | Dear Developer,In March of this year we notified you that your app contains code |
翻译过来也没太大意思,根据大部分开发者的反应以及官方的说法,appstore此次禁用的主要是几种热更新框架和技术,如dlopen、dlsym、respondingToSelector、 performSelector、method_exchangeImplementationsd、JSPatch等,做过app开发的同学应该都知道,通过远程下载的脚本使用这些函数进而改变app行为,显然与appstore的封闭、安全等理念相违背(相信这也是大部分果粉选择ios的原因)。
JSPatch的原理是开发者编写
JavaScript
代码,通过使用苹果内置的JavaScriptCore.Framework
来执行以实现热更新功能,通俗的理解就是JSPatch
为所有的Objective-C
的API
进行了映射,允许开发者在JS
端调用任意原生代码,显然这是危险的。
- 热更新技术
热更新简而言之就是在服务器不关闭的情况下,用户打开应用即可下载更新代码运行,这是目前移动游戏更新的主流方式之一。
那么为什么苹果没有禁用游戏的热更新呢?
游戏热更新主要的实现方式是把动态脚本(如Python、Lua等运行时动态解释执行)下载之后,让动态脚本调用游戏引擎提供的接口实现bug修复、UI/策略/玩法更新等。与JSPatch不同的是,动态脚本并不能任意调用全部原生代码,而是只能根据游戏引擎提供的接口调用相关功能。在这个过程中,游戏引擎的原生端作为一个安全沙箱,提供了一个安全的保护层,只要游戏引擎不要对外提供获取通讯录等接口,黑客就无法通过替换动态脚本的方式获取用户相关隐私资料,进而可以被认为是安全的,自然不在苹果的禁止范围内。
- app的组成,从方便理解的角度去看,可以将整个app拆成两个部分:
- 基础部分:底层的、不经常变动的部分。
- 业务部分:基于基础部分之上变动频繁的部分。
通常基础部分是无法热更新的,如果要修改这部分就得重新打包制作安装包(如安卓的apk/ios的ipa)给应用商店。而业务部分则是可以被热更新的,而通常负责业务部分热更新功能的正是基础部分。对于很多游戏来说,通常会把javascript、lua、python等这些脚本语言代码放在业务部分,这样一来游戏中的绝大部分业务内容就都可以实时更新了。
APK,即Android应用程序包(
Android application package
),它是Android
操作系统使用的一种应用程序包文件格式,用于分发和安装移动应用及中间件。一个Android应用程序的代码想要在Android设备上运行,必须先进行编译,然后被打包成为一个被Android系统所能识别的文件才可以被运行,而这种能被Android系统识别并运行的文件格式便是APK。 一个APK文件内包含被编译的代码文件(.dex 文件),文件资源(resources), assets,证书(certificates),和清单文件(manifest file)。
IPA后缀的文件是iOS系统的软件包,全称为iPhone application archive。通常情况下,IPA文件都是使用苹果公司的FairPlayDRM技术进行加密保护的。每个IPA文件都是ARM架构的可执行文件以及该应用的资源文件的打包文件,只能安装在iPhone,iPod Touch或iPad上。该文件可以通过修改后缀名为zip后,进行解压缩,查看其软件包中的内容。
二、一次热更新过程
- 快速开发一个游戏app并编译成一个安装包(如apk)上架,我们把这种完整的安装包称为母包。为了方便描述,我们把这个母包称为母包1,这时候的客户端版本,记作1.0。
1 | ## 基础部分 |
比方说我们的母包1包含了这么些东西,然后我们把这个1.0客户端给放在了应用商店,提供给用户下载使用。
- 游戏app的特点就是快,热门的游戏一般每周都会发版本(其中可能有bug修复、玩法升级等)。比如我们这次新加了玩法以及新手引导(修改1.mp4,增加4.lua),客户端版本记为1.1,包含的内容如下:
1 | ## 基础部分 |
我们在1.0版本的基础上,修改了一个文件又增加了一个文件。这时候我们希望玩家的游戏都同步到这个新版本来,改该怎么办呢?最传统的方法就是我再编译一个安装包,扔给应用商店。但是这样做就有问题了,比如说一个安装包有10G,但是就修改了10kb的内容,每次更新完后都让玩家下载10个G的安装包,这显然是不合理的。这时候,就该补丁包出场了。
我们制作了一个补丁包,它包含此次修改的文件和增加的文件,然后放在我们的服务器上。玩家进入游戏后的会自动下载这个补丁文件(具体实现不同的游戏有不同的实现方式,大体就是检查当前客户端的版本号和服务器上的版本号,通过对比差异来进行更新),下载完成后把这两个改动的文件更新到原来的客户端中(脚本语言解释执行),这样一来玩家手里的客户端就是今天的最新版本了。
1 | ## 补丁1 |
- 下周版本又修改了一些内容(增加5.lua),版本记为1.2,内容如下:
1 | ## 基础部分 |
现在想把这个最新版本同步更新给玩家,需要再打个补丁包叫
补丁2
,此时有两种方式
方式1:把相对于
1.0
版本的所有变动内容都放在补丁2中,即版本1.2 = 母包1.0 + 始终最新版本的一个补丁
,补丁2内容如下:1
2
31.mp4
4.lua
5.lua方式2:在补丁1(版本1.1)的基础上,制作补丁2(版本1.2),即
版本1.2 = 母包1.0 + 补丁1 + 补丁2(依次)
,补丁2内容如下:1
5.lua
- 继上个版本1.2之后,此次没有修改任何东西但重新编译了一个安装包,记作母包2,版本记为2.0,包含内容如下:
1 | ## 基础部分 |
母包2
中的内容和母包1加两补丁的1.2
版本的内容是一模一样的。这时候把母包2放在应用商店中给新来的用户下载,那么下载了母包2的用户打开就直接能玩了,不需要再下载补丁来更新客户端。与此同时,之前下载了我们母包1并且通过补丁更新到1.2版本的玩家,也不需要重新去下载一个母包2就可以获得一致的游戏内容。