热更配置和调试

在为原工程接入SOT之后(参考「 网站版 」),通过配置sotconfig.sh来控制生成能够热更的APP或者是生成补丁,本文介绍有哪些配置,并解释热更编译输出到控制台的信息,便于开发者遇到问题时解决问题。


1. sotconfig.sh

SDK的project-script目录下的sotconfig.sh,内容如下所示: ...

其中未注释的有2行变量,分别是:

  1. EnableSot : 是否启用SOT热更功能,默认为0,启用为1。如果为0,则APP编译跟原来没有区别,平时开发设为0即可,上架前改为1,然后重新编译项目,即可得到能用SOT热更的项目。设为1时,会生成代码记录文件到工程配置sotsaved目录下,用于之后比对代码生成补丁。
  2. GenerateSotShip : 控制是生成补丁还是只是进行热更编译。如果为0,则是热更编译。如果为1,则会去找项目sotsaved下的代码记录文件(就是上次值为0时热更编译生成的代码),用于跟现在的编译结果进行比对生成补丁。

强烈建议接入「 网站版 」体验一下。


2. 指定强制热更函数

SOT主要是通过比对代码生成补丁的,但也可以人为指定某些函数生成补丁。通过强制为某些函数生成补丁,让它运行在SOT虚拟机中来实现加固混淆,又或者是SOT自动比对出问题了等等,配置给了开发者手动指定的能力。

在sotconfig.sh内容里 可以看到类似xxxxxxxxxx_MODULENAME=("symbol1" "symbol2" "[\s\S]*"),意思是这条配置是针对MODULENAME的,这个就是当时在工程里配置的sotmodule的名字,例如ForceFixFunc_Inject_ShipOTDemo是针对ShipOTDemo的。

配置的("symbol1" "symbol2" "[\s\S]*")意思是它的值有3个,分别是symbol1, symbol2, [\s\S]*,它们需要用空格隔开,[\s\S]*是正则匹配的规则,意思是匹配所有的字符串。正则匹配用c++的regex库做的,需要参考这个库的正则语法。

下面解释几个module配置的用途:

  1. UnlinkSymbols : APP在EnableSot=0编译时没问题,但=1编译时报了链接符号失败的错误,可以用这个解决。例如ShipOTDemo这个Target在Link时报找不到xxxfunc符号,那么这里添加UnlinkSymbols_ShipOTDemo=("xxxfunc")即可。
  2. IgnoreSymbols : 直接无视这个函数或者全局变量,那么既不能热更它,也不能在热更代码里调用它或者访问它。
  3. ForceFixFunc_Inject : 在热更编译时(EnableSot=1,GenerateSotShip=0)将这个函数的代码删掉,只留下函数接口,一般可用于加固混淆,搭配下面的ForceFixFunc_Ship使用,编译时会在控制台输出log提示符合的函数名字。
  4. ForceFixFunc_Ship : 在生成补丁时(EnableSot=1,GenerateSotShip=1),强制为该函数生成补丁代码,编译时会在控制台输出log提示符合的函数名字。
  5. ForceNoFixFunc_Inject : 因为可以使用正则匹配,所以ForceFixFunc_Inject可能误伤一些函数,可以通过该配置剔除。
  6. ForceNoFixFunc_Ship : 因为可以使用正则匹配,所以ForceFixFunc_Ship可能误伤一些函数,可以通过该配置剔除。

例如想要加固混淆ShipOTDemo下命名开头为encrypt的函数,那么配置ForceFixFunc_Inject_ShipOTDemo=("encrypt[\s\S]*")ForceFixFunc_Ship_ShipOTDemo=("encrypt[\s\S]*"),那么就可以了。假如发现误伤了函数encrypt_abc,不想加固它,第一种办法是修改正则语法,第二种办法是增加配置ForceNoFixFunc_Inject_ShipOTDemo=("encrypt_abc")ForceNoFixFunc_Ship_ShipOTDemo=("encrypt_abc")


3. 文件白名单和黑名单

在默认情况下,SOT会把整个Target的代码文件都加入到热更编译中,但有的用户可能不想将某些文件加入热更编译,因为他知道这些文件的代码不会有Bug,并且未来也不打算修改里面的代码,所以将它们剔除也不会影响项目的热更。同时因为剔除了它们,SOT的编译速度也会变快,包体增大的程度也会减小。

从1.13版本开始,增加了白名单和黑名单的机制,用来精确控制哪些文件被加入热更编译,它们在sotconfig.sh文件中配置。 ...

默认是注释掉的,把前面的#去掉即可启用。WhiteList_MODULENAME是白名单,BlackList_MODULENAME是黑名单,启用时把MODULENAME改成真正的Target的名字,也就是配置编译时添加的-sotmudole后的名字,例如配置的是-sotmodule Demo,那么使用白名单就改成WhiteList_Demo。

=后面就是添加文件名列表,不用包含路径,只是文件名,也不要填写后缀名,例如文件完整路径是/User/xxx/project/abc.swift,那么这里填"abc"就可以了,多个文件名用空格隔开。

启用白名单意思是只把该列表里的文件加入到SOT热更编译。黑名单意思是列表里的文件不加入SOT编译,别的都加入SOT热更编译。两种模式只能启用其中一种,同时启用的情况下,只有白名单配置是生效的。

这个配置在热更注入和生成补丁时要保持一致,否则将会生成错误的补丁。

另外需要强调的是,生成补丁时如果使用了一些类或者变量,但这些类或者变量之前没在热更编译的文件中使用过,例如被黑名单剔除了,那么补丁也是无法访问,生成会报错。

为了方便大家快速枚举某个文件夹下所有的源文件的文件名,写了一个脚本,放在SDK目录/project-script/find_all_files.sh。使用方式就是在Terminal中调用sh SDK目录/project-script/find_all_files.sh 代码目录路径,就会打印该代码目录中所有源文件名字,然后复制到白名单或者黑名单配置里就可以了。例如: ...

然后添加到sotconfig.sh里即可: ...


编译控制台输出说明

启用EnableSot=1时,Xcode编译时,控制台会输出额外的信息,当出现问题时,开发者可以通过这些信息定位问题。


1. 源文件编译日志

被热更的Target的.m或者.mm文件,它们编译输出日志里会有run sot clang compile字样,说明成功使用了SOT编译工具,对这些文件进行热更编译了。 Swift文件则有run sot swift compile for module字样。


2. 链接日志

热更编译的信息主要出现在链接日志里,每个Target都有对应的一个链接日志,如下图的ShipOTDemo Target: ...

展开后有非常多的信息,首先是生成补丁(ship)的信息,如下图: ...

每个条目的意义如下:

  1. 说明接下来的日志是生成补丁的日志
  2. 加入了黑名单的符号,如本例是got开头的符号都被忽略了,用上面介绍的UnlinkSymbols配置
  3. 被替换的函数的名字,是mangle后的名字,本例没有,所以是0
  4. 新增的函数的名字,是mangle后的名字,本例没有,所以是0
  5. 补丁引用到原来APP的全局变量的名字,是mangle后的名字,本例没有,所以是0
  6. 补丁新增的全局变量的名字,是mangle后的名字,本例没有,所以是0
  7. 补丁是基于这个版本的代码生成的,就是保存在sotsaved的代码的hash,用于校验补丁是否是合法有效的,当修改了原始代码时,这个hash通常会变

然后是热更注入的信息,如下图: ... ...

每个条目的意义如下:

  1. 说明接下来的日志是热更注入的日志
  2. 正在进行热更注入的文件名
  3. 该文件下的这些函数可以被替换
  4. 该文件下的这些全局变量可以被补丁访问