You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS Firebase通知:APP被杀状态下点击通知跳转指定视图问题

嘿,这个问题我熟!当App处于被杀状态时,点击推送的启动逻辑和后台/前台完全不一样,得专门处理冷启动时的参数传递。我给你一步步拆解解决方法:

核心原因

当App被杀后点击推送启动,推送的参数不会走didReceiveRemoteNotification方法,而是会被包含在启动参数里(launchOptions或者SceneDelegate的connectionOptions),所以我们要在App初始化的阶段就提取并处理这些参数。

解决步骤(分两种架构情况)

1. 传统AppDelegate架构(iOS 12及以下)

didFinishLaunchingWithOptions里,先完成窗口和根视图的初始化,再检查启动参数里的推送信息,最后解析跳转逻辑:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    
    // 先初始化窗口和根视图控制器(确保这部分代码在处理推送之前)
    let window = UIWindow(frame: UIScreen.main.bounds)
    self.window = window
    let rootNav = UINavigationController(rootViewController: HomeViewController())
    window.rootViewController = rootNav
    window.makeKeyAndVisible()
    
    // 处理冷启动时的推送通知
    if let pushPayload = launchOptions?[.remoteNotification] as? [String: Any] {
        handlePushNavigation(with: pushPayload)
    }
    
    return true
}

// 封装通用的跳转处理方法
private func handlePushNavigation(with payload: [String: Any]) {
    // 假设推送payload里有自定义字段`targetScreen`,标记要跳转的页面
    guard let targetScreen = payload["targetScreen"] as? String else {
        print("未找到跳转标识")
        return
    }
    
    // 确保根视图是导航控制器(如果是TabBar需调整逻辑)
    guard let rootNav = window?.rootViewController as? UINavigationController else {
        print("根视图不是导航控制器,无法跳转")
        return
    }
    
    // 根据标识跳转对应页面
    switch targetScreen {
    case "orderDetail":
        // 从payload提取额外参数,比如订单ID
        let orderId = payload["orderId"] as? String ?? ""
        let detailVC = OrderDetailViewController(orderId: orderId)
        rootNav.pushViewController(detailVC, animated: true)
    case "messageCenter":
        let msgVC = MessageCenterViewController()
        rootNav.pushViewController(msgVC, animated: true)
    default:
        // 默认不跳转或返回首页
        break
    }
}

2. SceneDelegate架构(iOS 13及以上)

iOS 13后启动逻辑移到了SceneDelegate,需要在willConnectTo方法里处理推送参数:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    
    // 初始化窗口和根视图
    let window = UIWindow(windowScene: windowScene)
    self.window = window
    let rootNav = UINavigationController(rootViewController: HomeViewController())
    window.rootViewController = rootNav
    window.makeKeyAndVisible()
    
    // 处理冷启动的推送通知
    if let notificationResponse = connectionOptions.notificationResponse {
        let pushPayload = notificationResponse.notification.request.content.userInfo
        handlePushNavigation(with: pushPayload)
    }
}

// 复用通用跳转方法
private func handlePushNavigation(with payload: [String: Any]) {
    guard let targetScreen = payload["targetScreen"] as? String else { return }
    guard let rootNav = window?.rootViewController as? UINavigationController else { return }
    
    switch targetScreen {
    case "orderDetail":
        let orderId = payload["orderId"] as? String ?? ""
        let detailVC = OrderDetailViewController(orderId: orderId)
        rootNav.pushViewController(detailVC, animated: true)
    case "messageCenter":
        let msgVC = MessageCenterViewController()
        rootNav.pushViewController(msgVC, animated: true)
    default:
        break
    }
}

关键注意事项

  • 后端配合:推送payload必须包含自定义跳转标识(比如targetScreen),要让后端把这个字段放在aps字典外面,示例payload:
    {
      "aps": {
        "alert": {
          "title": "您的订单已发货",
          "body": "点击查看详情"
        },
        "sound": "default"
      },
      "targetScreen": "orderDetail",
      "orderId": "123456"
    }
    
  • 跳转时机:一定要先完成窗口和根视图的初始化,再处理跳转,否则会找不到导航控制器导致失败。
  • 测试方式:必须把App完全杀掉(从后台向上划掉),再点击推送测试,不能在后台或前台测试冷启动场景。

内容的提问来源于stack exchange,提问作者desila

火山引擎 最新活动