实验工具:
手机: iPhone 6s(12.1.2)、 iPhone8(14.0)、iPhone 8 Plus(15.3.1)
环境: Xcode13.1、Xcode13.2.1、Xcode13.3
一、检查启动时动态链接库
在 main.h 中进行断点调试:
LLDB调试image list
1. Xcode13.1
在Xcode13.1上需要编译成功:
将 -Wl,-weak-lswift_Concurrency -Wl,-rpath,/usr/lib/swift 添加到应用程序build settings中的 Other Linker Flags。
在iOS12上
(lldb) image list
[ 2] .../XX.app/Frameworks/libswiftCore.dylib
[...] ...略
在iOS14上
(lldb)image list
[ 2] .../usr/lib/swift/libswiftCore.dylib
[...] ...略
在iOS15上
(lldb)image list
[ 1] .../usr/lib/swift/libswift_Concurrency.dylib
[ 6] .../usr/lib/swift/libswiftCore.dylib
[...] ...略
- 解包得:
无Framworks文件夹, 所以动态库嵌入iOS15系统上
结论如下:
- 在iOS15以上及以下系统上 Storekit2Demo 均编译成功;
- 区别仅在于 libswift_Concurrency.dylib 仅在 iOS 15 时嵌入ipa包内
iOS15以下不引用 libswift_Concurrency.dylibPS: 注意⚠️ iOS12 上 swift动态库 是以嵌入ipa/Frameworks中的形式被调用;
2. Xcode13.2
- Xcode 13.2 Releasae Notes:
Apple Clang Compiler
已知的问题: 使用 Xcode 13 或 Xcode 13.1 构建的应用程序使用 Swift 并发功能(例如 async/await),部署到 15 之前的 iOS、15 之前的 tvOS 或 8 之前的 watchOS,并且启用了位码可能会在启动时崩溃报告未加载 libswift_Concurrency.dylib 库的错误。 (86349088)
解决方法:将 -Wl,-weak-lswift_Concurrency -Wl,-rpath,/usr/lib/swift 添加到应用程序build settings中的 Other Linker Flags。
- Swift 新特性
您现在可以在部署到 macOS Catalina 10.15、iOS 13、tvOS 13 和 watchOS 6 或更高版本的应用程序中使用 Swift Concurrency。这种支持包括async/await, actors, global actors, structured concurrency, 和task APIs。 (70738378)
必读:
Xcode13.2 存在着 iOS15 以下设备使用了 Concurrency 奔溃的问题; Xcode13.2以后版本的并发问题都是由于 Swift Concurrency 向前兼容到 iOS13.0 导致的;
3. Xcode13.2.1
- Xcode 13.2.1 发布说明:
已解决的问题 修复了使用Xcode 13或Xcode 13.1构建的应用程序有时在启动时崩溃,错误地报告 libswift_Concurrency.dylib库未加载。这仅影响使用 Swift 并发功能(如async/await)、在 15 之前部署到 iOS、tvOS(15 之前)或 watchOS(8 之前)并启用了位码的应用。(86349088);
但是这仅仅是修复了iOS13以及iOS14上的奔溃问题;而iOS13.0没有得到修复;
我们根据以上结论来分析事实,先从iOS14、iOS15推演,然后再研究iOS13以下;
在iOS14上
(lldb)image list
[ 2] .../XX.app/Frameworks/libswift_Concurrency.dylib
[ 3] .../usr/lib/swift/libswiftCore.dylib
[...] ...略
解ipa包得:
在iOS15上
无变化,所有动态库均在机器上,无Framworks文件夹;
综上:
- iOS14与iOS15均运行正常;
- 但是我们可以看到iOS14上做出改变:
libswift_Concurrency.dylib 嵌入到了ipa/Frameworks中; - iOS14依旧可以在真机上使用libswiftCore.dylib,从而不会出发引用失败的现象;
回过头看iOS12
- dyld: Library not loaded: /usr/lib/swift/libswiftCore.dylib
Referenced from: /private/var/containers/Bundle/Application/0D0C91E1-8B80-4AD9-9EFC-0F6C82A0F87E/XXX.app/Frameworks/libswift_Concurrency.dylib
解释: libswiftCore.dylib动态库无法加载,是因为libswift_Concurrency.dylib引用了它;
解包得:
综上:
- 在iOS12上奔溃,这是因为ipa/Framworks/ libswift_Concurrency.dylib 引用-> libswiftCore.dylib失败;
- 而libswiftCore.dylib并未打入ipa/Framworks中,所以 libswift_Concurrency.dylib 会引用失败;
- 又因为 Swift 只是向前兼容到 iOS13.0 ,所以这里存在苹果Xcode BUG:不应该将 libswift_Concurrency.dylib 打入包内,反而应该将libswiftCore.dylib打入包内Framworks从而保障app正常运行;
解决方案
所以有两种解决方案:
- 将 libswift_Concurrency.dylib 打入ipa/Framworks 时,一起打入libswiftCore.dylib等依赖库;
- 在 iOS13 以下设备不打入 libswift_Concurrency.dylib 库,因为仅仅是由它的引用问题造成的奔溃;
4. Xcode 13.3
在iOS12上
(lldb)image list
[ 2] .../XX.app/Frameworks/libswift_Concurrency.dylib
[ 3] .../XX.app/Frameworks/libswiftCore.dylib
[ 4] .../XX.app/Frameworks/libswiftAVFoundation.dylib
[...] ...略
在iOS14上
无变化,libswift_Concurrency.dylib打入ipa包内,libswiftCore.dylib依旧使用真机上的;
在iOS15上
无变化,所有动态库均在机器上,无Framworks文件夹;
在Xcode13.3编译后产物中我们主要关注到:
- iOS13以上设备相较于Xcode13.2.1无变化;
- iOS13以下将libswift_Concurrency.dylib、libswiftCore.dylib等依赖库一同打入ipa包内,解决了引用奔溃问题;
二、分析问题进程
问题主要来源:
- Xcode13.2版本发布:支持将Concurrency功能向前兼容到iOS13时,在iOS15以下系统的APP启动奔溃;
- Xcode13.2.1版本发布宣称已修复上述bug,其实还存在iOS13以下设备启动奔溃的问题;
- Xcode13.3 修复了以上bug;
我们发现在Xcode13.2.1中在iOS12上的异常:
不应该将 libswift_Concurrency.dylib 打入包内,反而应该将libswiftCore.dylib打入包内Framworks从而保障app正常运行;>
Xcode13.3这里主要是:
- 通过将libswift_Concurrency.dylib所需要的libswiftCore.dylib一起打入以解决问题;
- 但是这样虽然解决了问题,但是不太严谨:增加了包的体积而且没有根本解决问题(
所有iOS13以下包体都会增加),顺便抓住了iOS13以下无法使用该库API的弱点;
严谨起来
我们在上文Xcode13.2.1中提过:
所以有两种解决方案:
- 将 libswift_Concurrency.dylib 打入ipa/Framworks 时,一起打入libswiftCore.dylib等依赖库;
- 在 iOS13 以下设备不打入 libswift_Concurrency.dylib 库,因为仅仅是由它的引用问题造成的奔溃;
目前我们的需求:
- 在iOS15上运行StoreKit2套件,该套件只能在iOS15上使用;
- 其中该套件内存在libswift_Concurrency.dylib的引用,而该套件可以向前兼容到iOS13.0上;
- 我们是一个SDK提供方,需要为不同工程以及不同版本的Xcode提供服务,所以不能要求对方使用固定的Xcode13.3版本;
- 综上,我们目前只需要在iOS15上在任意Xcode13+版本运行;
所以方案:在iOS15以下设备上,不将libswift_Concurrency.dylib打入ipa/Frameworks中;
解决问题
由#掘金用户 @Skytoup提出的方案:
删除
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.5/iphoneos/libswift_Concurrency.dylib文件
主要是: 解决将 libswift_Concurrency.dylib 复制到 ipa 去的出发源头掐断,绝~
验证方案
1.1 iOS12
(lldb)image list
[ 2] .../XXX.app/Frameworks/libswiftCore.dylib
[...] ...略
解包:
1.2 iOS14
(lldb)image list
[ 2] .../usr/lib/swift/libswiftCore.dylib
[...] ...略
解包: 无Framworks文件夹;
1.3 iOS15
(lldb)image list
[ 3] .../usr/lib/swift/libswift_Concurrency.dylib
[ 2] .../usr/lib/swift/libswiftCore.dylib
[...] ...略
解包: 无Framworks文件夹;
以上均可以正常运行,且iOS15上Storekit2正常使用;
至此解决,感谢🙏