You need to enable JavaScript to run this app. Swift Pushkit VOIP推送唤起CallKit通话界面被启动逻辑覆盖问题求解
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 16:27:08