本文介绍如何接入SOT的网站版SDK,接入后即可使用本网站来管理补丁的分发,无需再自己搭建服务器。网站每月免费赠送价值100元的补丁流量,可以满足月活百万的App使用了。
接入SOT热更新,需要对编译工具和流程做一些改变,虽然门槛较高,但只需要做一次即可。教程使用的是x86 cpu架构的Mac电脑,并且用模拟器进行测试。M1的电脑无法使用模拟器测试,但可以直接测试真机。使用的Xcode版本为14.3.1,以示例工程「 ShipOTDemo 」为例。工程有两个分支,读者可以用main分支,然后跟随本篇教程,一步步接入。sot是配置好的分支,只需要下载解压SDK到项目根目录,并安装SDK,就可以测试SOT热更新。
这是一个很简单的工程,仅仅为了演示如何接入SDK,下载工程后,Xcode14直接打开应该就能编译成功和运行:
「 下载SOT的SDK 」,请用1.16及以上版本,解压到示例工程的目录中:
先运行一下xcode-select --install
安装xcode命令行工具,然后运行
sudo xcode-select --switch Xcode.app的路径
,把”xcode.app的路径“改成你mac上的xcode的路径,例如我的是/Applications/Xcode.app。
在terminal运行命令:sudo sh /Applications/ShipOTDemo/sotsdk/compile-script/install.sh
, 会把SDK目录compile-script下的clang, libtool, swift等脚本安装到本地编译工具链里,需要输入root密码。/Applications/ShipOTDemo/是我放工程的目录,你按照自己的目录来。
可以自己检查一下是否安装成功,命令行运行:xcrun --find sot_link.sh
,例如我的会得到结果
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sot_link.sh,进入到该目录还能看到其余安装进去的脚本:
修改编译工具链不会影响正常项目的编译,假如不想接入SOT SDK了,要完全恢复原状,运行compile-script下的uninstall.sh就行。如在命令行输入sudo sh /Applications/ShipOTDemo/sotsdk/compile-script/uninstall.sh
。
注意,即使有多个项目接入SOT,也只有第一次需要运行install.sh脚本,不用每个工程都运行。
增加1个Configuration,只有切换到这个Configuration才使用SOT编译模式。这样我们平时还是用原来的Configuration做开发,等到真正要出包给到商店时,才切换到SOT编译模式,对项目影响达到最小,添加的步骤如下:
选中ShipOTDemo Project,然后选择Info面板,点击Configurations的下面加号,复制Release的编译配置,并且命名为SotRelease,别的名字也可以,但注意名字都不要留有空格:
加完就是:
注意:本例只有此处需要添加,但如果你应用到自己项目中时,需要把所有的Project都加上这个Configuration,否则编译会报找不到文件等等的错误。所以加完这个Configuration之后,就马上去Edit Scheme切换一下,然后Build和Run一下,看是否有编译错误。
如果没有编译错误,正常运行的话,再进行后面的操作。如果有错误,请检查是否漏了一些工程没有添加上。
添加热更需要的编译选项,添加SOT虚拟机静态库等,步骤如下:
-sotmodule $(PRODUCT_NAME) $(SRCROOT)/sotsdk/libs/libsot_web.a -sotsaved $(SRCROOT)/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
每个选项的意义如下:
sotsdk/libs/libsot_web.a
是SOT虚拟机静态库的路径,链接的是网站版的虚拟机-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
,意义跟上一步是一样的,需要保持一致。
如果这个Target有Swift代码,在Active Compilation Conditions的SotRelease下添加sotmodule=$(PRODUCT_NAME) sotconfig="$(SRCROOT)/sotsdk/project-script/sotconfig.sh"
目前还不支持m1芯片的模拟器,所以需要排除模拟器的arm64架构,或者把Build Active Architecture Only改为Yes
在Preprocessor Macros添加USE_SOT=1
,后面用来控制是否编译调用SDK的代码
选中SwiftTest Target,把它的Mach-O Type改为Static Library(推荐静态库热更比较好,动态库也可以,但需要每个动态库都需单独链接libsot)。
静态库容易很多,重复跟ShipOTDemo差不多的步骤设置:
-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
sotmodule=$(PRODUCT_NAME) sotconfig="$(SRCROOT)/sotsdk/project-script/sotconfig.sh"
-sotmodule $(PRODUCT_NAME) -sotsaved $(SRCROOT)/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
。
SDK里提供了一个便利脚本,可以sdk目录里找到的project-script/sot_package.sh,它会把生成的补丁拷贝到Bundle文件夹下,方便我们找到它上传到网站。需要在每次SotRelease编译时调用这个脚本,按下面步骤添加:
脚本内容为:
if [[ "$CONFIGURATION" == "SotRelease" ]];then
sh "$SOURCE_ROOT/sotsdk/project-script/sot_package.sh" "$SOURCE_ROOT/sotsdk/project-script/sotconfig.sh" "$SOURCE_ROOT/sotsaved/$CONFIGURATION" ShipOTDemo SwiftTest
fi
可以注意到脚本里有两个参数,分别是ShipOTDemo和SwiftTest,这个是跟前面添加的Other C Flags里面的-sotmodule $(PRODUCT_NAME)对应的,因为$(PRODUCT_NAME)在这里会被Xcode替换成ShipOTDemo和SwiftTest,所以才能对应上了。如果是你自己的项目,这里要改成对应的名字。
并且把Based on dependency analysis的勾去掉,确保每次编译都会调用。
链接libz.tbd
和libc++.tbd
还是在这个页面下,打开Link Binary With Libraries页,加入下面这两个库
需要提前在代码里增加调用补丁同步API的代码:
打开ViewController.m文件,先增加引用SOT网站服务API的头文件的代码:
#ifdef USE_SOT #import "../sotsdk/libs/SotWebService.h" #endif
然后再在下面的函数SotUpdate添加下面的代码:
#ifdef USE_SOT SotApplyCachedResult ApplyShipResult = [SotWebService ApplyCachedAndPullShip:version_key_str is_dev:false cb:^(SotDownloadScriptStatus status) { if(status == SotScriptShipAlreadyNewest) { NSLog(@"SyncOnly SotScriptShipAlreadyNewest"); } else if(status == SotScriptShipHasSyncNewer) { NSLog(@"SyncOnly SotScriœœptShipHasSyncNewer"); } else if(status == SotScriptShipDisable) { NSLog(@"SyncOnly SotScriptShipDisable"); } else { NSLog(@"SyncOnly SotScriptStatusFailure"); } }]; if(ApplyShipResult.Success) { if(ApplyShipResult.ShipMD5) NSLog(@"sot success apply cached ship md5:%@", ApplyShipResult.ShipMD5); } #endif
这段代码用一个version_key_str做为唯一的Key向网站拉取补丁,如果拉取成功会把补丁保存下来,下次再调用该API时便能加载这个补丁。在这个示例程序中,version_key_str是通过一个文字输入控件获取的,后面会介绍如何在网站注册,然后获得VersionKey,等启动程序后输入到输入框里,就可以进行补丁拉取。
具体调用的是ApplyCachedAndPullShip这个API,补丁的同步需要考虑网络延迟等问题,可以看「 同步补丁API 」的解释。
如果是用户自己的程序,在网站获得了VersionKey之后,调用API的代码直接写死对应的VersionKey就可以了,本文这里只是为了演示。
按上面配置完之后,还需要控制sotconfig.sh的开关,否则编译出来的APP是无法热更的,SOT热更流程分为两部分,一部分是热更注入,一部分是生成补丁。
打开sotconfig.sh,文件在sotsdk/project-script目录下,里面有两个开关,EnableSot和GenerateSotShip:
此时去看构建日志,能看到很多SOT输出的信息:
切记如果是自己的APP,要打包发商店,打包是Archive要切换到SotRelease,本文只是测试,不用改这一步也可以:
按上一步编译成功后,运行APP,点击Run按钮,看到输出的是hello SOT:
接下来通过生成补丁,把hello SOT改成其它字。
运行APP,点击Run按钮,看到输出的是hello SOT。
此时把刚才在网站得到的VersionKey填入上面的控件中,并且点击Sot Sync按钮。
会在Xcode控制台得到类似下面的输出,意思是同步到了最新的补丁。
再点一次Sot Sync按钮,就会加载刚才下载好的补丁,并且会再次去同步补丁。
这时候去点击Run按钮,就得到了新的输出,
下次再打开APP,第一次点击Sot Sync按钮就会成功加载补丁,因为补丁被缓存了下来。如果接下来同步到最新的补丁,就会把缓存的补丁替换掉。
不是所有新加的代码都能够生效,举个例子来说,如果调用了老代码没有调用过的函数,就可能不会生效。这个Demo工程只是用来演示的,原本的代码量很少,不用对其做过多测试。具体什么能热更生效,什么不能,参看文档「 热更能力 」。
有任何问题可以到「 github发issue 」,我们会统一解答,也方便其他人看到。
APP每同步一次补丁信息,则消耗1瓦力,1元能够买10000瓦力。同步补丁信息发现有新补丁要下载,则还需按补丁大小额外收费,补丁每100KB消费3瓦力,不足100KB按100KB计算。假如同步补丁信息后发现已经下载过此补丁,则不会重新下载了,只消耗同步补丁信息的费用。举个例子,每日10000用户使用APP,那每日同步补丁信息消耗10000瓦力,开发每5日发布一个新补丁,大小100KB,发布新补丁后,APP需要下载此补丁,第一次下载的时候消费3瓦力,此后不需要再消耗下载费用。
目前每月赠送用户100万瓦力,足够百万月活的App使用了,无需充值。
注意:此处的补丁大小并不是指用户上传的补丁的大小,而是上传后经过网站解析生成的产物,并且使用zlib压缩过的大小,上传后才可以看到,通常比用户生成的补丁大小要小一些。
网站版提供了两种同步补丁的方式,Sync接口必须是通过网络同步到补丁信息,才能加载补丁,APP没有网络的情况下,则调用Sync接口会失败,也不会加载到任何补丁,即使之前有网并且成功同步过也一样。而ApplyCachedAndPullShip接口则可以在无网络情况下也能加载上次缓存好的补丁,具体请看「 同步补丁API 」解释。
补丁信息都保存在CDN上,支持非常高的并发,即使本网站被攻击无法访问,也不影响APP同步补丁,所以可以放心使用。
如果账户瓦力值小于0时,则APP无法加载任何补丁,即使它们之前已经同步到了最新的补丁。可以在版本信息页面看到每个版本消耗的瓦力值,网站统计瓦力的消耗有几分钟的延迟。另外需要说明的是,欠费并且重新充值后,可能也会有几分钟延迟APP才能重新同步并加载补丁,此时如果着急,可以编辑一下版本信息,可能能让CDN更快的刷新缓存。
目前最大支持5MB的补丁,补丁大小通常不会那么大,取决于要修复的代码。当然也可以把本方案用于减包,把大量逻辑生成为补丁,原生代码在热更注入时就删掉了,如何配置sotconfig.sh请看:「 热更配置 」