Swift Pushkit VOIP推送唤起CallKit通话界面被启动逻辑覆盖问题求解
解决方案
核心思路是区分应用启动场景,针对普通用户启动和VOIP推送冷启动走不同的初始化逻辑,从根源避免冗余请求和通话界面被覆盖的问题。
1. 新增启动场景全局标记
在AppDelegate中新增标记位,区分当前应用是否由VOIP推送唤起:
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // 新增VOIP启动标记 var isLaunchedByVOIPPush: Bool = false // 可选:存储当前展示的通话界面实例 var currentCallVC: UIViewController? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 检查启动参数是否包含VOIP推送 payload if let _ = launchOptions?[.voip] as? [AnyHashable: Any] { isLaunchedByVOIPPush = true } // 原有加载启动页的逻辑保留 initiateFirstScreen("SplashScreen", storyboardName : "sheet") return true } }
2. 改造启动页初始化逻辑
原有SplashScreen中的token校验、用户信息读取、Signalr连接等逻辑,仅在非VOIP启动场景下执行:
func checkLogin() { // VOIP启动场景直接跳过原有初始化流程,优先加载通话界面 guard !AppDelegate.shared.isLaunchedByVOIPPush else { // 直接实例化通话界面作为根控制器 let callVC = UIStoryboard(name: "main", bundle: nil).instantiateViewController(withIdentifier: "CallVC") AppDelegate.shared.currentCallVC = callVC AppDelegate.shared.window?.rootViewController = callVC AppDelegate.shared.window?.makeKeyAndVisible() return } // 原有普通启动逻辑保留 if let oauth = AppDelegate.shared.authState, oauth.isAuthorized{ initiateFirstScreen("HomeVC", storyboardName : "main") }else{ initiateFirstScreen("LoginVC", storyboardName : "main") } }
3. 拦截根控制器切换逻辑
修改initiateFirstScreen方法,VOIP场景下禁止非通话界面替换根控制器,避免覆盖正在展示的通话界面:
func initiateFirstScreen(_ vcName: String, storyboardName : String) { guard let window = AppDelegate.shared.window else{ AlertUtils.alertMessageWithOkAction(vc: self, mes: Language.get("Something went wrong")){b in exit(0) } return } // VOIP启动场景仅允许切换到通话界面,其他切换请求直接拦截 guard !AppDelegate.shared.isLaunchedByVOIPPush || vcName == "CallVC" else { return } let storyBoard: UIStoryboard = UIStoryboard(name: storyboardName, bundle: nil) let vc = storyBoard.instantiateViewController(withIdentifier: vcName) window.rootViewController = vc window.makeKeyAndVisible() }
4. 通话结束流程处理
根据需求实现通话结束后的逻辑:
// 通话结束回调方法 func callDidFinish() { guard AppDelegate.shared.isLaunchedByVOIPPush else { // 普通启动场景下的通话结束逻辑自行实现 return } // 需求1:通话结束直接退出应用 exit(0) // 可选需求:如果需要用户停留在应用,重置标记后走普通初始化流程即可 // AppDelegate.shared.isLaunchedByVOIPPush = false // AppDelegate.shared.currentCallVC = nil // checkLogin() }
注意事项
- VOIP启动场景下不需要执行任何冗余的初始化请求,所有原有启动逻辑都可以完全跳过,仅保留通话必需的最小逻辑即可
- Pushkit收到推送的回调逻辑需要和全局标记联动,确保标记准确性
内容的提问来源于stack exchange,提问作者famfamfam
相关产品推荐
相关产品推荐

