解决CocoaAsyncSocket在iOS16系统上的崩溃问题

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

本篇文章记录了从昨天更新iOS16发现的一个崩溃问题到解决的过程。

前言

昨天中秋节后第一天上班,苹果爸爸推送了iOS16系统。

于是,作为iOS开发者的常规操作,我开始漫长升级之路:

  • 升级macOS到12.6
  • 升级iOS16
  • 升级Xcode14

运行App,然后崩溃了,崩溃的截图信息如下:

image.png

简单复现崩溃情况

因为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:

image.png

有一个8月15日提交的反馈的issue,大概是说在Xcode14的beta5上有崩溃,而且也是涉及CocoaAsyncSocket

于是乎,我们顺藤摸瓜继续去依赖库CocoaAsyncSocket上面去找找。

果然,一个issue非常醒目:

image.png

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:

image.png

第一个PR就格外醒目!解决iOS16在后台的崩溃问题。

image.png

虽然这个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中就有反馈这个问题:

Snip20220914_8.png

但是,在最新的2020年12月14日的CocoaAsyncSocket7.6.5版本中依旧还是这么写的:

Snip20220914_9.png

既然kCFStreamNetworkServiceTypeVoIP已经过期了,那么我就用issuse 402里面提到的PKPushTypeVoIP替换一下试试。

image.png

编译,运行,App没有崩溃!!!

将过期的kCFStreamNetworkServiceTypeVoIP改为使用PKPushTypeVoIP才是解决问题的关键!!!

总结

在本篇,我们解决了CocoaAsyncSocket在iOS16系统上的崩溃问题,其实没有太多技巧而言。

我们首先通过Xcode崩溃的信息,基本定位到了CocoaAsyncSocket,然后在通过Github中的issuesPR,了解到了相关API的替换,最后发现kCFStreamNetworkServiceTypeVoIP已经过期了,使用之前已经有大佬提出的方案,就解决了这个问题。

还记得我们之前简单统计吗?崩溃只在iOS16的真机出现,而且有开发者认为是iOS16 SDK的Bug导致

而我通过替换kCFStreamNetworkServiceTypeVoIP改为PKPushTypeVoIP解决这个问题后,我更倾向于这个观点:

在iOS16 SDK中,可能kCFStreamNetworkServiceTypeVoIP真的失效了,没有意义了,所以继续使用kCFStreamNetworkServiceTypeVoIP并不能完成配置,所以导致了崩溃。

到这篇文章发布之前,我已经PR了代码到CocoaAsyncSocket,至于会不会被采纳,那就不知道了。

image.png

考虑到涉及使用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客户端。

猜你喜欢

转载自juejin.im/post/7143124820811579423