Swift5 iOS应用中实现点击Firebase推送消息跳转至对应目标视图的技术方案咨询
嘿,刚好我之前做过类似的功能,给你一步步拆解怎么实现点击推送跳转到指定带参页面的需求,就像WhatsApp那样直接打开对应聊天窗口~
首先得让你的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端才能稳定拿到这些参数。
我们需要覆盖三种场景:应用未运行、后台挂起、前台活跃时点击推送的情况,用统一的逻辑来处理跳转。
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) }
- 确保你的
ChatViewController有对应的属性来接收参数(比如targetChatId、targetUserId),并在页面加载时根据这些参数动态加载内容。 - 测试时要注意:如果是用Xcode调试,需要在真机上测试推送功能,模拟器无法接收APNs推送。
- 后端发送推送时,要确保
data字段的参数类型和iOS端解析的一致(比如字符串类型不要传数字)。
内容的提问来源于stack exchange,提问作者bircastri

