总结下封装sdk遇到的一些问题。
目的是要封装个sdk供渠道app使用,内部会集成一些广告商sdk,然后封装一些网络请求传递调用信息,最后打包提供给客户。
功能总体很简单,考虑到需要后期维护,选了cocoapods工具作为操作集,从初始化,到demo,到打包上传均提供现成的解决方案。
问题1
pod太慢,下行速度在几kb徘徊,搜了一波答案,用SwitchHosts将git主要节点加入host ,又用git config --global http.https://github.com.proxy socks5://127.0.0.1:1086 将git代理到vpn端口上,效果立即提升。
问题2
根据说明配置好spec文件后,发现无法运行模拟器,报错如下:
照着最佳答案配置后,问题解决。原因是:
苹果最新退出的m1芯片彻底排除了x86_64的指令集,从Xcode12开始,模拟器指令集也默认也包含了arm64,但因为很多第三方针对模拟器编译后的产物并不包含,所以需要将模拟器的指令集中排除arm64,设置后,模拟器将不再被认为支持arm64。
大概有以下几种方案:
方案1
Build Settings >> Excluded Architectures added "arm64" to both Release and Debug mode for "Any iOS Simulator SDK" option.
这种方案需要将主项目和pod项目同时设置,且再次pod install后pod相关的设置会失效。
方案2
s.pod_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
s.user_target_xcconfig = { 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64' }
需要在pod spec里增加两行,但对于自己的pod dev项目可以,对于其它第三方项目是没有权限的,其中pod_target_xcconfig和user_target_xcconfig的区别为:
- pod_target_xcconfig 用于当自身pod配置
- user_target_xcconfig 用于设置调用方的配置,比如主工程,鉴于工具不可污染调用方的原则,不建议使用。所以调用方还是建议自己在Build Setting里设置为好。
方案3
post_install do |installer|
installer.pods_project.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
end
end
在Podfile里增加以上,可以设置所有pod项目,一劳永逸,也是最终解决方案
方案4
- 删除Valid Architectures 选项
在xcode12之前Valid Architectures用于标识所有指令集的集合,通过和standard architectures搭配得到最终需要的指令集,Xcode12以后弃用Valid Architectures,推出Excluded Archs来排除不支持的指令集,显然指令集太多了,算交集不如算排除来得简单。
但最终不清楚是如何解决的问题,not work for me。
方案5
- Setting Validate Workspace to YES
不清楚具体含义,Xcode12开始有的选项,英文翻译为:
If enabled, perform validation checks on the workspace configuration as part of the build process.
https://developer.apple.com/forums/thread/669274 里有个答案说明:
Same thing happened with my project. I believe that this is an intentional change by Apple to force developers to start distributing xcframeworks with support for arm64 simulators (M1 Macs). Fat binary frameworks don't work anymore because simulators and actual devices can have the same architecture. The proper solution is to repack the GoogleCast framework into xcframework. You can do this by splitting the fat binary into two using lipo (one for simulator and one for real devices). If you don't want to do this, you can enable "Validate workspace" in build settings. This will enable you to build your project and only output a warning.
说是打开Validate workspace设置后,以上问题只会用警告的方式输出,不影响运行,但同样 not word for me。
后续查看后得知:
苹果在Xcode12.3中统一验证了framework的合法性,不在支持合成模拟器和真机的framework(因为模拟器和真机都支持arm64了),所以就会报错,但因错误类似,被归结为一个问题,有点混淆视听。
开启Validate workspace后,会将workspace错误当做警告,暂时解决问题,同样的,所有错误都会被当做警告,风险未知。
链接:https://stackoverflow.com/questions/63267897/building-for-ios-simulator-but-the-linked-framework-framework-was-built/65306886
至此 该问题解决,从搜索到的文章数量来看,Xcode12 绝大部分问题都因为m1芯片引发,吐槽者甚众,模拟器从诞生起就和真机是两码事,很多第三方服务都得通过打包合成的方式提供服务,突然被暂停影响面太大了。
----------------------开始打包----------------------
问题3
- 隐藏.h文件private_header_files 设置后不生效。
- 解决
pod默认会将所有.h设为公开,设置public_header_files后将只读取其中的.h作为公开类。
问题4
- 执行
pod lib lint SMSDK.podspec --verbose --allow-warnings - 报错
missing compatible arch in /Library/Ruby/Gems/2.6.0/gems/ffi-1.14.2/lib/ffi_c.bundle - /Library/Ruby/Gems/2.6.0/gems/ffi-1.14.2/lib/ffi_c.bundle - 解决
ffi-1.14.2不支持m1芯片,命令增加arch -x86_64前缀,解决问题。通过将终端app设置为Rosetta模式无效。
Rosetta为苹果针对M1芯片推出的兼容模式
问题5
- 执行
pod trunk push SMSDK.podspec --allow-warnings - 报错
[!] Source code for your Pod was not accessible to CocoaPods Trunk. Is it a private repo or behind a username/password on http? - 解决
因为pod是私有库,私有库应使用pod repo push而不是pod trunk push,浪费不少时间,其实是因为搞错了pod库的模式,创建pod私有库其实毫无意义,但凡要给别人用,必须公开。隐蔽源代码应该再创建个git仓库才对,pod仓库只用来放编译好的framework即可。
问题6
- 执行
pod package SMSDK.podspec --force --exclude-deps --no-mangle --embedded - 报错
fatal error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: Pods/build/package.a and Pods/build-sim/package.a have the same architectures (arm64) and can't be in the same fat output file - 解决
其实还是和问题1一样,错误类型不同而已,起初根本不知道什么原因,执行pod package时错误不能稳定出现,后来才发现是缓存问题,每次打包前要执行pod cache clean -- all,另外执行打包时需要从git仓库拉代码,默认拉取main分支,所以版本分支的代码还要及时同步到main。
---------------------测试运行------------------------
问题7
Undefined symbols for architecture arm64
framework拖入项目后,所有引用文件对应的.m文件均编译失败,
已经被前面几个问题折磨的死去活来,第一眼看到architecture arm64 想当然的以为又是指令集问题,不断的换电脑、切分支、新建项目、clean项目、删除缓存、重新打包、修改配置、编译下载,重试无数种方案的组合,新旧问题交织在一起乱作一团,简直要崩溃。
中间间或能成功运行几次,以为问题解决,万事大吉,赶紧各种备份。然而一觉醒来问题依旧,当场崩溃,完全的摸不着脉络。三天三夜,业务代码一句没动。
尝试过放弃pod工具集,用苹果最原始的方案重新开始,脚本打包,但找了几个脚本根本不能良好运行,再去debug太耗时间;还有只创建framework不创建demo,用编译产物导入到其它项目运行,也不能准确生效。
还有一些零碎的问题,比如手动拖入项目和从Link Binary With Libraies导入的具体区别;还有Genral tab下Embed的Do Not Embed ,Embed&Sign, Embed Without Signing三选项的区别和联系。
偶然在新项目里 用pod 导入了某第三方,发现对应的错误消失,想起之前项目里需要在Podflie和spec都导入pod,忘了什么原因。
--------------重新回到pod package。
- --exclude-deps 用于剔除第三方生成。
为作为服务方framework集成第三方后难免与主项目冲突,所以为了解决冲突打包时去掉了第三方依赖,这也是为什么pod lint和pod package不报错的原因
- --no-mangle 用于避免pod新建命名空间
默认的mangle用来提前命名类来避免冲突,第三方库的类名前都会加入统一前缀,例如:PodYourPodName_YourClass,而且--no-mangle和 --exclude-deps 无法拆分使用,当剔除第三方生成时 ,命名修改毫无意义;不剔除第三方,不重新命名肯定冲突。
问题8
- 执行
pod package SMSDK.podspec --force --embedded - 报错
[!] podspec has binary-only depedencies, mangling not possible. - 解决
因项目里使用了其它静态文件,无法打包成framework............卒。
重新使用 pod package SMSDK.podspec --force --exclude-deps --no-mangle --embedded 强制打包。
将测试项目内导入framework依赖的第三方后,所有问题解决。