2021.6 更新
根据目前了解情况,除查找技术解决方案外,还有可能向苹果申请特殊权限来解决此问题。关键词:com.apple.developer.pushkit.unrestricted-voip
需求
公司项目有一套即时的视频语音聊天功能,产品希望是当App切入后台挂起或者被用户划掉后,收到视频语音推送时,App可以持续震动及响铃(持续震动及响铃),并且用户点击通知时,App启动后就可以及时的进行视频语音通话(用户无等待)。
技术现状
苹果推送有三种方案:
1.普通推送
2.静默推送
3.VoIP推送
针对三种推送方案的说明,网上有很多很详细的资料,这里就不一一列举。我们很快的就可以锁定,如果要实现以上需求,VoIP是我们唯一可以选择的方案。
在Xcode11之前,我们可以直对接VoIP推送,唯一面临的是苹果的审核。但是前段时间苹果发布了一则通知:
Important
On iOS 13.0 and later, if you fail to report a call to CallKit, the system will terminate your app. Repeatedly failing to report calls may cause the system to stop delivering any more VoIP push notifications to your app. If you want to initiate a VoIP call without using CallKit, register for push notifications using the UserNotifications framework instead of PushKit. For more information, see UserNotifications.
通过Xcode11我们收到VoIP推送时,如果我们没有调用Callkit相关代码,即reportNewIncomingCallWithUUID,我们会直接收到以下崩溃信息:
Apps receving VoIP pushes must post an incoming call (via CallKit or IncomingCallNotifications) in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay.
*** Assertion failure in -[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes], /BuildRoot/Library/Caches/com.apple.xbs/Sources/PushKit/PushKit-37/PKPushRegistry.m:343
显然苹果为了避免我们不正当的使用VoIP推送,进行了强制处理,所以我们需要对接CallKit咯?如果这样做了,在提交的时候,以下信息可能在等着你:
Apple Dear Developer,
The Chinese Ministry of Industry and Information Technology (MIIT) http://www.miit.gov.cn/n1146285/ ... n3057713/index.html requested that CallKit functionality be deactivated in all apps available on the China App Store.
Since your app currently includes CallKit and is available for sale on the China App Store, you will need to submit an update that removes CallKit functionality in China.
VOIP call functionality continues to be allowed but can no longer take advantage of CallKit ’ s intuitive look and feel. CallKit can continue to be used in apps outside of China.
If you have questions or do not believe your app is subject to this update, please contact MIIT.
Best regards,
App Store Review
那我们通过手机号码等条件,进行区域处理。国内使用普通推送,国外通过VoIP来做应该可以通过苹果要求,但是老板不同意了,我们面向的是国内用户。仿佛已经撞到南墙了!
另辟蹊径
那让我们先来对比下几个大厂如何做的。
- QQ:收到视频通话,手机持续震动几秒直至推送自动隐藏。点击QQ无等待直接可以接听
- 微信:收到视频通话,手机持续震动至少30s。点击微信无需等待直接可以接听
- 闲鱼:收到视频通话,手机震动,点击闲鱼后无需等待直接可以接听
BOSS: QQ、微信都实现了,你为什么实现不了。。。
既然这些App都收到了VoIP推送并且激活了App,同时没有出现CallKit的电话界面,说明通过某些方式是可以实现的。那我就把重点放在了当我们调用reportNewIncomingCallWithUUID方法的时候,系统做了什么。如果可以找到,那我们就可以偷偷地做个好心人帮系统做一下。
尝试思路一
尝试打印当前所有线程内的方法调用,看这个过程中,是否有一些不一样的方法被调用,令人遗憾的是并没有找到有用的信息。
尝试思路二
监听所有通知的发送,是否通过一些通知进行了信息传递。这这个过程中,我们发现有一个不一样的通知出现:PKPushIncomingCallReportedNotification。
然后让我们试试不再调用reportNewIncomingCallWithUUID方法,而是发送这个通知呢?结果正是我们想要的!没有CallKit的通话界面,App有没有异常崩溃通知。
存在的问题
但是偶尔会出现无法再次收到VoIP的push通知。
高重现场景为:收到VoIP推送后长时间不处理,客户端会被异常终止,之后就收不到了。但是收到时客户端激活,就没有问题。
写在最后
目前工作有其他更紧急的插入进来,暂时没有继续研究了(后面抽时间再看)。这里只是提供了一种解决问题的思路,我们不能因为认为做不到就不去尝试。
如果有朋友有更好的思路或者存在问题解决方案找到了,可以回复用来帮助更多的人学习。
同时呢,这种方式只是我们挑战自己的方式,上架App还是要遵守苹果规范的!