You need to enable JavaScript to run this app. iOS端接收FCM自定义布尔、整型数据失败,仅能获取字符串如何解决?
优惠活动
大模型
产品
解决方案
定价
更多

iOS端接收FCM自定义布尔、整型数据失败,仅能获取字符串如何解决?

iOS FCM推送无法正确获取非String类型自定义字段的解决方案

问题复现

我通过curl向我的iOS应用发送自定义FCM消息(不止包含标题和内容),代码如下:

curl -X POST --header "Authorization: key=myServerKey" \
--Header "Content-Type: application/json" \
https://fcm.googleapis.com/fcm/send \
-d @- << EOF
{
  "to": "my device token",
    "data": {
        "urlFlag": true,
        "category": "Electric",
        "messageId": 1238884523
    },
    "notification": {
        "title": "Test",
        "body": "What do you want?"
    }
}
EOF

注:原curl请求的JSON结构中notification字段下title后缺少逗号,属于语法错误,实际使用时需要补上

我在AppDelegate的userNotificationCenter(_:willPresent:withCompletionHandler:)方法中接收推送消息,代码如下:

import UIKit
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        /* Firebase Cloud Messaging */
        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        Messaging.messaging().token { token, error in
            if let error = error {
                print("Error fetching FCM registration token: \(error)")
            } else if let token = token {
                if self.showFirebaseToken {
                    print("Remote FCM registration token: \(token)")
                }
            }
        }
        
        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self
            
            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }
        application.registerForRemoteNotifications()
        
        return true
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        completionHandler([[.alert, .sound]])
                
        if let aps = userInfo["aps"] as? [String: Any], let alert = aps["alert"] as? [String: Any] {
            if let title = alert["title"] as? String, let body = alert["body"] as? String {
                print("title: \(title) body: \(body)") // good
            }
        }
        
        if let urlFlag = userInfo["urlFlag"] as? Bool {
            print("Flag: \(urlFlag)") // no good
        }
        if let category = userInfo["category"] as? String {
            print("category: \(category)") // good
        }
        if let messageId = userInfo["messageId"] as? Int {
            print("ID: \(messageId)") // no good
        }
    }
}

应用可以正常接收通知的标题和内容,但是自定义数据集中包含布尔、字符串、数字三种类型时,仅能成功获取String类型的数据。

补充信息

返回的userInfo内容如下:

[AnyHashable("google.c.fid"): cgthRgMJPEkaidXXhrXuqv, AnyHashable("urlFlag"): true, AnyHashable("messageId"): 1238884523, AnyHashable("aps"): {
    alert =     {
        body = "What do you want?";
        title = Test;
    };
}, AnyHashable("google.c.sender.id"): 1073343011223, AnyHashable("category"): Electric, AnyHashable("google.c.a.e"): 1, AnyHashable("gcm.message_id"): 1627387811171401]

问题原因

FCM推送的自定义非字符串字段(布尔、数字)在iOS端的userInfo中是以NSNumber类型存储的,无法直接通过as? Bool/as? Int做Swift原生类型转换,所以会导致转换失败返回nil。

解决方案

修改字段获取逻辑,先将值转为NSNumber,再提取对应类型的值即可:

// 处理布尔类型urlFlag
if let flagNum = userInfo["urlFlag"] as? NSNumber {
    let urlFlag = flagNum.boolValue
    print("Flag: \(urlFlag)")
}

// 处理数字类型messageId
if let idNum = userInfo["messageId"] as? NSNumber {
    // 数值小于2^31用intValue即可,超过范围可以用int64Value
    let messageId = idNum.intValue
    print("ID: \(messageId)")
}

如果需要兼容服务端可能传字符串格式数字的场景,可以再加一层兼容判断:

var messageId: Int?
if let idNum = userInfo["messageId"] as? NSNumber {
    messageId = idNum.intValue
} else if let idStr = userInfo["messageId"] as? String, let num = Int(idStr) {
    messageId = num
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 17:27:02