【发布时间】:2020-04-26 14:12:40
【问题描述】:
我正在使用 FCM 为我的 iOS 应用创建和发送推送通知。
开发环境:
Xcode 11.3
运行 iOS 13.3 的 iPhone X
斯威夫特 5.2
Pod 版本:
- Firebase 6.14.0
- FirebaseMessaging 4.1.10
- FirebaseInstanceID 4.2.8
问题:
在遇到问题之前,我已将我的应用设置为能够在应用同时处于后台和前台时接收通知。我对自己非常满意,我提交了代码。在此之后,我无法在前台或后台接收通知。无论使用通知是从 Cloud Messaging 仪表板还是 POSTMAN 发送的,我都会收到成功的响应,但通知永远不会出现。
起初我以为我可能已经达到通知配额,但现在是事后 2 天。
我已尝试解决问题:
- 卸载并重新安装应用程序(刷新设备令牌)
- 将
UIApplication.shared.registerForRemoteNotifications()移至FirebaseApp.configure()之前 - 下载了新的 GoogleService-Info.plist 并替换了现有的
- 检查了 bundle id 等是否全部匹配
- 将 firebase pod 更新为最新版本(如果有帮助,FirebaseMessaging 的版本为 4.1.9)
- 设置
Messaging.messaging().shouldEstablishDirectChannel = true - 删除并重新添加了所需的功能
- 将
FirebaseAppDelegateProxyEnabled设置为YES 和NO - 设置
shouldEstablishDirectChannel = true - 设置
useMessagingDelegateForDirectChannel = true - 将一些逻辑从 didFinishLaunchingWithOptions() 移至 applicationDidBecomeActive()
代码:
注意:这是最初为我工作的未更改代码。
AppDelegate.swift
import UIKit
import Firebase
import FBSDKCoreKit
import GoogleMaps
import SwiftLocation
import GooglePlaces
import Crashlytics
import GoogleSignIn
import Armchair
import UserNotifications
import FirebaseMessaging
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var swipeNavigationViewController: SwipeNavigationViewController!
override init() {
super.init()
FirebaseApp.configure()
Database.database().isPersistenceEnabled = true
swipeNavigationViewController = SwipeNavigationViewController()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseConfiguration.shared.setLoggerLevel(.error)
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
// Google Maps
GMSServices.provideAPIKey(FireBaseConstants.GoogleAPIKey)
GMSPlacesClient.provideAPIKey(FireBaseConstants.GoogleAPIKey)
GeocoderRequest.GoogleOptions(APIKey: FireBaseConstants.GoogleAPIKey)
let navigationViewController = UINavigationController(rootViewController: swipeNavigationViewController)
navigationViewController.setNavigationBarHidden(true, animated: false)
self.window?.rootViewController = navigationViewController
self.window?.makeKeyAndVisible()
showAlertIfPointedTowardProductionDatabase()
setupReviewRequest()
UIApplication.shared.registerForRemoteNotifications()
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// If granted comes true you can enabled features based on authorization.
guard granted else { return }
DispatchQueue.main.async {
print("UserID: \(UserManager.sharedManager.currentUser?.userID)")
let pushManager = PushNotificationManager(userID: "currently_logged_in_user_id")
pushManager.registerForPushNotifications()
}
}
UNUserNotificationCenter.current().delegate = self
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let handledByFB = ApplicationDelegate.shared.application(app, open: url, options: options)
var handledByGoogle = false
if !handledByFB {
handledByGoogle = GIDSignIn.sharedInstance().handle(url)
}
let handled = handledByFB || handledByGoogle
return handled
}
private func setupReviewRequest() {
//Code...
}
// This method will be called when app received push notifications in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
}
PushNotificationManager.swift
import Foundation
import Firebase
import FirebaseFirestore
import FirebaseMessaging
import UIKit
import UserNotifications
class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate {
let userID: String
let gcmMessageIDKey = "gcm.message_id"
init(userID: String) {
self.userID = userID
super.init()
}
func registerForPushNotifications() {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (_, error) in
guard error == nil else{
print(error!.localizedDescription)
return
}
}
//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)")
}
}
UIApplication.shared.registerForRemoteNotifications()
updateFirestorePushTokenIfNeeded()
}
func updateFirestorePushTokenIfNeeded() {
if let token = Messaging.messaging().fcmToken {
// let usersRef = Firestore.firestore().collection("users_table").document(userID)
// usersRef.setData(["fcmToken": token], merge: true)
print("Remote instance ID token: \(token)")
}
}
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.
}
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print(response)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
print(userInfo)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
func application(_ application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { //data -> String in
return String(format: "%02.2hhx", $0)
}
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
UserDefaults.standard.synchronize()
}
}
这是使用以下所有链接设置的(我确定还有一些我忘记了):
- https://code.tutsplus.com/tutorials/get-started-with-firebase-messaging-for-ios--cms-32126#comment-4345018783
- Firebase - Swift 4: Message sent but not received
- Get push notification while App in foreground iOS
- https://www.iosapptemplates.com/blog/ios-development/push-notifications-firebase-swift-5
回复信息:
邮递员:
{
"multicast_id": 2586780331808083728,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1578532253832479%2b1845e62b1845e6"
}
]
}
云消息传递:
【问题讨论】:
标签: ios swift firebase firebase-cloud-messaging google-cloud-messaging