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
相关产品推荐
相关产品推荐

