Weak Linking

最近我们的 app 在 iOS 8 上有一个启动 crash 的问题,原因是启动加载动态库时找不到 Network Extension 的符号,这个符号是 iOS 9 引入的。报错类似这样:

1
2
3
4
5
6
Dyld Error Message:
Symbol not found: _OBJC_CLASS_$_NEPacketTunnelFlow
Referenced from: /private/var/mobile/Containers/Bundle/Application/610BA4A6-D057-4F6B-AA80-907827D2B24E/xxx.app/Frameworks/NEKit.framework/NEKit (which was built for iOS 9.3)
Expected in: /System/Library/Frameworks/NetworkExtension.framework/NetworkExtension
in /private/var/mobile/Containers/Bundle/Application/610BA4A6-D057-4F6B-AA80-907827D2B24E/xxx.app/Frameworks/NEKit.framework/NEKit
Dyld Version: 353.5

解决的方法是使用 Weak Linking。在 Xcode 的 Linked Frameworks and Libraries 中将 Network Extension 的 Status 修改成 optional,再重新编译 NEKit 即可。

在 iOS/macOS 上,许多系统库都是以动态库的形式存在的,当我们的 app 引用了系统库时,Xcode 并不会把系统库打包到 ipa 里,而是系统会在 app 启动时由 dynamic linker 在运行时链接所有需要的动态库。如果我们的 app 用到新系统提供的某些特性,当 app 运行在旧版本上时会因为找不到需要的动态库而 crash。

Apple 为此引入了 Weak Linking。在使用了 Weak Linking 后,系统在 app 启动时找不到对应的符号不会立刻 crash,只有在真正调用到这些符号时才会 crash(所以在使用新符号前必须检查系统版本或者符号是否真的存在)。

给鸡排饭加个蛋