Swift接入例子-适合多人协作
在「 Swift接入例子 」中介绍了Swift项目如何接入SOT。但是要求SDK解压到特定目录中,编译配置的路径也是绝对路径,不适合多人协作合开。文本介绍适合多人开发协作的接入方法。
还是以开源的「 SwiftMessages 」Demo为例,该工程全部用Swift语言开发。这里把修改好的版本上传到了git上,分支为 「 sotcollaboration 」,SotDebug接入免费版,SotRelease接入网站版,读者只需要进行下面的 Step1.配置编译环境 就可以直接用该分支测试。
现在开始从头讲解,git clone原本的工程后(我的路径为/Applications/SwiftMessages),命令行cd /Applications/SwiftMessages
进入根目录,使用版本切换命令:git checkout 1e49de7b3780b699
(因本文档制作于21年10月21号,以当日版本为准)。首先进入Demo目录,打开Demo.xcodeproj工程,scheme默认就已经选中了Demo:
我使用的是Xcode12.4,可以直接编译成功,启动APP能看到画面(模拟器):
点击最上面的MESSAGE VIEW控件,会弹出一个错误提示窗口,今天我们就来用SOT热更的方式修改错误提示的文案:
Step1: 配置编译环境
「 下载SOT的SDK 」,解压到项目目录下 /Applications/SwiftMessages/Demo/sotsdk
在terminal运行命令:sh /Applications/SwiftMessages/Demo/sotsdk/compile-script/install.sh
安装SOT编译工具链,需要输入密码。
用文本编辑器打开 /Applications/SwiftMessages/Demo/sotsdk/project-script/sotconfig.sh,修改EnableSot=1:新版SDK已经不会再使用sotconfig.sh里的sdkdir,sotbuilder和objbuilder路径了,所以不用修改这些配置了,删掉也可以。
Step2: 增加Configuration
增加两个Configuration,只有切换到这两个Configuration才使用SOT编译模式,平时还是用原来的Configuration做开发,步骤如下:
- 选中Demo Project,然后选择Info面板,点击Configurations的下面加号,复制Debug的编译配置,并且命名为SotDebug,用来接入免费版的SOT。再选择复制Release编译配置,命名为SotRelease,用来配置网站版的SOT,注意名字都不要留有空格:加完就是:
- 给SwiftMessages也加上这两个Configuration:
注意:读者应用到自己项目中时,需要把所有的工程都加上这两个Configuration,否则编译会报找不到文件等等的错误。所以加完这两个Configuration的之后,就马上切换到它们去Build和Run一下,看是否有编译错误,如果没有再进行下面的操作,如果有,请检查是否漏了一些工程没有添加上。
Step3: 修改编译选项
添加热更需要的编译选项,添加SOT虚拟机静态库等,步骤如下:
选中Demo工程,然后选择Demo这个Target,再选择Build Settings:
在Other Linker Flags的SotDebug中添加
-sotmodule $(PRODUCT_NAME) sotsdk/libs/libsot_free.a -sotsaved $(SRCROOT)/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
在SotRelease中添加
-sotmodule $(PRODUCT_NAME) sotsdk/libs/libsot_web.a -sotsaved $(SRCROOT)/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
。每个选项的意义如下:
- -sotmodule是module的名字,可以直接用$(PRODUCT_NAME),也可以自定义名字,名字不要有空格
- -sotsaved是编译中间产物保存的目录,补丁自动化生成需要对比前后编译的产物来生成补丁
- -sotconfig指定了项目sotconfig.sh的路径,该脚本控制sot编译器的工作
sotsdk/libs/libsot_free.a
是SOT虚拟机静态库的路径,链接的是免费版的虚拟机sotsdk/libs/libsot_web.a
是SOT虚拟机静态库的路径,链接的是网站版的虚拟机
在Other C Flags以及Other Swift Flags的SotDebug和SotRelease下添加
-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh
,意义跟上一步是一样的,需要保持一致。经过上面两步,相关的编译配置结果如下图:在Preprocessor Macros添加
USE_SOT=1
,后面用来控制是否编译调用SDK的代码因为SOT SDK库文件编译时不带Bitcode,所以也需要把Enable Bitcode设为No。
为了模拟器架构时不编译arm64,给SotRelease增加如下配置或者把Build Active Architecture Only设为Yes
Step4: 增加拷贝补丁脚本
SDK里提供了一个便利脚本,路径在sdk目录的project-script/sot_package.sh,它会把生成的补丁拷贝到Bundle文件夹下,在每次项目编译成功时调用该脚本,添加步骤如下:
脚本内容为:
if [[ "$CONFIGURATION" == "SotDebug" || "$CONFIGURATION" == "SotRelease" ]];then
sh "$SOURCE_ROOT/sotsdk/project-script/sot_package.sh" "$SOURCE_ROOT/sotsdk/project-script/sotconfig.sh" "$SOURCE_ROOT/sotsaved/$CONFIGURATION" Demo
fi
复制代码
把Based on dependency analysis的勾去掉。
Step5: 链接C++库
SOT需要压缩库和c++标准库的支持,还是在这个页面下,打开Link Binary With Libraries页
点击加号,分别加入这两,libz.tbd
和libc++.tbd
Step6: 调用SDK API
需要用Swift代码调用OC代码,已经提供了一个样例代码在SDK的swift-call-objc目录中,先把callsot.h和callsot.m拷贝到Demo目录下
再添加到Demo工程中。点击Xcode软件的File按钮,找到Demo目录下的callsot.h和callsot.m,接着点击Add Files to "Demo",如下图所示:
点击Add按钮,添加后会弹出询问:是否创建桥接文件。点击按钮Create Bridging Header:
然后可以看到项目中多了3个文件,分别是callsot.h,callsot.m和Demo-Bridging-Header.h:
打开Demo-Bridging-Header.h,加入一行代码#import "callsot.h"
打开callsot.m,修改代码为
#import <Foundation/Foundation.h>
#import "callsot.h"
#import "../sotsdk/libs/SotWebService.h"
@implementation CallSot:NSObject
-(void) InitSot
{
#ifdef USE_SOT
#ifdef DEBUG
[SotWebService ApplyBundleShip];
#else
[SotWebService Sync:@"1234567" is_dev:false cb:^(SotDownloadScriptStatus status)
{
if(status == SotScriptStatusSuccess)
{
NSLog(@"SotScriptStatusSuccess");
}
else
{
NSLog(@"SotScriptStatusFailure");
}
}];
#endif
#endif
}
@end
复制代码
注意SotWebService.h的头文件路径不再依赖于绝对路径,并且代码里用了#ifdef USE_SOT
宏来隔开API调用代码,不影响正常编译:
打开AppDelegate.swift,加入两行代码let sot = CallSot()
和sot.initSot()
注意:读者在应用到自己项目中时,以上这些配置的路径不要生搬硬套。例如找不到SotWebService.h文件,找不到sotconfig.sh文件等等,读者自己要清楚SDK的目录与自己工程目录的相对关系,灵活调整这些配置的路径。
测试热更-免费版
按上面配置完之后,先测试免费版热更功能
Step1: 热更注入
- 将Build Configuration切换到SotDebug
- 确保sotconfig.sh的配置是,EnableSot=1以及GenerateSotShip=0,先Clean Build Folder一下,然后再Build:
然后看编译日志的输出,Link日志可以看到run sot link等输出,会告诉你每个文件里哪些函数可以被热更等信息:
项目编译成功了,该APP可以正常启动。同时它具备了热更能力,可以加载补丁改变程序的代码逻辑,下面介绍如何生成补丁来测试它。
Step2: 生成补丁
上一步进行了热更注入的编译,当时的代码保存到了Demo/sotsaved这个文件夹下,用来和新代码比较生成补丁。生成补丁步骤如下:
- 首先启动SOT生成补丁模式,修改sotconfig.sh为EnableSot=1,GenerateSotShip=1
- 接下来直接在Xcode里修改源代码,把ViewController.swift文件的”Something is horribly wrong!“改成了”SOT is great“,修改前:修改后:
- Swift项目生成补丁,每次都需要先Clean项目,再Build项目。然后查看编译日志输出,可以看到生成了补丁并且被脚本拷贝到了Bundle目录下,可以展开Link Demo(x86_64)的编译日志:点击展开后,可看到生成补丁的Link日志,日志里显示了函数demoBasics被修改了:
- 生成出来的补丁原始文件保存到了Demo/sotsaved/SotDebug/x86_64/ship/ship.sot,还记得之前加了一个script到Build Phase中吗?它会每次编译结束时,会把这个补丁拷贝到了Bundle目录中,并且添加CPU架构到文件名中。可以在Bundle中看到这个补丁,至此完毕。
Step3: 加载补丁
启动APP,API会判断Bundle内是否有补丁,有则加载,加载成功的日志大概如下,提示有一个模块加载了热更补丁:之后点击最上面的MESSAGE VIEW控件,发现弹出的文案变成了SOT is great:
如果去Xcode断点调试demoBasics,会发现无法断住了,因为实际执行补丁代码的是SOT虚拟机。
顺便提一嘴,GenerateSotShip=1时,编译APP用的是保存在sotsaved目录下的代码,所以无论怎么修改Xcode里的代码,如果没有把补丁拷贝到Bundle目录里,那么APP都是最后一次GenerateSotShip=0热更注入时的样子。
如果怀疑,可以把拷贝补丁的Script脚本从Build Phases删除,可以发现GenerateSotShip=1怎么改代码都不会生效了。
注意:如果读者接入自己的一个很简单项目进行测试,例如设置某个控件的颜色,热更前是红色,修改后是绿色,发现无法生效。那是因为这样的项目太过于简单,寥寥几行代码。热更前没有访问过绿色的这个全局变量,在热更时也无法访问到了,SOT只能利用原有的能力,无法无中生有。所以不要这样测试,更具体的原因在「 热更能力-语言特性 」说明。通常完整的项目代码比较多,所以就不会有这样的缺陷。
接入网站版
按上面的教程,已经对APP实现了免费版和网站版的接入。它俩区别只是链接的库不一样,具体就是Other Linker Flags根据Configuration区别配置,SotRelease下接入了网站版。但除了APP接入了网站版SDK,还需要用配合网站来管理补丁的发布。
Step1: 注册网站
- 第一步当然是注册网站,成为会员。点击跳转注册页面,免费注册,注册需要验证邮箱,然后登录。
- 从导航栏进入我的APP:
- 点击创建APP,弹出弹窗填写APP的名字:
- 进入APP页面,点击右上角的创建新版本按钮,会弹出弹窗,需要选择网站版,SDK版本选择1.0,目前只有1.0版本,然后输入版本号,版本号可以是随意字符串,方便区分就行。
- 创建版本成功后,点击版本,进入版本页面,左上角是唯一标识该版本的VersionKey,后面API接口需要这个Key。
Step2: 修改VersionKey
打开callsot.m,修改网站版的Sync接口,第一个参数填入你在网站创建的版本的VersionKey。至此,网站版热更就算接入完成了。
Step3: 测试网站热更
网站版生成补丁的步骤免费版是一样的,需要经历热更注入->出包->修改代码->生成补丁,这里不再赘述。
唯一不同的是,生成出来的补丁要上传到网站上,然后才能通过网络同步到手机上实现热更。通过之前的免费版教程,知道生成的补丁会被拷贝到Bundle目录下,所以去Bundle目录里就能找它,在Xcode导航栏里右键选择Products下的Demo.app,选择Show in Finder:
右键Demo文件,选择Show Package Contents:
找到目录下的sotship_arm64.sot,这里用手机测试,cpu是arm64类型,补丁名字带有cpu后缀,这就是补丁了:
回到网站的版本页面,点击右侧上传补丁按钮:
弹出页面里,真机的架构一般选择arm64,除非是老的armv7的机器,并把补丁文件拖到框里,点击上传:
上传成功并且补丁文件无异常(补丁最大支持5MB),则会添加成功,补丁默认是停用状态,需要点击编辑来启用它:
这里选择全量启用,点击下面的提交按钮,然后补丁就会成功启用了:
上一步更新了补丁状态,通常很快生效,但CDN有时也需要1到2分钟才能生效。之后手机打开APP,如果成功下载补丁和加载的话,就能看到下面的日志:这里输出的md5也跟网站上的补丁md5是一致的。
打开APP后,点击最上面的MESSAGE VIEW控件,发现弹出的文案变成了SOT is great:
注意:使用网站版,需要考虑到网络传输延迟的问题,只有看到了下载补丁和成功加载补丁的日志之后,调用的函数才会使用热修后的函数。例如有的开发问我,首屏代码怎么无法热更生效?那是因为首屏代码调用的时机太早了,SOT去网站上拿补丁,是异步的,不会一直卡住等着,而且在异步线程中等待结果。在补丁没传输回来之前,首屏的代码都已经调用结束了,这种情况下当然调用的还是老的代码了。而免费版没有这个问题,因为免费版是同步加载补丁的,直接去Bundle里加载,不是异步的。
构建热更注入版本和构建补丁必须是同一台机器,同一个Xcode版本。例如上架前APP用Xcode12进行了热更注入,而之后用Xcode13来构建补丁,那么将得到无效甚至错误的补丁。请使用同一个版本Xcode。
Step4: 几点提示
- 网站版跟免费版主要接入流程差不多,可以用免费版测试,功能通过测试之后再接入网站版。
- 网站版需要有网络的情况下才能生效,如果手机没有网,即使之前已经下载过了补丁,也无法加载。
- 网站版费用很低,日活10万的APP,一个月几百块就够了。
- 网站版补丁和配置都放在CDN上,支持高并发。
非主Target接入热更
上面的教程都是针对主Target,也就是Demo。这个工程还有一个名为SwiftMessages的Framework,也可以热更,下面介绍如何配置。
可以看到SwiftMessages的Mach-O Type是Dynamic Library,通过下图方式查看得到:
这种类型的话,配置相对麻烦些。还有一种是Static Library,配置起来会简单得多。但本例改成Static Library启动会崩溃,所以按Dynamic Library的方式来介绍。
Step1: 修改编译选项
- 选中SwiftMessages.xcodeproject工程,然后选择SwiftMessages这个Target,再选择Build Settings:
- 在Other Linker Flags的SotDebug中添加
-sotmodule $(PRODUCT_NAME) $(SRCROOT)/Demo/sotsdk/libs/libsot_free.a -sotsaved $(SRCROOT)/Demo/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh
- 在Other Linker Flags的SotRelease中添加
-sotmodule $(PRODUCT_NAME) $(SRCROOT)/Demo/sotsdk/libs/libsot_web.a -sotsaved $(SRCROOT)/Demo/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh
- 在Other C Flags以及Other Swift Flags的SotDebug和SotRelease中,添加
-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh
,意义跟上一步是一样的,需要保持一致。经过上面两步,相关的编译配置结果如下图:这一步跟Demo的配置差不多,区别在于有些路径写法不一样,以达到复用Demo配置的目的,读者可以仔细比较一下。 - 在Preprocessor Macros添加
USE_SOT=1
,后面用来控制是否编译调用SDK的代码 - 需要把Target的Enable Bitcode设为No。
- 为了模拟器架构时不编译arm64,给SotRelease增加如下配置
Step2: 链接C++库
点击Build Phases页面,打开Link Binary With Libraries页,点击加号,分别加入这两,libz.tbd
和libc++.tbd
Step3: 调用SDK API
因为SwiftMessages是动态库,所以需要在它的编译文件中调用SDK的热更初始化接口。跟Demo一样,添加OC文件。先从Demo文件夹中复制callsot.h和callsot.m文件到SwiftMessages文件夹中
选中SwiftMessages工程,点击Xcode软件的File按钮,接着点击Add Files to "SwiftMessages.xcodeproject",如下图所示:
选择到SwiftMessages目录,同时选中callsot.h和callsot.m两个文件,勾选下面的Copy items if needed,勾选Add to targets:中的SwiftMessages target,如下图所示:
点击Add按钮,然后可以看到项目中多了2个文件,分别是callsot.h,callsot.m,修改CallSot类名为CallSotMessage:
去到右边面板,把文件属性改成public:
打开callsot.m,做相应路径和类名的修改:
打开Demo-Bridging-Header.h,加入一行代码#import "SwiftMessages/callsot.h"
:
打开AppDelegate.swift,加入两行代码let sot1 = CallSotMessage()
和sot1.initSot()
因为这时候有两个Target都可以生成补丁,Demo和SwiftMessages,需要修改拷贝补丁的脚本,加入SwiftMessages:
Step4: 测试热更
测试热更的流程跟之前是一模一样的,只是输出的日志可能会有所区别,我们过一遍。EnableSot=1和GenerateSotShip=0热更注入,先Clean后Build,如果去看编译日志的Link SwiftMessages,也可以看到热更注入的信息。
然后修改MessageView.swift的代码,错误提示的文案会加上“SOT is great”:
GenerateSotShip=1开启生成补丁模式,Clean后Build,查看Link SwiftMessages日志,有提示该函数被热更:
接下来可以看到补丁拷贝脚本日志输出的信息,这里它检测到有两个Target都生成了补丁文件,会把它们两个合成一个,拷贝到Bundle目录下:
启动APP,会看到两条加载补丁的日志,因为我们Demo Target和SwiftMessages Target都调用了API接口:
点击MESSAGE VIEW控件,可以看到错误提示文案后面多了“SOT is great”,热更成功:
网站版的测试跟以前也是一样的,这里不再重复了。
Step5: 几点提示
- Dynamic Library的热更编译改法其实跟主Target,也就是Mach-O Type为Executable的改法是一样,只是这里复用了主Target的一些配置,例如sotsaved目录和sotconfig.sh的路径。增加再多的Target也可以按同样的改法修改它们。
- 补丁拷贝脚本只需要主Target有就行了,把要热更的sotmodule对应的名字加上即可,条件就是sotsaved目录必须是同一个。
- 如果需要接入网站版,那么每个需要热更的Target都需要调用API跟网站同步,它们的消耗是独立计费的。
Static Library的改法
上面说到Dynamic Library的改法步骤比较多,而且有诸多缺点,如果能把Framework的Mach-O Type改成Static Library是最好的,会少很多步骤和配置。由于本例无法修改,这里简单说一下步骤:
- 在Other Libraian Flags添加
-sotmodule $(PRODUCT_NAME) -sotsaved $(SRCROOT)/Demo/sotsaved/$(CONFIGURATION)/$(CURRENT_ARCH) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh
,注意是Other Libraian Flags而不是Other Linker Flags了。还有这里比Dynamic Library加的配置少一个,即没有链接SDK的.a库文件了。 - 在Other C Flags以及Other Swift Flags添加
-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh
,这步跟之前是一模一样的。 - 需要把Target的Enable Bitcode设为No。
- 修改拷贝补丁的脚本,加入该Target的名字,例如本例加入SwiftMessages,跟之前也是一模一样的:
然后就配置完了,如果是使用网站版,同步一次消耗,就能实现所有Target的热更,修改简单,对包体影响最小。
总结
本文完整介绍Swift项目如何接入免费版和网站版。
本文的方式是把SDK拷贝到了工程文件夹里,让它可以跟随项目一起进行版本管理,路径也配置成了相对路径,更加灵活。
通过新增Configuration的方式,也做到了不影响原来的开发,Debug和Release相当于没有接入SOT,适合大多数开发平时使用。只需上线前改成SotRelease出包,就能让APP就得到热更能力。
作者:忒修斯科技
链接:https://juejin.cn/post/7033403091550470180