注册
iOS

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做开发,步骤如下:



  1. 选中Demo Project,然后选择Info面板,点击Configurations的下面加号,复制Debug的编译配置,并且命名为SotDebug,用来接入免费版的SOT。再选择复制Release编译配置,命名为SotRelease,用来配置网站版的SOT,注意名字都不要留有空格:...加完就是:...
  2. SwiftMessages也加上这两个Configuration:...

注意:读者应用到自己项目中时,需要把所有的工程都加上这两个Configuration,否则编译会报找不到文件等等的错误。所以加完这两个Configuration的之后,就马上切换到它们去Build和Run一下,看是否有编译错误,如果没有再进行下面的操作,如果有,请检查是否漏了一些工程没有添加上。


Step3: 修改编译选项


添加热更需要的编译选项,添加SOT虚拟机静态库等,步骤如下:




  1. 选中Demo工程,然后选择Demo这个Target,再选择Build Settings:...




  2. Other Linker FlagsSotDebug中添加-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虚拟机静态库的路径,链接的是网站版的虚拟机



  3. Other C Flags以及Other Swift Flags的SotDebug和SotRelease下添加-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/sotsdk/project-script/sotconfig.sh,意义跟上一步是一样的,需要保持一致。经过上面两步,相关的编译配置结果如下图:...




  4. Preprocessor Macros添加USE_SOT=1,后面用来控制是否编译调用SDK的代码...




  5. 因为SOT SDK库文件编译时不带Bitcode,所以也需要把Enable Bitcode设为No...




  6. 为了模拟器架构时不编译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.tbdlibc++.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: 热更注入



  1. Build Configuration切换到SotDebug...
  2. 确保sotconfig.sh的配置是,EnableSot=1以及GenerateSotShip=0,先Clean Build Folder一下,然后再Build:...

然后看编译日志的输出,Link日志可以看到run sot link等输出,会告诉你每个文件里哪些函数可以被热更等信息:......


项目编译成功了,该APP可以正常启动。同时它具备了热更能力,可以加载补丁改变程序的代码逻辑,下面介绍如何生成补丁来测试它。




Step2: 生成补丁


上一步进行了热更注入的编译,当时的代码保存到了Demo/sotsaved这个文件夹下,用来和新代码比较生成补丁。生成补丁步骤如下:



  1. 首先启动SOT生成补丁模式,修改sotconfig.shEnableSot=1GenerateSotShip=1
  2. ...
  3. 接下来直接在Xcode里修改源代码,把ViewController.swift文件的”Something is horribly wrong!“改成了”SOT is great“,修改前:...修改后:...
  4. Swift项目生成补丁,每次都需要先Clean项目,再Build项目。然后查看编译日志输出,可以看到生成了补丁并且被脚本拷贝到了Bundle目录下,可以展开Link Demo(x86_64)的编译日志:...点击展开后,可看到生成补丁的Link日志,日志里显示了函数demoBasics被修改了:...
  5. 生成出来的补丁原始文件保存到了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: 注册网站



  1. 第一步当然是注册网站,成为会员。点击跳转注册页面,免费注册,注册需要验证邮箱,然后登录。
  2. 从导航栏进入我的APP:...
  3. 点击创建APP,弹出弹窗填写APP的名字:...
  4. 进入APP页面,点击右上角的创建新版本按钮,会弹出弹窗,需要选择网站版,SDK版本选择1.0,目前只有1.0版本,然后输入版本号,版本号可以是随意字符串,方便区分就行。...
  5. 创建版本成功后,点击版本,进入版本页面,左上角是唯一标识该版本的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: 修改编译选项



  1. 选中SwiftMessages.xcodeproject工程,然后选择SwiftMessages这个Target,再选择Build Settings:...
  2. Other Linker FlagsSotDebug中添加-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
  3. Other Linker FlagsSotRelease中添加-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
  4. Other C Flags以及Other Swift FlagsSotDebugSotRelease中,添加-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh,意义跟上一步是一样的,需要保持一致。经过上面两步,相关的编译配置结果如下图:...这一步跟Demo的配置差不多,区别在于有些路径写法不一样,以达到复用Demo配置的目的,读者可以仔细比较一下。
  5. Preprocessor Macros添加USE_SOT=1,后面用来控制是否编译调用SDK的代码...
  6. 需要把Target的Enable Bitcode设为No...
  7. 为了模拟器架构时不编译arm64,给SotRelease增加如下配置...

Step2: 链接C++库


点击Build Phases页面,打开Link Binary With Libraries页,点击加号,分别加入这两,libz.tbdlibc++.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: 测试热更




  1. 测试热更的流程跟之前是一模一样的,只是输出的日志可能会有所区别,我们过一遍。EnableSot=1和GenerateSotShip=0热更注入,先Clean后Build,如果去看编译日志的Link SwiftMessages,也可以看到热更注入的信息。




  2. 然后修改MessageView.swift的代码,错误提示的文案会加上“SOT is great”:...




  3. GenerateSotShip=1开启生成补丁模式,Clean后Build,查看Link SwiftMessages日志,有提示该函数被热更:...




  4. 接下来可以看到补丁拷贝脚本日志输出的信息,这里它检测到有两个Target都生成了补丁文件,会把它们两个合成一个,拷贝到Bundle目录下:...




  5. 启动APP,会看到两条加载补丁的日志,因为我们Demo Target和SwiftMessages Target都调用了API接口:...




  6. 点击MESSAGE VIEW控件,可以看到错误提示文案后面多了“SOT is great”,热更成功:


    ...网站版的测试跟以前也是一样的,这里不再重复了。




Step5: 几点提示



  1. Dynamic Library的热更编译改法其实跟主Target,也就是Mach-O Type为Executable的改法是一样,只是这里复用了主Target的一些配置,例如sotsaved目录和sotconfig.sh的路径。增加再多的Target也可以按同样的改法修改它们。
  2. 补丁拷贝脚本只需要主Target有就行了,把要热更的sotmodule对应的名字加上即可,条件就是sotsaved目录必须是同一个。
  3. 如果需要接入网站版,那么每个需要热更的Target都需要调用API跟网站同步,它们的消耗是独立计费的。

Static Library的改法


上面说到Dynamic Library的改法步骤比较多,而且有诸多缺点,如果能把Framework的Mach-O Type改成Static Library是最好的,会少很多步骤和配置。由于本例无法修改,这里简单说一下步骤:



  1. 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库文件了。
  2. Other C Flags以及Other Swift Flags添加-sotmodule $(PRODUCT_NAME) -sotconfig $(SRCROOT)/Demo/sotsdk/project-script/sotconfig.sh,这步跟之前是一模一样的。
  3. 需要把Target的Enable Bitcode设为No
  4. 修改拷贝补丁的脚本,加入该Target的名字,例如本例加入SwiftMessages,跟之前也是一模一样的:...

然后就配置完了,如果是使用网站版,同步一次消耗,就能实现所有Target的热更,修改简单,对包体影响最小。




总结


本文完整介绍Swift项目如何接入免费版和网站版。


本文的方式是把SDK拷贝到了工程文件夹里,让它可以跟随项目一起进行版本管理,路径也配置成了相对路径,更加灵活。


通过新增Configuration的方式,也做到了不影响原来的开发,Debug和Release相当于没有接入SOT,适合大多数开发平时使用。只需上线前改成SotRelease出包,就能让APP就得到热更能力。


作者:忒修斯科技
链接:https://juejin.cn/post/7033403091550470180

0 个评论

要回复文章请先登录注册