我能够从Firebase控制台在前台和后台发送测试通知(应用程序处于休眠状态且已关闭)。但是没有接收到由云功能触发的推送通知。
我知道推送通知有效,因为该应用的Android版本可以接收它们。
这是我用来启用推送通知的教程(我自然排除了不推荐使用的功能):
https://www.iosapptemplates.com/blog/ios-development/push-notifications-firebase-swift-5
总结:
这是我的应用程序委托:
class AppDelegate: UIResponder, UIApplicationDelegate {
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
Messaging.messaging().delegate = self
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)
}
//get application instance ID
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instance ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
}
application.registerForRemoteNotifications()
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
extension AppDelegate : MessagingDelegate {
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func application(_ application: UIApplication, didRegiterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { //data -> String in
return String(format: "%02.2hhx", $0)
}
print(tokenParts)
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
UserDefaults.standard.synchronize()
}
}
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
// Change this to your preferred presentation option
completionHandler([[.alert, .badge, .sound]])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
我关闭了烦恼(我一生无法把握它的本质,但是根据Firebase,我应该将其关闭,就像我做到的那样。
值得一提的是,当我从AppDelegate推送令牌时,令牌并不总是保存在服务器上。由于我在应用程序中设置了侧面菜单,因此将其作为扩展放置在其中(也许稍后再进行更改,但是云功能必须具有最新的令牌):
extension ContainerViewController : MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
let db = Firestore.firestore()
getUserEmail { (userId) in
if let userId = userId {
let userRef = db.collection("Customer_Data").document(userId)
userRef.setData(["tokenId" : fcmToken], merge : true)
}
}
}
func getUserEmail(completion : @escaping (String?) -> Void) {
let user = Auth.auth().currentUser
if let user = user?.email {
completion(user)
}
}
}
因此我可以验证令牌是否已保存。这时我可能做错了什么?是的,这是在Mac上插入的物理设备上,并且在无线推送构建时。
编辑 添加了APNs身份验证密钥而不是证书
两个通知的有效载荷
data: {
title: notificationTypes[notificationType].title + ' ' + planType ,
body: 'Meal Plan: ' + order.mpName + '\n' +
'Restaurant:' + order.restaurantName + '\n' +
'Total sum :' + order.currentTotal,
}
和
data : {
title: notificationTypes[notificationType].title + ' ' + planType ,
body: 'Meal Plan: ' + order.mpName + '\n' +
'Restaurant:' + order.restaurantName + '\n' +
'Total sum :' + order.currentTotal,
color:'#3EDF3E',
tag: notificationTypes[notificationType].tag
}