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

iOS端FCM通知点击跳转指定页面并展示数据异常问题

Got it, let's work through this FCM notification redirect issue together. I’ve tackled this exact scenario before, so here’s a step-by-step solution to get your app navigating to the right screen and displaying the notification data properly:

Step 1: Lock Down FCM & Notification Configuration

First, ensure your AppDelegate is set up to intercept notification interactions. You need to assign the UNUserNotificationCenter delegate to yourself—otherwise iOS will default to opening the home screen. Here’s the updated setup:

import UIKit
import Firebase
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        // Critical: Set UNUserNotificationCenter delegate to self
        UNUserNotificationCenter.current().delegate = self
        Messaging.messaging().delegate = self
        
        // Request necessary notification permissions
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
        application.registerForRemoteNotifications()
        
        // Check if app was launched from a notification (background/killed state)
        if let notificationData = launchOptions?[.remoteNotification] as? [String: Any] {
            handleInitialNotificationLaunch(from: notificationData)
        }
        
        return true
    }
    
    // ... keep your existing AppDelegate methods here
}
Step 2: Handle Foreground Notification Taps

When your app is in the foreground and the user taps a notification, the userNotificationCenter(_:didReceive:withCompletionHandler:) method fires. This is where you’ll override the default behavior and redirect to your target screen:

// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate {
    // Triggered when user taps a notification (foreground/background)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        
        // Extract your custom payload data (match keys to your FCM server payload)
        guard let targetScreen = userInfo["target_screen"] as? String,
              let notificationDetails = userInfo["notification_data"] as? [String: Any] else {
            // Fallback to home screen if required data is missing
            navigateToHome()
            completionHandler()
            return
        }
        
        // Navigate based on the target screen identifier
        switch targetScreen {
        case "order_detail":
            navigateToOrderDetail(with: notificationDetails)
        case "message_inbox":
            navigateToMessageInbox(with: notificationDetails)
        // Add cases for all your app's target screens
        default:
            navigateToHome()
        }
        
        completionHandler()
    }
    
    // Optional: Show notifications as alerts while the app is in foreground
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .badge, .sound])
    }
}
Step 3: Build Navigation Logic & Pass Data

Next, create helper methods to navigate to your target view controllers and inject the notification data. Adjust this code to match your app’s navigation structure (e.g., UINavigationController, UITabBarController):

extension AppDelegate {
    private func navigateToHome() {
        guard let window = self.window else { return }
        let homeVC = HomeViewController()
        let navController = UINavigationController(rootViewController: homeVC)
        window.rootViewController = navController
        window.makeKeyAndVisible()
    }
    
    private func navigateToOrderDetail(with data: [String: Any]) {
        guard let window = self.window else { return }
        
        // Initialize your target view controller
        let orderDetailVC = OrderDetailViewController()
        
        // Pass data to the VC (adjust properties to match your VC's setup)
        orderDetailVC.orderId = data["order_id"] as? String
        orderDetailVC.orderStatus = data["status"] as? String
        
        // Navigate: Push if inside a navigation stack, or set as root if needed
        if let currentNav = window.rootViewController as? UINavigationController {
            currentNav.pushViewController(orderDetailVC, animated: true)
        } else {
            let navController = UINavigationController(rootViewController: orderDetailVC)
            window.rootViewController = navController
            window.makeKeyAndVisible()
        }
    }
    
    private func navigateToMessageInbox(with data: [String: Any]) {
        guard let window = self.window else { return }
        let messageVC = MessageInboxViewController()
        messageVC.unreadMessageCount = data["unread_count"] as? Int ?? 0
        
        // If using a tab bar controller, switch to the correct tab first
        if let tabBar = window.rootViewController as? UITabBarController {
            tabBar.selectedIndex = 2 // Update to your message tab index
            if let tabNav = tabBar.selectedViewController as? UINavigationController {
                tabNav.pushViewController(messageVC, animated: true)
            }
        } else {
            let navController = UINavigationController(rootViewController: messageVC)
            window.rootViewController = navController
            window.makeKeyAndVisible()
        }
    }
    
    // Handle notification taps that launch the app from background/killed state
    private func handleInitialNotificationLaunch(from userInfo: [String: Any]) {
        // Wait a short delay to ensure the window is fully initialized
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            guard let targetScreen = userInfo["target_screen"] as? String,
                  let details = userInfo["notification_data"] as? [String: Any] else {
                return
            }
            
            switch targetScreen {
            case "order_detail":
                self?.navigateToOrderDetail(with: details)
            case "message_inbox":
                self?.navigateToMessageInbox(with: details)
            default:
                self?.navigateToHome()
            }
        }
    }
}
Step 4: Ensure Your FCM Payload Includes Custom Data

Your server’s FCM payload must include the custom fields your app expects to identify the target screen and pass data. Here’s a sample payload format:

{
  "to": "YOUR_DEVICE_TOKEN",
  "notification": {
    "title": "New Order Alert",
    "body": "Order #456 has been delivered!"
  },
  "data": {
    "target_screen": "order_detail",
    "notification_data": {
      "order_id": "456",
      "status": "delivered",
      "delivery_time": "2024-05-20 14:30"
    }
  }
}
Key Notes to Avoid Issues
  • Always use the data field for custom data: The notification field is only for display, and custom data won’t be accessible there.
  • Test all states: Verify navigation works when the app is foreground, background, and fully killed.
  • Use weak self in async blocks: Prevent retain cycles in the delayed navigation for initial app launches.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:33:11