You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift5 iOS应用中实现点击Firebase推送消息跳转至对应目标视图的技术方案咨询

嘿,刚好我之前做过类似的功能,给你一步步拆解怎么实现点击推送跳转到指定带参页面的需求,就像WhatsApp那样直接打开对应聊天窗口~

第一步:让PHP后端配合添加自定义推送参数

首先得让你的PHP后端在发送FCM推送时,在Payload里加入自定义数据字段,用来标识推送类型和传递页面所需的参数(比如聊天ID、用户ID)。

举个标准的FCM推送Payload示例,重点是data字段,这里面就是我们要传递的参数:

{
  "to": "用户的FCM_TOKEN",
  "notification": {
    "title": "新消息提醒",
    "body": "张三给你发了一条消息"
  },
  "data": {
    "type": "chat", // 用来区分推送类型,比如聊天、系统通知等
    "chatId": "123456", // 目标聊天窗口的ID
    "userId": "789012"  // 对方用户的ID
  }
}

注意:自定义参数一定要放在data字段里,或者放在Payload顶层(但用data更规范),这样iOS端才能稳定拿到这些参数。

第二步:修改iOS端代码,处理推送点击逻辑

我们需要覆盖三种场景:应用未运行、后台挂起、前台活跃时点击推送的情况,用统一的逻辑来处理跳转。

2.1 设置UNUserNotificationCenter代理

首先在你的configureNotification()方法里,给UNUserNotificationCenter设置代理,这样才能监听推送的点击事件:

func configureNotification() {
    if #available(iOS 10.0, *) {
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in
            // 授权结果处理(可选)
        }
        // 新增:设置代理
        center.delegate = self
    }
    UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
    UIApplication.shared.registerForRemoteNotifications()
}

然后让你的AppDelegate遵守UNUserNotificationCenterDelegate协议,添加两个核心方法:

extension AppDelegate: UNUserNotificationCenterDelegate {
    // 应用在前台时收到推送,控制是否显示横幅/声音
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // 显示横幅、声音和角标,用户点击横幅后会走下面的didReceive方法
        completionHandler([.banner, .sound, .badge])
    }

    // 点击推送时的核心处理逻辑(不管应用是后台还是前台点击横幅)
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // 调用统一的跳转处理函数
        handleNotificationNavigation(userInfo: userInfo)
        completionHandler()
    }
}

2.2 处理应用未运行时的推送点击

当应用完全关闭,用户点击推送启动应用时,需要在didFinishLaunchingWithOptions里获取启动参数:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    configureNotification()
    
    // 检查是否是通过点击推送启动应用
    if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable: Any] {
        handleNotificationNavigation(userInfo: remoteNotification)
    }
    
    return true
}

如果你的项目用了SceneDelegate(iOS13+),把这段逻辑移到scene(_:willConnectTo:options:)方法里:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let _ = (scene as? UIWindowScene) else { return }
    if let remoteNotification = connectionOptions.notificationResponse?.notification.request.content.userInfo {
        handleNotificationNavigation(userInfo: remoteNotification)
    }
}

2.3 实现统一的跳转逻辑

写一个通用的函数,解析推送参数并跳转到对应页面:

// 统一处理推送跳转
func handleNotificationNavigation(userInfo: [AnyHashable: Any]) {
    // 解析自定义参数
    guard let data = userInfo["data"] as? [String: Any],
          let pushType = data["type"] as? String else {
        print("推送参数解析失败")
        return
    }
    
    // 根据推送类型跳转到不同页面
    switch pushType {
    case "chat":
        // 获取聊天页面所需参数
        guard let chatId = data["chatId"] as? String,
              let userId = data["userId"] as? String else {
            return
        }
        // 跳转到聊天界面
        navigateToChatVC(chatId: chatId, userId: userId)
    case "system_notice":
        // 如果有其他类型的推送,比如系统通知,在这里添加跳转逻辑
        break
    default:
        print("未知的推送类型")
    }
}

// 跳转到聊天界面的具体实现
func navigateToChatVC(chatId: String, userId: String) {
    // 获取当前的窗口和根控制器
    guard let window = UIApplication.shared.windows.first,
          let rootVC = window.rootViewController else {
        return
    }
    
    // 实例化你的聊天ViewController(替换成你实际的类名)
    let chatVC = ChatViewController()
    // 传递参数给聊天页面
    chatVC.targetChatId = chatId
    chatVC.targetUserId = userId
    
    // 根据你的根控制器类型做跳转:
    // 情况1:根控制器是UINavigationController
    if let navVC = rootVC as? UINavigationController {
        navVC.pushViewController(chatVC, animated: true)
    }
    // 情况2:根控制器是UITabBarController(比如大多数社交APP)
    else if let tabBarVC = rootVC as? UITabBarController,
            let selectedNavVC = tabBarVC.selectedViewController as? UINavigationController {
        // 先切换到消息Tab(可选,根据你的需求)
        tabBarVC.selectedIndex = 0
        // 再push聊天页面
        selectedNavVC.pushViewController(chatVC, animated: true)
    }
}

2.4 优化现有推送接收方法

你的didReceiveRemoteNotification方法可以保留,但主要用来处理静默推送或者前台推送的额外逻辑,点击跳转的逻辑已经交给上面的代理方法了:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    Messaging.messaging().appDidReceiveMessage(userInfo)
    print("收到推送内容:\(userInfo)")
    
    // 应用在前台时的额外处理(比如弹出内部提示)
    if application.applicationState == .active {
        // 可选:显示自定义弹窗或提示
    }
    
    completionHandler(UIBackgroundFetchResult.newData)
}
最后要注意的点
  1. 确保你的ChatViewController有对应的属性来接收参数(比如targetChatId、targetUserId),并在页面加载时根据这些参数动态加载内容。
  2. 测试时要注意:如果是用Xcode调试,需要在真机上测试推送功能,模拟器无法接收APNs推送。
  3. 后端发送推送时,要确保data字段的参数类型和iOS端解析的一致(比如字符串类型不要传数字)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:42:32