StoreKit2中libswift_Concurrency.dylib启动奔溃

5,409 阅读5分钟

实验工具:

手机: iPhone 6s(12.1.2)、 iPhone8(14.0)、iPhone 8 Plus(15.3.1)

环境: Xcode13.1、Xcode13.2.1、Xcode13.3


一、检查启动时动态链接库

main.h 中进行断点调试:

image.png

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 
[...] ...

image.png

在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.dylib
  • PS: 注意⚠️ 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包得: image.png

在iOS15上

无变化,所有动态库均在机器上,无Framworks文件夹;

综上:

  • iOS14与iOS15均运行正常;
  • 但是我们可以看到iOS14上做出改变: libswift_Concurrency.dylib 嵌入到了ipa/Frameworks中;
  • iOS14依旧可以在真机上使用libswiftCore.dylib,从而不会出发引用失败的现象;
回过头看iOS12
  1. 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引用了它;

解包得: image.png 综上:

  • 在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 
[...] ...

image.png

在iOS14上
无变化,libswift_Concurrency.dylib打入ipa包内,libswiftCore.dylib依旧使用真机上的; 
在iOS15上
无变化,所有动态库均在机器上,无Framworks文件夹; 

在Xcode13.3编译后产物中我们主要关注到:

  1. iOS13以上设备相较于Xcode13.2.1无变化;
  2. 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 
[...] ...

解包: image.png

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正常使用;

至此解决,感谢🙏

libswift_Concurrency.dylib

StoreKit2【附源码

动态链接器DYLD流程分析