我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情
本篇文章记录了从昨天更新iOS16发现的一个崩溃问题到解决的过程。
前言
昨天中秋节后第一天上班,苹果爸爸推送了iOS16系统。
于是,作为iOS开发者的常规操作,我开始漫长升级之路:
- 升级macOS到12.6
- 升级iOS16
- 升级Xcode14
运行App,然后崩溃了,崩溃的截图信息如下:
简单复现崩溃情况
因为Xcode14是后续持续开发刚需的IDE版本(理论上说目前使用Xcode13也可以继续进行开发,但是对于适配iOS16,还是Xcode14更好),我们对崩溃问题进行了简单的复现统计:
IDE版本 | iOS版本 | 设备 | 是否崩溃 |
---|---|---|---|
Xcode14 | iOS 15 | 真机 | 否 |
Xcode14 | iOS 15 | 模拟器 | 否 |
Xcode14 | iOS 16 | 真机 | 是 |
Xcode14 | iOS 16 | 模拟器 | 否 |
可以看出,该崩溃仅仅只在iOS16的真机上出现。
排查定位问题
根据信息,我们可以发现崩溃的问题出现在CocoaMQTT
相关的依赖库——CocoaAsyncSocket
。
于是我们先去CocoaMQTT
上面去看了一些open issue:

有一个8月15日提交的反馈的issue,大概是说在Xcode14的beta5上有崩溃,而且也是涉及CocoaAsyncSocket
。
于是乎,我们顺藤摸瓜继续去依赖库CocoaAsyncSocket
上面去找找。
果然,一个issue非常醒目:
I think this is a problem inside iOS 16 Core Foundation framework. The source code of new Core Foundation is not released, so I just file a bug to apple(FB11489606).
根据反馈者的意见:认为这个bug可能是由于iOS16架包中的Core Foundation framework导致。
于是我们又顺带看了看CocoaAsyncSocket
的PR:
第一个PR就格外醒目!解决iOS16在后台的崩溃问题。
虽然这个PR还没有合并,但是对于我们App开始连接MQTT就崩溃的情况还是值得试一试的,于是我们立即在Pod的源码中对这里进行了修改。
修改后,MQTT正常工作,也没有崩溃了。
难道你觉得到这里已经完了?并没有,我们接着往下看。
深入:kCFStreamNetworkServiceTypeVoIP
过期导致的崩溃
我特地去看了一下有关kCFStreamNetworkServiceTypeVoIP
的代码,其介绍如下:
/* deprecated network service type: */
CFN_EXPORT const CFStringRef kCFStreamNetworkServiceTypeVoIP CF_DEPRECATED(10_7, 10_11, 4_0, 9_0, "use PushKit for VoIP control purposes"); // voice over IP control - this service type is deprecated in favor of using PushKit for VoIP control
复制代码
kCFStreamNetworkServiceTypeVoIP
这个常量实际上早在iOS9就已经过期了。
甚至2016年,在CocoaAsyncSocket
中Close的issue中就有反馈这个问题:
但是,在最新的2020年12月14日的CocoaAsyncSocket
的7.6.5
版本中依旧还是这么写的:
既然kCFStreamNetworkServiceTypeVoIP
已经过期了,那么我就用issuse 402
里面提到的PKPushTypeVoIP
替换一下试试。
编译,运行,App没有崩溃!!!
将过期的kCFStreamNetworkServiceTypeVoIP改为使用PKPushTypeVoIP才是解决问题的关键!!!
总结
在本篇,我们解决了CocoaAsyncSocket
在iOS16系统上的崩溃问题,其实没有太多技巧而言。
我们首先通过Xcode崩溃的信息,基本定位到了CocoaAsyncSocket
,然后在通过Github中的issues
和PR
,了解到了相关API的替换,最后发现kCFStreamNetworkServiceTypeVoIP
已经过期了,使用之前已经有大佬提出的方案,就解决了这个问题。
还记得我们之前简单统计吗?崩溃只在iOS16的真机出现,而且有开发者认为是iOS16 SDK的Bug导致。
而我通过替换kCFStreamNetworkServiceTypeVoIP改为PKPushTypeVoIP解决这个问题后,我更倾向于这个观点:
在iOS16 SDK中,可能kCFStreamNetworkServiceTypeVoIP
真的失效了,没有意义了,所以继续使用kCFStreamNetworkServiceTypeVoIP并不能完成配置,所以导致了崩溃。
到这篇文章发布之前,我已经PR了代码到CocoaAsyncSocket
,至于会不会被采纳,那就不知道了。
考虑到涉及使用CocoaAsyncSocket
的App与第三库众多,也希望官方大佬早点解决这个问题吧。
参考文档
使用 CocoaAsyncSocket “kCFStreamNetworkServiceTypeVoIP is deprecated in iOS 9 ” warning 解决方案
kCFStreamNetworkServiceTypeVoIP is deprecated in iOS 9 warning
fix crash of backgrouding in iOS16
自己写的项目,欢迎大家star⭐️
RxStudy:RxSwift/RxCocoa框架,MVVM模式编写wanandroid客户端。
GetXStudy:使用GetX,重构了Flutter wanandroid客户端。